かきスタンプ

福岡でフリーランスの物流系のエンジニアやってます。

Laravel:Command クラスの handle メソッドに記述されている return 0 って何?

【 環境 】
Laravel のバージョン: 8.16.1
PHP のバージョン: 7.4.7

コマンドを作成する時、以下のようなコマンドで雛形を作ることが出来ます。 (例:SampleCommand クラス)

php artisan make:command SampleCommand

上記のコマンドで作成されるファイルは、こんな感じ。

app\Console\Commands\SampleCommand.php

class SampleCommand extends Command
{

// 中略

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        return 0;
    }
}

handle メソッドの「return 0;」って何?
と思って調べてみたら、どうやら、コマンドを実行した時に帰って来る終了コードみたい。

終了コードって?

直前に実行したコマンド(ジョブ等)が、成功したのか失敗したのかを識別するためのコード。

Linux の場合、以下のコマンドで確認できる。

echo $?

0 : 成功
0以外 : 失敗(エラーコード)

といった感じ。

PHPユニットの実行結果の合否判定にも使えます。

(例)
php artisan test --testsuite=Unit

handle メソッドの return

コマンドから作成する雛形を実行した時、必ず 0 が返ってくるので、常に「成功」と判断される。

何かしらの処理を実行して、成功したか/失敗したかを判断したいなら、リターンコードを返してもいいかもしんない。

    public function handle()
    {
        $returnCode = $this->accountService->destroyLockedAccount();

        // 本当は直接返してもいいけど、説明するにはこっちが分かりやすそうだったんで。
        return $returnCode
    }

ちなみに return を省略した場合「0」が返る。

コマンドラインからコマンドを実行する場合「;」で繋げて実行結果を出力するといいかもしれません。

php artisan command:name ; echo $?

スケジューラでもリターンコードは取得できる?

調べてみたが、どうやら出来ないみたい。

$schedule->command の戻り値は event で、コマンドの実行結果を格納されるワケではない。
メソッドチェーンの先に実行結果のリターンコードを取得できるメソッドが無いか調べてみたが、どうやら無さそう。

という事で、スケジューラからコマンドを実行する場合、コマンドが成功したかどうかを判断する場合、各々のメソッドで識別が必要。

class Kernel extends ConsoleKernel
{
    protected function schedule(Schedule $schedule)
    {
        $event = $schedule->command(SampleCommand::class)
                                ->everyMinute();

        dump($event->expression);  //=> "* * * * *"


        //// 本当はこんな感じで書いてみたかった
        //
        // $returnCode = $schedule->command(SampleCommand::class)
        // if($returnCode === 0){
        //     \Log::info('SampleCommand は正常に終了しました。');
        // }else{
        //     \Log::error("SampleCommand は異常終了しました。エラーコード{$SampleCommand}");
        // }

    }

Laravel:artisan route:list コマンド実行時の「_debugbar..」の情報をカットする

Laravel Debugbar は便利なんだけど、artisan route:list コマンドでルーティング情報をリストアップする時、先頭が「_debugbar」というノイズが入って来ます。

ですが、Laravel 8.34 以上なら、「--except-path」のオプションを付けると、上記のノイズを除去できます。

コマンド内容

php artisan route:list --except-path _debugbar

以下、Laravel 8.5.16 で実行しています。

--except-path オプションなし

f:id:kakisoft:20210507005726p:plain

--except-path オプションあり

f:id:kakisoft:20210507005749p:plain


参考
https://github.com/barryvdh/laravel-debugbar/issues/1046

Laravel:migration 実行時、MySQL の時だけ実行するコマンドを設定する

Laravel の migration は便利なのですが、テーブルのスキーマ定義が、Laravel の命令だけで解決できない事があります。

例えば、「テーブル名にコメントを付ける」といった命令は用意されていないため、実行したい場合は DBドライバごとの固有のコマンドを使用する必要があります。( Laravel 8 時点)

具体的には、DB::statement メソッドにて、ALTER TABLE コマンドを実行します。

しかし、ALTER TABLE コマンドは、ほとんどの場合、RDB固有のコマンドとなってしまうため、migration の本流に載せるのは避けたい。

そんな感じで、「データベースドライバが MySQL の時だけ実行したい」または「SQLite の時だけ実行したい」といった場合、getDriverName() にて、データベースドライバを名を取得して、識別する方法があります。

具体的には、以下のようなコード。

    public function up()
    {
        if (DB::getDriverName() !== 'mysql') {
            return;
        }

        DB::statement("ALTER TABLE `users` COMMENT 'ユーザマスタ'");
    }

上記の場合、MySQL の時のみ、ALTER TABLE コマンドを実行します。
SQLite の場合、DB::getDriverName() にて 'sqlite' という値を取得します。)

コードを書く場合、変に switch文で分岐させるよりも、個別のドライバ用に migration ファイルを用意して、該当のドライバでなければ早期リターンする、という構造がいいんじゃないかと思います。

Laravel : 【MySQL】int のサイズを指定しているにも関わらず、column_type が「int(11)」となってしまう

MySQL のバージョン : 5.7
Laravel のバージョン: 8.16.1
PHP のバージョン: 7.4.7
 
Laravel で migration ファイルにてテーブルのカラムを追加する時、こんな感じで intのサイズを指定する事ができる。

    Schema::table('projects', function (Blueprint $table) {
        $table->integer('category_code')->length(3);
    });

が、実際に生成された MySQLスキーマを見ると、column_type は「int(11)」。
何故? 何か間違えた?

