これまでLaravel のArtisanコマンドを使ってできることをご紹介しました。
Artisanコマンドにはたくさんの機能が備わっていますが、その他にもオリジナルのコマンドを作成することができます。
今回はオリジナルのArtisanコマンドを作成する方法と、作成したコマンドを定期実行するためのLaravelのコマンドスケジューラに登録する方法をご紹介します。
この2つの機能を組み合わせると、毎日決められた時間にある処理を実行するといったバッチ処理を簡単に実装することができます。
また、作成したオリジナルコマンドは他のArtisanコマンドと同様にコンソールからも簡単に実行できますので、自分が作ったプログラムを他の開発者に利用させる際にも便利です。
目次
- Artisan オリジナルコマンドの作成
1.1 コマンドクラスの生成
1.2 オリジナルコマンドの実装
1.3 コマンドの実行 - コマンドスケジューラにオリジナルコマンドを登録する
2.1 スケジュールの登録
2.2 コマンドスケジューラの有効化 - コマンドの実行結果をログファイルに出力する
- 最後に
1. Artisanオリジナルコマンドの作成
Artisanのオリジナルコマンドを作成すれば、自分で実装した任意の処理をコンソールおよびコマンドスケジューラから実行することができます。
今回の記事では、データベース上のUserテーブルに登録されているユーザーの件数を毎分取得するコマンドを作成してみます。
1.1 コマンドクラスの生成
まず、オリジナルコマンドの処理を記述するためのコマンドクラスを生成します。
コマンドクラスはArtisan make:commandコマンドを実行することで、はじめから用意されている雛形を元に自動で生成することができます。
# Laravelプロジェクト(PROJECT_NAME)に移動 cd ~/html/laravel/PROJECT_NAME # オリジナルコマンド用のコマンドクラスを生成する php-7.1 artisan make:command UserCountCommand
今回はUserテーブルに登録されているユーザーの件数を取得するためのコマンドなので、クラス名はUserCountCommandとしています。
成功すると、コマンドクラスのファイルがapp/Console/Commands/の直下に作成されます。
1.2 オリジナルコマンドの実装
1.1で生成したコマンドクラスは何も処理が書かれていない空っぽの状態なので、コマンドの名前と任意の処理を記入していきます。
管理ユーザー登録用のUserCountCommandファイルをテキストエディタで開いて編集します。
app/Console/Commands/UserCountCommand.php
<?php namespace App\Console\Commands; use Illuminate\Console\Command; use App\User; class UserCountCommand extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'user:count'; /** * The console command description. * * @var string */ protected $description = 'Command description'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { //標準出力またはログに出力するメッセージ $message = '[' . date('Y-m-d h:i:s') . ']UserCount:' . User::count(); //INFOレベルでメッセージを出力する $this->info( $message ); } }
まず、Userテーブルに対して操作を行いますので
use App\User;
でUserモデルを読み込んでいます。
次に
rotected $signature = 'user:count';
の部分ですが、変数$signatureにコマンドの名前を設定します。
コマンドの名前は任意ですが、覚えやすいものをつけましょう。
最後に、コマンドが実行されたときの処理をhandle()メソッドの中に記入します。
データベース上にあるUserテーブルの情報を参照するのにUser::countプロシージャを呼び出していますが、これはLaravelのEloquent ORMという機能を使っています。
Eloquent ORMについて今回は説明を省略しますが、SQLを書かずにテーブルの参照・登録・更新・削除ができるとても便利な機能です。
メッセージの出力はechoでもできますが、今回はコマンドクラスに用意された標準出力用のメソッド
$this->info()
を使用します。
コマンドクラスには$this->info()の他にも、エラー出力用の$this->error()や、配列を渡すことで自動的にテーブルレイアウトに整形してくれる$this->table ()などの便利な標準出力用のメソッドが用意されています。
コマンドクラスの作成が終わりましたら、作成したコマンドクラスをLaravelに認識させるために下記コマンドをPROJECT_NAME配下で実施し、オートロードの再構成を行います。
php-7.1 ../composer.phar dump-autoload
Laravelは必要なファイルを自動的に読み込む、Composerのオートロードという仕組みを利用しています。
Laravelで開発を進めていくと、新しいファイルを追加した時などさまざまな場面で「Class <ファイル名> does not exist」というエラーが発生することがあります。
上記のエラーが発生したら、まずオートロードの再構成を行ってみてください。
1.3 コマンドの実行
1.2で作成したオリジナルコマンドを、コンソールから実行してみます。
php-7.1 artisan user:count
実行結果は標準出力に出力されます。
成功したら、以下のようなメッセージが緑色の文字で表示されます。
2. コマンドスケジューラにオリジナルコマンドを登録する
Laravelにはコマンドスケジューラという機能があります。
コマンドスケジューラは、あるコマンドを定期実行(決められた日時に繰り返し実行)させるための機能です。
Linuxサーバーを利用されている場合、サーバーのCronを利用して定期実行を設定する方法がポピュラーですが、LaravelにはCronより便利なコマンドスケジューラの機能がありますので、そちらを使用しましょう。
2.1 スケジュールの登録
まずコマンドスケジューラに、定期実行したいコマンドとそれを実行するスケジュールを登録します。
今回は、1.で作成したオリジナルコマンドを毎分ごとに実行するというスケジュールを追加してみます。
app/Console/Kernel.php
<?php namespace App\Console; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ \App\Console\Commands\UserCountCommand::class ]; /** * Define the application's command schedule. * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ protected function schedule(Schedule $schedule) { // user:countコマンドを毎分実行する $schedule->command('user:count')->everyMinute(); } /** * Register the commands for the application. * * @return void */ protected function commands() { $this->load(__DIR__.'/Commands'); require base_path('routes/console.php'); } }
追加するのは全部で2箇所です。
まず、配列$commandsに1.で作成したコマンドクラスの情報を指定します。
末尾をクラス名::classとするところに注意してください。
次に、scheduleメソッドの中にコマンドを実行したいスケジュールを記入します。
$schedule->command('user:count')の部分でどのコマンドを実行するかを明示して
->everyMinute()の部分で実行する日時を指定しています。
everyMinuteメソッドは毎分実行するという設定ですが、他にもCronと同じような細かい実行タイミングの設定が可能ですので、代表的なものを以下に紹介します。
- 毎時間実行する
$schedule->hourly(); - 毎日12時00分に実行する
$schedule ->daily(); - 毎日指定した時間に実行する
$schedule ->dailyAt('5:15'); - 毎月指定した日時に実行する
$schedule ->monthlyOn(25, '23:55'); - Cronと同じ書き方で指定することもできます
$schedule ->cron('* * * * * *');
2.2 コマンドスケジューラの有効化
2.1でスケジュールの登録を行いましたが、これだけではまだコマンドスケジューラは有効になっていません。
Laravelのコマンドスケジューラは裏でCronの機能を利用していますので、crontabにArtisanのコマンドスケジューラを有効にするための設定を追加する必要があります。
Laravelのコマンドスケジューラを有効化するためには、crontabに以下の設定を追加する必要があります。
* * * * * /usr/local/bin/php-7.1 /usr/home/<ユーザー名>/html/laravel/PROJECT_NAME/artisan schedule:run
共用レンタルサーバー『ACE01』では、直接Cronテーブルを編集することができませんので、下記手順に従い「スクリプト定期実行ツール」を利用します。
「スクリプト定期実行ツール」では定期実行のスケジュールを登録する際に、ファイルを指定しなければなりません。(実行するコマンドを直接書くことができません)
そのために、まずArtisanのコマンドスケジューラを実行するためのコマンドを実行するためのPHPファイル(do_cron.php)を作成します。
do_cron.php
<?php exec('/usr/local/bin/php-7.1 /usr/home/<ユーザー名>/html/laravel/PROJECT_NAME/artisan schedule:run');
exec関数はPHPからコマンドラインの外部コマンドを実行することができます。またこの際に、PHPとArtisanについては絶対パスで指定するようにしてください。
ファイルを作成しましたら、サーバーのコントロールパネルにログインして、「スクリプト定期実行ツール」で先ほど作成したファイルを定期実行する設定を行います。
「公開サイト用設定」→「スクリプト定期実行ツール」を選択すると以下のような設定画面が表示されます。
写真を参考にして、次のように設定してください。
- 「新規登録」は先ほど作成したファイル(do_cron.php)を選択
- 「PHPのバージョン」は7.1~を選択
- 「実行スケジュール」は1分毎になるように選択
全ての選択が終わったら「追加する」ボタンをクリックしてください。
これでコマンドスケジューラが有効になり、2.1で登録したスケジュールどおりにコマンドが定期実行されるようになりました。
3. コマンドの実行結果をログファイルに出力する
ここまでの手順を振り返ると、1.で作成したオリジナルコマンドを2.で定期実行するようになりました。
しかし、今のままでは、コマンドスケジューラで定期実行されるコマンドはバックグラウンドで実行されているため、実行結果を知ることができません。
また、正常に完了したのか、エラーが発生したのかも分かりません。
これでは不便なので、コマンドの実行結果やエラーを記録するログファイルを作ってそのファイルに結果を出力するように設定してみましょう。
Laravelのコマンドスケジューラには、ログファイルを出力するためのメソッドも用意されています。
app/Console/Kernel.php
~省略~ protected function schedule(Schedule $schedule) { // user:countコマンドを毎分実行して、ログファイルに出力する $schedule->command('user:count')->everyMinute() ->appendOutputTo(storage_path('logs/user_count.log') ); } ~省略~
ログファイルを出力するには、appendOutputToメソッドを使用します。
appendOutputToメソッドはファイルが既に存在する場合は追記して、存在しない場合は新規作成を行います。
追記ではなく実行ごとに新しいログファイルを作成したい場合はappendOutputToメソッドの代わりにsendOutputToメソッドを使用してください。
storage/logs/にログファイルuser_count.logが作成されます。
毎分ごとにコマンドの実行結果が記述されていることを確認してください。
4. 最後に
今回の記事では、Artisanのオリジナルコマンド作成とコマンドスケジューラの設定方法についてご紹介いたしました。Webアプリケーションでは定期実行によるバッチ処理を実装することが多いので、Laravelのコマンドスケジューラを使いこなして、開発効率の向上を目指しましょう。