\App\Services\AdminDataSyncService

数据同步服务

职责:把数据库数据与 Seeder 规范数据对齐(与 db:seed 的全量 TRUNCATE 不同,本服务永不删行)—— 缺行补插(自然键不存在才插,id 冲突自动回落数据库序列)、 内容同步(仅「代码持有」表逐字段对齐,「数据持有」表绝不覆盖)、 序列同步 + 业务缓存清理(受保护缓存自动豁免)。 规范数据来源:PG 上事务内真实执行 Seeder::run() 抓取权威行后回滚;其他驱动回退源码提取。 新装/升级/接手旧库后运行 php artisan data:sync --apply 一次即可收敛,可重复执行(幂等)。

┌────────────────── 分区导航(按此顺序阅读)──────────────────┐ 分区 1 · 同步入口 syncAll / reconcile / canonicalRows (补插用户行的密码明文经 generatedPasswords 回显) 分区 2 · 内部辅助 captureBySeederRun / extractRowsFromSource / seederTable / jsonColumns remapRow / naturalKey / findExistingId / insertRow contentDiff / normalizeJson / bumpSequence / clearCaches └────────────────────────────────────────────────────────────┘

Summary

Methods
Properties
Constants
syncAll()
reconcile()
canonicalRows()
$generatedPasswords
NATURAL_KEYS
CONTENT_SYNC_TABLES
FK_REMAP
SELF_PARENT
IGNORED_COLS
SEEDERS
No protected methods found
No protected properties found
N/A
captureBySeederRun()
extractRowsFromSource()
assertLiteralOnly()
seederTable()
jsonColumns()
remapRow()
naturalKey()
findExistingId()
insertRow()
contentDiff()
normalizeJson()
bumpSequence()
clearCaches()
No private properties found
N/A

Constants

NATURAL_KEYS

NATURAL_KEYS = ['td_sys_menu' => ['name'], 'td_sys_permission' => ['code'], 'td_sys_role' => ['code'], 'td_sys_cache' => ['name'], 'td_sys_config_definition' => ['key'], 'td_sys_config_value' => ['key', 'tab_key'], 'td_sys_dict_type' => ['code'], 'td_sys_dict_data' => ['type_code', 'parent_id', 'value'], 'td_sys_company' => ['code'], 'td_sys_dept' => ['name'], 'td_sys_user' => ['username'], 'td_sys_role_menu' => ['role_id', 'menu_id'], 'td_sys_role_permission' => ['role_id', 'permission_id'], 'td_sys_user_role' => ['user_id', 'role_id'], 'td_sys_post' => ['code'], 'td_sys_user_dept' => ['user_id', 'dept_id', 'post_id'], 'td_sys_post_scope' => ['post_id', 'scope_mode', 'company_id', 'dept_id'], 'td_sys_user_scope' => ['user_id', 'company_id', 'dept_id'], 'td_sys_template' => ['type', 'code'], 'td_sys_job_type' => ['type_code']]

各表自然键(出自唯一约束;无唯一约束用 name)

CONTENT_SYNC_TABLES

CONTENT_SYNC_TABLES = ['td_sys_menu', 'td_sys_permission', 'td_sys_role', 'td_sys_cache', 'td_sys_config_definition', 'td_sys_dict_type', 'td_sys_dict_data', 'td_sys_company', 'td_sys_dept', 'td_sys_post', 'td_sys_template', 'td_sys_role_menu', 'td_sys_role_permission', 'td_sys_user_role', 'td_sys_user_dept', 'td_sys_post_scope', 'td_sys_user_scope', 'td_sys_job_type']

内容同步范围(代码持有表);config_value/user 为数据持有表,只补缺不覆盖内容

FK_REMAP

FK_REMAP = ['role_id' => 'td_sys_role', 'menu_id' => 'td_sys_menu', 'permission_id' => 'td_sys_permission', 'user_id' => 'td_sys_user', 'dept_id' => 'td_sys_dept', 'post_id' => 'td_sys_post', 'company_id' => 'td_sys_company', 'definition_id' => 'td_sys_config_definition']

绑定表 id 列 → 主表(插入时按自然键已存在行的实际 id 重映射)

SELF_PARENT

SELF_PARENT = ['td_sys_menu' => true, 'td_sys_dept' => true, 'td_sys_dict_data' => true]

自引用 parent_id 的表

IGNORED_COLS

IGNORED_COLS = ['id', 'create_time', 'update_time']

内容比对/同步忽略列:主键与数据库自动维护的时间戳

SEEDERS