と思って調べてみたら、こんなのが見つかった。

https://stackoverflow.com/questions/25772759/schema-builder-length-of-an-integer

If you're using MySQL, you can't specify the length of an integer column. You can only choose between one of the available integer types, described at http://dev.mysql.com/doc/refman/5.1/en/integer-types.html

要は、「MySQL を使っている場合、長さの指定はできない」らしい。

どういう事かと言うと、MySQL の一部の型は、型によって既にサイズが確定しており、サイズを好き勝手に変える事は出来ないとの事。

その表が、こちら。
https://dev.mysql.com/doc/refman/8.0/en/integer-types.html

結論

MySQL で int を使うなら必ず『 int(11) 』になるけど、MySQL の仕様上、仕方ないから勘弁してね 」

じゃ、tinyint はどうなの?
という事で調べてみたら、こんなのがあった。

Laravelにてテーブルの既存カラムをtinyint型に変更できない問題

要は、
「int → tinyint に変更できない」
との事。(逆なら可)

逆が出来ないという事は、rollback が正常に動かないという事なので、採用は慎重に、というか見送った方がいいだろ。

実際、自分も余計なエラーに悩まされたし。

という訳で、int、bigint を使う場合は、デフォルトの長さでOK。
(というかそれ以外できない)

NVM for Windows を使ったけど Node.js のバージョンが切り替わらない! そんな時は、環境変数を見てみよう。

NVM for Windows を使うと、Windows 上で Node.js のバージョン管理ができるのですが、バージョンが切り替わらない現象に遭遇しました。
以下、その対策です。

NVM for Windows のインストール

Chocolatey(パッケージマネージャー)を使用しています。Chocolateyのインストール方法は、こちらでも。
ちなみに公式サイトはこちら

choco install nvm

別バージョンの Node.js をインストール

例:v13.7.0

nvm install v13.7.0

Node.js のバージョンを切り替え

例:v13.7.0

nvm use 13.7.0

これで Node.js のバージョンが切り替わってるはずが

λ node -v
v14.4.0

こんな感じで、マシンにインストールされている Node.js のバージョンが表示されました。

対策

環境変数が正常に設定されていない可能性があるので、設定し直します。

まず、コマンドプロンプトで「where nvm」と入力し、nvm のパスを調べます。
PowerShell には where コマンドは無いみたい)

C:\>where nvm
C:\ProgramData\nvm\nvm.exe

今回のケースの場合、「C:\ProgramData\nvm」を使用します。

システムの環境変数に、以下を追加します。

変数名 : NVM_HOME
変数値 : C:\ProgramData\nvm

続いて、コマンドプロンプトで「where node」と入力し、node.js のパスを調べます。

C:\>where node
C:\Program Files\nodejs\node.exe

今回のケースでは、「C:\Program Files\nodejs」を使用します。

システム環境変数に、以下を設定します。

変数名 : NVM_SYMLINK
変数値 : C:\Program Files\nodejs

こんな感じになります。
f:id:kakisoft:20200607113304j:plain

その後、環境変数の設定内容を反映させます。
(コンソールのウィンドウを開きなおす)

それでもバージョンが切り替わらない場合

公式サイトから配布されているインストーラを使用してください。
https://github.com/coreybutler/nvm-windows/releases/

nvm-setup.zip を選択し、「nvm-setup.exe」を起動してインストール。

f:id:kakisoft:20200607113316j:plain

こんなメッセージが出た場合は「はい」を選択します。
多分、この時に Node.js と上手い事やってくれてるんじゃないかと思います。

Laravel : $this->validate にて、カスタムメッセージを使用する

Laravel でバリデーションをする時、FormRequest を継承したクラスを定義しなくても、コントローラに以下のように書く事でバリデーションができます。

FormRequest を使うほどの汎用性もボリュームもない場合は、この方法でも良いのではないでしょうか。

    $this->validate(
        $request,
        [
            'title' => 'required|min:3',
            'body'  => 'required'
        ],
    );

エラーメッセージをカスタマイズしたい場合、フォームリクエストを使用したときは messages() メソッドにその内容を書いていくけど、この場合はどうすれば?
と思って調べてみた。

単に、validate の第2引数に、メッセージの内容を渡すだけでOKです。

    $this->validate(
        $request,
        [
            'title' => 'required|min:3',
            'body'  => 'required'
        ],
        [
            'title.required' => 'please enter title.',
            'body.required'  => 'please enter body.'
        ]
    );

Validatorファサードを使用する場合、こんな感じ。

      \Validator::make($request->all(),
          [
              'title' => 'required|min:3',
              'body' => 'required',
          ],
          [
              'title.required' => 'please enter title.',
              'body.required'  => 'please enter body.'
          ]
      )->validate();

PHP:JSON エンコードした時に「/」が「\/」になる挙動を回避

通常、json_encode した場合、「/」は「\/」にエスケープされます。

$array_data = [
    'message' => 'Please register as /regist_users',
];

echo json_encode($array_data);
//=> {"message":"Please register as \/regist_users"}

エスケープさせず、そのまま「/」を表示したい場合、JSON_UNESCAPED_SLASHES オプションを使います。

$array_data = [
    'message' => 'Please register as /regist_users',
];


echo json_encode($array_data, JSON_UNESCAPED_SLASHES);
//=> {"message":"Please register as /regist_users"}

 
 


<参考>
https://www.php.net/manual/ja/function.json-encode.php
https://www.php.net/manual/ja/json.constants.php