CodeIgniter 4 中如何精确运行单个迁移文件(支持模块化按需执行)

codeigniter 4 原生不支持直接运行指定迁移文件,但可通过自定义 cli 命令调用 `migrationrunner::force()` 方法实现精准迁移,适用于模块化项目中按组(如 blog、sales)独立执行特定迁移。

在模块化 CodeIgniter 4 项目中,常需按业务域(如 blog、sales、storage)组织迁移文件,并支持仅执行某模块的特定迁移——例如部署新销售功能时,仅运行 sales 目录下的迁移,而非全量迁移。遗憾的是,CI4 官方 spark migrate 命令仅支持按版本号(--force 到某时间戳)、命名空间或全部回滚,不提供“仅运行某一个 .php 迁移文件”的内置指令

所幸,CI4 的 MigrationRunner 类公开了关键方法 force($file, $namespace = 'App', $group = 'default'),它允许传入完整文件路径(相对于 ROOTPATH),跳过版本校验与依赖检查,直接执行该文件中的 up() 方法。我们可基于此构建一个高复用性的自定义命令 migrate:file。

✅ 快速创建自定义命令

在终端执行以下命令生成骨架类:

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

该命令将在 app/Commands/ 下生成 MigrateFileCommand.php。替换其内容为以下精简可靠的实现:

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

    public function run(array $params)
    {
        $filePath = $params[0] ?? null;
        if (!$filePath) {
            CLI::error('Missing required argument: migration file path.');
            $this->showHelp();
            return;
        }

        $namespace = CLI::getOption('namespace') ?: 'App';
        $dbgroup   = CLI::getOption('dbgroup') ?: 'default';

        CLI::write("Executing migration: {$filePath} (NS: {$namespace}, DB: {$dbgroup})", 'yellow');

        $runner = Services::migrations();
        try {
            if (!$runner->force(ROOTPATH . $filePath, $namespace, $dbgroup)) {
                CLI::error('Migration execution failed.', 'red');
                return;
            }

            foreach ($runner->getCliMessages() as $msg) {
                CLI::write($msg);
            }
            CLI::write('✅ Migration completed successfully.', 'green');
        } catch (\Throwable $e) {
            CLI::error("Error: {$e->getMessage()}", 'red');
        }
    }
}
? 注意:确保迁移文件路径使用正斜杠 /(Windows 也兼容),且必须包含 .php 扩展名;路径以 ROOTPATH 为根,如 app/Database/Migrations/...,而非 APP_PATH 或 WRITEPATH。

? 使用示例

执行单个迁移(默认 App 命名空间 + default 数据库):

php spark migrate:file "app/Database/Migrations/2025-05-10-120000_AddSalesDiscounts.php"

指定命名空间(如模块化结构 Modules\Sales)和数据库组:

php spark migrate:file "Modules/Sales/Database/Migrations/2025-05-10-120000_AddSalesDiscounts.php" \
  --namespace "Modules\Sales" \
  --dbgroup "sales_db"

查看帮助文档:

php spark help migrate:file

? 模块化批量执行(进阶用法)

回到你原始需求——按模块键(如 $files['sales'])批量运行多个迁移,可在控制器或服务中封装逻辑:

// 在任意服务类中
public function runModuleMigrations(string $module): bool
{
    $files = [
        'blog'    => ['app/Database/Migrations/2025-01-01-000000_CreatePostsTable.php'],
        'sales'   => [
            'app/Database/Migrations/2025-05-10-120000_AddSalesDiscounts.php

', 'app/Database/Migrations/2025-05-11-143000_AddOrderStatuses.php' ], 'storage' => ['app/Database/Migrations/2025-02-20-090000_CreateFilesTable.php'] ]; $migrationRunner = \Config\Services::migrations(); foreach ($files[$module] ?? [] as $path) { if (!$migrationRunner->force(ROOTPATH . $path, 'App')) { log_message('error', "Failed to run migration: {$path}"); return false; } } return true; }

⚠️ 重要提醒

  • force() 不校验迁移顺序或已执行状态,请确保手动维护执行顺序(如按时间戳升序);
  • 生产环境慎用,建议仅用于开发/部署脚本,避免破坏迁移历史一致性;
  • 若需幂等性与状态追踪,仍应优先使用标准 spark migrate --all 流程,将模块迁移纳入统一版本序列。

通过该方案,你不仅解决了“运行单个迁移”的技术瓶颈,更获得了面向模块的灵活迁移调度能力——让 CI4 的数据库演进真正匹配现代分层架构的演进节奏。