SEEDERS = [\Database\Seeders\TdSysMenuSeeder::class, \Database\Seeders\TdSysPermissionSeeder::class, \Database\Seeders\TdSysRoleSeeder::class, \Database\Seeders\TdSysCacheSeeder::class, \Database\Seeders\TdSysConfigDefinitionSeeder::class, \Database\Seeders\TdSysConfigValueSeeder::class, \Database\Seeders\TdSysDictTypeSeeder::class, \Database\Seeders\TdSysDictDataSeeder::class, \Database\Seeders\TdSysCompanySeeder::class, \Database\Seeders\TdSysDeptSeeder::class, \Database\Seeders\TdSysUserSeeder::class, \Database\Seeders\TdSysRoleMenuSeeder::class, \Database\Seeders\TdSysRolePermissionSeeder::class, \Database\Seeders\TdSysUserRoleSeeder::class, \Database\Seeders\TdSysPostSeeder::class, \Database\Seeders\TdSysUserDeptSeeder::class, \Database\Seeders\TdSysPostScopeSeeder::class, \Database\Seeders\TdSysUserScopeSeeder::class, \Database\Seeders\TdSysTemplateSeeder::class, \Database\Seeders\TdSysJobTypeSeeder::class]

依赖顺序(同 DatabaseSeeder)

Properties

$generatedPasswords

$generatedPasswords : array

本次 --apply 补插用户行时对应的初始密码明文(username → 明文),供命令回显

Type

array

Methods

syncAll()

syncAll(bool  $apply = false) : array

全部表对齐。返回每表报告:

Parameters

bool $apply

Returns

array —

reconcile()

reconcile(string  $table, array<int,array<string,mixed>>  $rows, array<string,array<string,int>>  $maps, bool  $apply = false, array<int,string>  $touched = [], array<int,string>|null  $inserted = null) : array

单表对齐:补缺 + (代码持有表)内容同步。

Parameters

string $table
array> $rows

规范行(Seeder 顺序)

array> $maps

seeder 原始 id → 库实际 id

bool $apply

是否落库(false 仅报告差异)

array $touched

已变更表清单(apply 时按引用回填)

array|null $inserted

补插用户名清单(按引用回填,供密码明文回显)

Returns

array —

canonicalRows()

canonicalRows(string  $class) : array

规范数据:PG 事务内真实执行 Seeder 后抓取(权威);失败/非 PG 回退源码提取

Parameters

string $class

Returns

array —

captureBySeederRun()

captureBySeederRun(string  $class) : array

事务内执行 Seeder::run()(TRUNCATE+全量插入),SELECT 抓取后回滚——数据库零改动

Parameters

string $class

Returns

array —

extractRowsFromSource()

extractRowsFromSource(string  $class) : array

从 Seeder 源码提取 $rows 字面量(先经白名单校验,仅接受纯标量/数组字面量语法)

Parameters

string $class

Returns

array —

assertLiteralOnly()

assertLiteralOnly(array  $tokens) : void

eval 前白名单校验:字面量只允许标量与数组语法 token (数字/字符串/null/true/false/数组箭头/括号逗号/空白注释), 出现变量、函数调用、类常量、操作符等任何可执行构造一律拒绝。

Parameters

array $tokens

seederTable()

seederTable(string  $class) : string

从 Seeder 源码提取 TABLE 常量

Parameters

string $class

Returns

string —

jsonColumns()

jsonColumns(string  $table) : array

取表的 json/jsonb 列名(仅 PG)

Parameters

string $table

Returns

array —

remapRow()

remapRow(string  $table, array  $row, array  $maps) : array

行内 id 重映射:外键列按主表映射;自引用表 parent_id 按本表映射

Parameters

string $table
array $row
array $maps

Returns

array —

naturalKey()

naturalKey(array  $keyCols, array  $row) : string

自然键归一:列值归一为字符串(null 哨兵),json 编码防分隔符碰撞

Parameters

array $keyCols
array $row

Returns

string —

findExistingId()

findExistingId(string  $table, array  $keyCols, array  $row) : ?int

按自然键查已存在行的 id

Parameters

string $table
array $keyCols
array $row

Returns

?int —

insertRow()

insertRow(string  $table, array  $row, array  $jsonCols, array  $keyCols, array  $maps) : ?int

插入行:id 冲突时去 id 用序列重试;自然键冲突回查已存在行

Parameters

string $table
array $row
array $jsonCols
array $keyCols
array $maps

Returns

?int —

contentDiff()

contentDiff(string  $table, array  $row, array  $jsonCols, array  $dbRow) : array

逐字段内容差异(忽略主键/时间戳;json 规范化比较;'' 与 null 等价;dbRow 由调用方内存索引传入,不再逐行查库)

Parameters

string $table
array $row
array $jsonCols
array $dbRow

Returns

array —

normalizeJson()

normalizeJson(mixed  $v) : mixed

递归 json 规范化:字符串解码、数组递归

Parameters

mixed $v

Returns

mixed —

bumpSequence()

bumpSequence(string  $table) : void

PG 序列对齐到 MAX(id)(插入后防序列冲突)

Parameters

string $table

clearCaches()

clearCaches() : void

清业务缓存:全部注册项 forgetAll(受保护缓存自动豁免,不踢会话/验证码/限流)