You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 10如何扩展现有Artisan命令?添加自定义选项

如何扩展现有的Laravel Artisan migrate命令?

我希望为php artisan migrate添加两个自定义选项:

php artisan migrate --core
php artisan migrate --project=0f9ebA2

需求是不修改默认migrate命令的任何行为,仅新增这两个选项,通过一个包装类预先设置配置变量或路径参数,之后把所有其他参数正常传递给原Artisan migrate命令。

预期的大致实现逻辑:

  • 当使用--core选项时:
public function handle() {
    $this->call('migrate', ['--path' => '/database/migrations/core', ...$this->arguments()]);
}
  • 当使用--project=xxx选项时:
public function handle() {
    config(['tenant.key' => $this->argument('--project')]);
    $this->call('migrate', ['--path' => '/database/migrations/project', ...$this->arguments()]);
}

Laravel官方文档主要聚焦于编写全新自定义命令,偶尔提到用$this->call()调用其他命令,但没有覆盖扩展现有命令或传递通配符参数的场景。


已尝试但无效的方案

  • 创建独立自定义命令(如php artisan migrate:core):虽然能实现功能,但无法保留原migrate命令的所有必要选项,没法为核心迁移设置上下文。
  • 自定义命令手动传递参数:可以通过$this->arguments()获取参数并附加到内部调用,但所有参数都必须在自定义命令的签名里声明,否则会被拒绝,没有通配符传递的方式;复制原migrate的参数定义又缺乏灵活性,无法适配Laravel核心后续变更或第三方包的扩展。
  • 直接继承原MigrateCommand创建新命令:尝试做原migrate的别名,代码如下:
namespace App\Console\Commands;

use Illuminate\Database\Console\Migrations\MigrateCommand;

class MigrateCore extends MigrateCommand {
    protected $signature = 'migrate:core';

    public function handle() {
        parent::handle();
    }
}

运行时抛出Laravel核心级别的BindingResolutionException异常:

Target [Illuminate\Database\Migrations\MigrationRepositoryInterface] is not instantiable while building [App\Console\Commands\MigrateCore, Illuminate\Database\Migrations\Migrator]

显然这不是Laravel推荐的实现方式。


正确的实现方案

方法1:扩展原生migrate命令(推荐)

Laravel允许通过命令启动钩子修改现有命令的定义,添加自定义选项并注入逻辑,完全保留原命令的所有功能:

  1. 在app/Providers/AppServiceProvider.php的boot方法中添加以下代码:
use Illuminate\Support\Facades\Artisan;
use Illuminate\Database\Console\Migrations\MigrateCommand;
use Symfony\Component\Console\Input\InputOption;

public function boot()
{
    Artisan::starting(function ($artisan) {
        // 找到原生migrate命令
        $command = $artisan->find('migrate');
        
        // 添加--core选项(无值)
        $command->getDefinition()->addOption(
            new InputOption(
                'core',
                null,
                InputOption::VALUE_NONE,
                '执行核心模块迁移'
            )
        );
        
        // 添加--project选项(需要传值)
        $command->getDefinition()->addOption(
            new InputOption(
                'project',
                null,
                InputOption::VALUE_REQUIRED,
                '执行指定项目的租户迁移'
            )
        );

        // 保存原命令的handle方法
        $originalHandle = $command->handle;
        
        // 覆盖handle方法注入自定义逻辑
        $command->handle = function () use ($command, $originalHandle) {
            $input = $command->input;
            
            // 处理--core选项
            if ($input->getOption('core')) {
                $input->setOption('path', database_path('migrations/core'));
            }
            
            // 处理--project选项
            if ($projectKey = $input->getOption('project')) {
                config(['tenant.key' => $projectKey]);
                $input->setOption('path', database_path('migrations/project'));
            }
            
            // 执行原命令的逻辑
            return $originalHandle->call($command);
        };
    });
}
  1. 使用方式:
    直接运行目标命令,原migrate的所有参数(如--force、--seed等)都能正常使用:
# 执行核心迁移,同时强制跳过环境检查
php artisan migrate --core --force

# 执行指定项目的迁移并自动填充种子数据
php artisan migrate --project=0f9ebA2 --seed

方法2:自定义包装命令(兼容旧版本)

如果不想修改原命令,也可以创建一个自定义命令,通过通配符接收所有参数再传递给原migrate:

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;

class CustomMigrate extends Command
{
    protected $signature = 'migrate {--core : 执行核心模块迁移} {--project= : 执行指定项目的租户迁移} {--*=* : 传递原migrate命令的所有选项}';

    protected $description = '扩展版migrate命令,支持核心/项目迁移切换';

    public function handle()
    {
        $arguments = [];
        
        // 处理自定义选项
        if ($this->option('core')) {
            $arguments['--path'] = database_path('migrations/core');
        }
        
        if ($projectKey = $this->option('project')) {
            config(['tenant.key' => $projectKey]);
            $arguments['--path'] = database_path('migrations/project');
        }
        
        // 收集所有其他非自定义选项
        foreach ($this->options() as $key => $value) {
            $excludeOptions = ['core', 'project', 'help', 'quiet', 'verbose', 'version', 'ansi', 'no-ansi', 'no-interaction', 'env'];
            if (!in_array($key, $excludeOptions)) {
                $arguments["--{$key}"] = $value !== false ? $value : true;
            }
        }
        
        // 调用原migrate命令
        return Artisan::call('migrate', $arguments);
    }
}

内容的提问来源于stack exchange,提问作者CodeMoose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:59:59