Let's say, for example, I want to add a couple of options to php artisan migrate:
php artisan migrate --core
php artisan migrate --project=0f9ebA2
Is it possible to extend an existing artisan command? I don't want to change any default behavior, just add options. It would be sufficient to have a wrapper class that pre-sets certain options, like changing a config variable or adding a path argument, then passes through everything else to the artisan function as normal.
Stubbed out, php artisan migrate --core would look something like:
public function handle() {
$this->call('migrate', ['--path' => '/database/migrations/core', ...$this->arguments()]);
}
Stubbed out, php artisan migrate --project=0f9ebA2 would look something like:
public function handle() {
config(['tenant.key' => $this->argument('--project')]);
$this->call('migrate', ['--path' => '/database/migrations/project', ...$this->arguments()]);
}
Laravel's documentation is focused solely on authoring custom commands and occasionally invoking other commands with $this->call() - it doesn't seem to cover extending existing functionality, or passing arguments through.
Already Tried / Doesn't Work:
- Creating a separate custom command like
php artisan migrate:core. This will work exactly for the functionality I wish to add, and nothing else - it won't preserve any ofmigrate's other options, which are also needed. The goal is to set context formigrate's core functionality. - Passing arguments through a custom command manually, like the examples above. I can get existing arguments with
$this->arguments()and reattach them to the inner artisan call, but each argument also needs to be in the definition of the custom command - trying to pass an argument that isn't in the commands defined arguments causes the command to be rejected. There doesn't seem to be a way to just wildcard passthrough. Sure I can copy-paste migrate's existing argument definitions, but it won't be flexible with any future core changes or 3rd party packages. - Creating a new custom command that extends
migratedirectly. Trying a proof-of-concept alias of the basemigrate:
namespace App\Console\Commands;
use Illuminate\Database\Console\Migrations\MigrateCommand;
class MigrateCore extends MigrateCommand {
protected $signature = 'migrate:core';
public function handle() {
parent::handle();
}
}
Results in a hairy BindingResolutionException from higher up Laravel's core hierarchy:
Target [Illuminate\Database\Migrations\MigrationRepositoryInterface] is not instantiable while building [App\Console\Commands\MigrateCore, Illuminate\Database\Migrations\Migrator]
which, to me, feels like embarking on a path not intended.
Try adding this as
app/Console/Commands/MigrateCore.php:The error you were getting:
is fairly cryptic, but if you look into the comments in
Illuminate\Container\Containerwhere the error is thrown, it starts to make a bit of sense:The constructor for
Illuminate\Database\Console\Migrations\MigrateCommandwants to be injected with an instance ofIlluminate\Database\Migrations\Migratorwhich in turn is looking for aIlluminate\Database\Migrations\MigrationRepositoryInterface. But no concrete classes have been bound to that interface yet.So, instead of just inheriting the constructor from
Illuminate\Database\Console\Migrations\MigrateCommandwe initialize those bindings with theapp()helper, and then pass them to the constructor.Got a bit of help from this Laracasts post.