mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-01 15:32:48 +08:00
refactor(scheme): 优化数据库同步逻辑并增加备份表检查
This commit is contained in:
@@ -40,10 +40,10 @@ class MallGoods extends BaseScheme
|
||||
#[Field(type: 'text', comment: '商品属性')]
|
||||
public $property;
|
||||
|
||||
#[Field(type: 'decimal', length: 8, precision: 8, scale: 2, default: '0.00', comment: '市场价')]
|
||||
#[Field(type: 'decimal', length: 8, precision: 8, default: '0', comment: '市场价')]
|
||||
public $market_price;
|
||||
|
||||
#[Field(type: 'decimal', length: 8, precision: 8, scale: 2, default: '0.00', comment: '折扣价')]
|
||||
#[Field(type: 'decimal', length: 8, precision: 8, default: '0', comment: '折扣价')]
|
||||
public $discount_price;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '销量', unsigned: true)]
|
||||
|
||||
@@ -7,7 +7,9 @@ use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Config;
|
||||
use think\facade\Db;
|
||||
use app\common\service\scheme\SchemeToDbService;
|
||||
use app\common\service\scheme\DbToSchemeService;
|
||||
use app\common\scheme\attribute\Table;
|
||||
use ReflectionClass;
|
||||
|
||||
@@ -26,10 +28,12 @@ class Sync extends Command
|
||||
$skipData = $input->getOption('skip-data');
|
||||
|
||||
$service = new SchemeToDbService();
|
||||
$generator = new DbToSchemeService();
|
||||
$schemeDir = app()->getAppPath() . 'admin/scheme/';
|
||||
$ignoreTables = Config::get('scheme.ignore_tables', []);
|
||||
$connection = Config::get('database.default', 'mysql');
|
||||
$prefix = Config::get('database.connections.' . $connection . '.prefix', '');
|
||||
$backupPrefix = Config::get('scheme.backup_prefix', 'backup');
|
||||
|
||||
if (!is_dir($schemeDir)) {
|
||||
$output->writeln("<error>Scheme directory not found: $schemeDir</error>");
|
||||
@@ -43,11 +47,37 @@ class Sync extends Command
|
||||
|
||||
if (class_exists($className)) {
|
||||
$tableName = $this->getTableNameFromScheme($className);
|
||||
if (!empty($tableName) && $this->isIgnoredTable($tableName, $ignoreTables, $prefix)) {
|
||||
$output->writeln("Skipping $className (ignored table: $tableName)");
|
||||
if (empty($tableName)) {
|
||||
$output->writeln("Skipping $className (missing table name)");
|
||||
continue;
|
||||
}
|
||||
|
||||
$fullTableName = $this->getFullTableName($tableName, $prefix);
|
||||
if ($this->isBackupTable($fullTableName, $prefix, $backupPrefix)) {
|
||||
$output->writeln("Skipping $className (backup table: $fullTableName)");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->isIgnoredTable($fullTableName, $ignoreTables, $prefix)) {
|
||||
$output->writeln("Skipping $className (ignored table: $fullTableName)");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->checkTableExists($connection, $fullTableName)) {
|
||||
try {
|
||||
$expectedClass = basename($file, '.php');
|
||||
$generated = $generator->generate($fullTableName, $expectedClass);
|
||||
$existing = (string)file_get_contents($file);
|
||||
if ($this->normalizeCode($generated) === $this->normalizeCode($existing)) {
|
||||
$output->writeln("Skipping $className (no schema changes)");
|
||||
continue;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Check failed for $className: " . $e->getMessage() . "</error>");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln("Syncing $className...");
|
||||
try {
|
||||
$backup = $service->sync($className, $skipData);
|
||||
@@ -91,4 +121,47 @@ class Sync extends Command
|
||||
|
||||
return in_array($shortName, $ignoreTables, true) || in_array($tableName, $ignoreTables, true);
|
||||
}
|
||||
|
||||
protected function normalizeCode(string $code): string
|
||||
{
|
||||
$code = str_replace(["\r\n", "\r"], "\n", $code);
|
||||
$code = preg_replace('/[ \t]+$/m', '', $code);
|
||||
return trim((string)$code);
|
||||
}
|
||||
|
||||
protected function checkTableExists(string $connection, string $tableName): bool
|
||||
{
|
||||
$database = (string)Config::get('database.connections.' . $connection . '.database', '');
|
||||
if ($database !== '') {
|
||||
$rows = Db::connect($connection)->query(
|
||||
'SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? LIMIT 1',
|
||||
[$database, $tableName]
|
||||
);
|
||||
return !empty($rows);
|
||||
}
|
||||
|
||||
$escaped = addcslashes($tableName, "\\_%");
|
||||
$tables = Db::connect($connection)->query("SHOW TABLES LIKE '$escaped'");
|
||||
return !empty($tables);
|
||||
}
|
||||
|
||||
protected function getFullTableName(string $tableName, string $prefix): string
|
||||
{
|
||||
if ($prefix && !str_starts_with($tableName, $prefix)) {
|
||||
return $prefix . $tableName;
|
||||
}
|
||||
|
||||
return $tableName;
|
||||
}
|
||||
|
||||
protected function isBackupTable(string $tableName, string $prefix, string $backupPrefix): bool
|
||||
{
|
||||
$basePrefix = $prefix . $backupPrefix;
|
||||
if ($basePrefix === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pattern = '/^' . preg_quote($basePrefix, '/') . '_?\\d{14}(?:_.*)?$/';
|
||||
return preg_match($pattern, $tableName) === 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user