CodeIgniter 4 中如何精准执行单个迁移文件(Migration)

codeigniter 4 原生不支持直接运行单个迁移文件,但可通过自定义 cli 命令调用 `migrationrunner::force()` 方法实现精准迁移控制,支持指定命名空间、数据库组及动态路径。

在 CodeIgniter 4 的数据库迁移体系中,php spark migrate 默认按时间戳顺序执行所有待迁移文件,而 php spark migrate -f 仅支持指定已注册的迁移类名(含完整命名空间),无法直接通过文件路径触发单次迁移。当项目采用模块化架构(如 blog、sales、storage 等独立模块),需按需激活某模块的特定迁移时,原生能力便显得力不从心。此时,最可靠、可复用的解决方案是:创建自定义 CLI 命令,封装 MigrationRunner::force() 调用逻辑

✅ 实现步骤详解

1. 生成命令骨架

在项目根目录执行:

php spark make:command MigrateFile --command migrate:file --group Database --suffix Command

该命令将在 app/Commands/ 下生成 MigrateFileCommand.php。

2. 编写核心逻辑(关键改造)

将生成的文件替换为以下精简可靠的实现(已适配 CI4.4+,兼容命名空间与多数据库组):

 'Full migration file path relative to ROOTPATH (e.g., "app/Database/Migrations/2025-01-01-000000_CreateUsersTable.php")'
    ];
    protected $options     = [
        '--namespace' => 'Migration namespace (default: "App")',
        '--dbgroup'   => 'Database group name (default: "default")',
    ];

    public function run(array $params)
    {
        CLI::write('▶️ Running single migration...', 'yellow');

        if (!isset($params[0])) {
            CLI::error('Error: Missing migration file path.');
            $this->showHelp();
         

return; } $runner = Services::migrations(); $namespace = CLI::getOption('namespace') ?: 'App'; $dbgroup = CLI::getOption('dbgroup') ?: 'default'; $filePath = ROOTPATH . $params[0]; if (!is_file($filePath)) { CLI::error("File not found: {$filePath}"); return; } try { $result = $runner->force($filePath, $namespace, $dbgroup); if (!$result) { CLI::error(lang('Migrations.generalFault')); return; } foreach ($runner->getCliMessages() as $msg) { CLI::write($msg); } CLI::write('✅ Migration completed successfully.', 'green'); } catch (\Throwable $e) { CLI::error('Exception: ' . $e->getMessage()); } } }
? 关键说明:$runner->force($filePath, $namespace, $dbgroup) 是核心——它绕过版本检查,强制加载并执行指定 PHP 文件中的迁移类,完全满足“按需触发单文件”的诉求。

3. 使用示例

# 执行 App 命名空间下的迁移文件
php spark migrate:file "app/Database/Migrations/2025-05-10-120000_AddSalesOrderTable.php"

# 指定模块命名空间(如 Modules\Sales)
php spark migrate:file "Modules/Sales/Database/Migrations/2025-06-01-090000_UpdateInvoiceStatus.php" --namespace "Modules\Sales"

# 切换至测试数据库组
php spark migrate:file "app/Database/Migrations/2025-01-01-000000_TestDataSeeder.php" --dbgroup "tests"

4. 进阶:在代码中调用(如 Controller 或 Service)

// 在控制器中动态触发迁移
public function triggerSalesMigration()
{
    $output = command('migrate:file "app/Database/Migrations/2025-05-10-120000_AddSalesOrderTable.php"');
    log_message('info', 'Sales migration output: ' . $output);
    return $this->response->setJSON(['status' => 'done', 'output' => $output]);
}

⚠️ 注意事项与最佳实践

  • 路径必须准确:$params[0] 是相对于 ROOTPATH 的路径,不要包含 ROOTPATH 前缀(命令内部已自动拼接)。
  • 命名空间需匹配:确保迁移文件顶部 namespace 声明与 --namespace 参数一致,否则类无法被正确反射加载。
  • 幂等性保障:force() 不检查是否已执行,重复运行可能引发 SQL 错误(如重复建表)。建议在业务逻辑中自行校验 migration_version 表或添加 if (! $this->db->tableExists(...)) 防御。
  • 生产环境慎用:单文件迁移适合开发/部署调试,正式环境推荐使用标准 migrate 流程保证版本一致性。
  • 错误处理:示例中已包含基础异常捕获,实际项目中可扩展日志记录(如写入 writable/logs/)便于追踪。

通过该方案,你不仅能解决模块化迁移的精准调度问题,更可将其封装为团队标准工具——让 php spark migrate:file 成为 CI4 项目中与 migrate 并行的可靠迁移双引擎。