Laravel4、自作コマンド名を柔軟に設定する

タグ: Laravel4  

ここ数日、自作パッケージのコマンドをいろいろ作成しています。

ちょうど、他でもコマンドについてTipが書かれていますので、私もノウハウを残しておきます。

完全に一つのアプリとして仕上げるのでしたら、コマンドは勝手に作成できますが、パッケージで公開を前提にすると、コマンドがバッティングした時のため、柔軟に設定できたほうが便利です。

Artisanコマンドにより作成されるクラスは、nameプロパティが用意されています。これを直接変更しても、変わりません。

パッケージからコマンドを提供するとなると、サービスプロバイダーを作成し、それを登録してもらうことになります。その中で、コマンドの準備も行います。通常regisetメソッドで、コンテナに登録しておくことになります。

$this->app['somepackage.ancommand'] = $this->app->share( function($app)
{
     return new AnCommandClass( );
} );

$this->commands( 'somepackage.ancommand');

コンテナにsomepackage.ancommandという名前で登録しています。コアは全部この様に小文字で、必要に応じピリオド区切った名前を使用しています。ですが、実は名前付きクラス名でも可能です。多分、小文字を使っているのは、通常ユーザーが作成するクラス名はアッパー・キャメル記法ですので、内部のクラスとバッティングしないようにという配慮だと推測しています。

逆に言えば、他箇所でも使用されるクラスであれば、名前空間付きのクラス名で登録しておけば、わざわざApp::bindやsingltonで指定する必要はありません。

$this->app->shareで指定されたクロージャーはすぐに実行され、リターンするインスタンスは、シングルトンとして取り扱われます。それ以外の結合方法がお好みでしたら、shareメソッドでなく、bindやsingleton、instanceメソッドなどを使い分けましょう。

registerメソッド実行時点では、Laravelのセットアップも行われていませんので、エイリアスのコアクラス名は使用できません。(たぶん、APPだけは使用できたような気もしますが、記憶があやふやです。)

本題に戻りますが、一度設置した名前を変更したい場合、bootメソッドの中で、コンテナに登録したインスタンスに対しsetNameメソッドが使用できます。

$this->app['somepackage.ancommand']->setName('NewCommand:NewSubCommand');

もちろん柔軟にやるなら、設定を利用しましょう。

$this->app['somepackage.ancommand']->setName(\Config::get(package::item));

setNameメソッドはSymfonyのクラスが持っており、名前のバリデーションを行なってから設定します。

最初自前で同名のメソッドを作成してしまい、しばらくうまく動かず悩みました。分かってしまえば、簡単です。