refactor(scheme): 优化数据库同步逻辑并增加备份表检查

This commit is contained in:
augushong
2026-01-09 22:26:34 +08:00
parent ff037400e9
commit 23826cd06e
2 changed files with 77 additions and 4 deletions

View File

@@ -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)]

View File

@@ -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;
}
}