a_hamada/ 2024年 5月 29日/ 技術

こんにちは、濱田です。
札幌は最近寒暖差が激しくて体調を崩しそうな季節です。

さて今回はこれまでとは少し違い、Laravel について書いていきます。
最近業務でLaravelを扱っていて、その中ではまったことを定期的に書いていこうかなと思っています。

今回はLaravelでカスタムコマンドを実装したときに同じ引数に対して複数個値を渡そうとして結構はまったので、そのことについて書いていきます。

はじめに

Laravelでカスタムコマンドを作成すること自体はそこまで珍しいことではないと思います。
まずはカスタムコマンドの作成方法から説明します。
下記のコマンドを実行するとCommandクラスを継承した、指定したコマンド名がついたクラスファイルが作成されます。

php artisan make:command "コマンド名"

そうして作成されたクラスファイル内のhandleメソッドに自分のやりたい処理を記述していきます。

Laravelのカスタムコマンドで引数の定義

次にコマンド実行時に引数を指定する方法です。
作成されたクラスファイル内に

protected $signature = 'command:name';

という記述があります。
これはコマンド実行時のartisanコマンドの書式を定義するコードなのですが、引数定義もここで行います。
例えば「batch:sampleCommand」という名前のコマンドに"arg"という引数を定義する場合は以下のような定義になります。

protected $signature = 'batch:sampleCommand { arg }';

このように定義することでコマンドで引数を受け取って処理することができます。
引数を増やしたい場合は上記の定義の後ろに"{ arg2 } { arg3 }..."とつなげていくことで実現できます。
もし引数をオプショナルにする場合は、signatureの引数定義の部分に{ arg? }のように引数名の後ろに"?"をつけるとオプショナルにできます。
引数をロジック側で受け取る際は

$arg = $this->argument('arg')

のようにして受け取れます。

同一の引数に複数の値を受け取るには?

前置きが長くなりましたが、ここからが本題です。
※ちなみにですがLaravelのカスタムコマンドの引数はあまり複雑な値を扱うことを推奨していないので、今回の方法もあまりお勧めできるコードではないことをご理解ください。
同一の引数に複数の値というと何がしたいのかわからないかもしれませんが、
例えば以下のように値を受け取りたい場合です。(あくまでイメージです、この方法では受け取れないのでご注意ください)

php artisan batch:sampleCommand "りんご" "バナナ" "ブドウ" "赤" "黄色" "紫"
protected $signature = 'batch:sampleCommand { fruits } { fruits } { fruits } { colors } { colors } { colors }';

$fruits = $this->argument('fruits') // ['りんご', 'ばなな', 'ブドウ']
$colors = $this->argument('colors') // ['赤', '黄色', '紫']

$fruits = ['りんご', 'ばなな', 'ブドウ'];
$colors = ['赤', '黄色', '紫']

上記の例でいうところの$fruitsと$colorsを引数で受け取りたいというのが今回のテーマです。

では実際に私が実現した方法を説明します。
結論から言うとjson形式で引数を渡してhandle()で引数を受け取る際、json_decodeでデコードすると受け取れます。

signatureを下記のように定義したとします。

protected $signature = 'batch:sampleCommand { jsonData }';

そしてこのコマンド実行時に
先ほどの果物の例を当てはめて書くと

php artisan batch:sampleCommand {"fruits": ['りんご', 'ばなな', 'ブドウ'], "colors": ['赤', '黄色', '紫']}

となります。

そしてhandle()で引数を受け取る際には

$jsonData = json_decode($this->argument('data'), true);

とすることで$jsonDataに連想配列のかたちで引数を受け取ることができます。

まとめ

今回はLaravelのコマンドで同一の引数に複数の値を受け取る方法について書きました。
今になって考えてみるとstring型の引数で受け取って、あとから好きな型に成形すればよかったかなとか思いましたが
当時はそんな頭が無かったのでこのやり方に落ち着きました。

先ほども書きましたが、Laravelのカスタムコマンドの引数は基本的に数と位置で判断するので基本的にシンプルにするのが推奨されているので、おそらくこの方法はあまり良い設計ではないと思います。
それでも私と同じようなことをしたいけどやり方が分からなくて困っているという方の助けになれば幸いです。

次回もLaravelのカスタムコマンド関連で1個書きたいなと思っています。
それではまた!

About a_hamada

2020年9月からWebプログラマに転向した半人前 日々勉強することばかり。 最近使っている言語はもっぱらPython