Laravelでバッチプログラムを作成する | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

Laravelではartisanコマンドを通してコマンドラインから様々な処理を実行することができます。

アプリケーションを作成した場合、全てがWebインターフェースで実装するということは難しい場合もあるので、コマンドラインから実行できるバッチファイルを用意した ほうが便利なことが多かったりします。

ということで、Laravel4.2をベースにしたLaravel上でコマンドを作成する手順のまとめです。



コマンドのテンプレートを作成する


artisanコマンドはlaravelディレクトリの直下に存在し、色んな処理を実行することができます。


$ php artisan list
Laravel Framework version 4.2.18

Usage:
  [options] command [arguments]

Options:
  --help           -h Display this help message
  --quiet          -q Do not output any message
  --verbose        -v|vv|vvv Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
  --version        -V Display this application version
  --ansi              Force ANSI output
  --no-ansi           Disable ANSI output
  --no-interaction -n Do not ask any interactive question
  --env               The environment the command should run under.

Available commands:
  changes                     Display the framework change list
  clear-compiled              Remove the compiled class file
  down                        Put the application into maintenance mode
  dump-autoload               Regenerate framework autoload files
  env                         Display the current framework environment
  help                        Displays help for a command
  list                        Lists commands
  migrate                     Run the database migrations
  optimize                    Optimize the framework for better performance
  routes                      List all registered routes
  serve                       Serve the application on the PHP development server
  tail                        Tail a log file on a remote server
  tinker                      Interact with your application
  up                          Bring the application out of maintenance mode
  workbench                   Create a new package workbench
asset
  asset:publish               Publish a package's assets to the public directory
auth
  auth:clear-reminders        Flush expired reminders.
  auth:reminders-controller   Create a stub password reminder controller
  auth:reminders-table        Create a migration for the password reminders table
cache
  cache:clear                 Flush the application cache
  cache:table                 Create a migration for the cache database table
command
  command:make                Create a new Artisan command
- snip -

この中に自作したコマンドを追加しオプションを指定することでバッチ処理を実行できたりします。

まずは、コマンドファイルを作ることからスタートなのですが、一からコマンドファイルを作成するのも手間なので、そのテンプレートファイルをartisanコマンドを通し て作成することができます。


$ php artisan command:make FooCommand

上記のように実行することでFooCommandファイルを作成することができます。

正常に実行されると、laravel/app/commandsディレクトリ以下に作成されます。


<?php

use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class FooCommand extends Command {
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'command:name';

    /**
     * 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 fire()
    {
        //
    }

    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return array(
            array('example', InputArgument::REQUIRED, 'An example argument.'),
        );
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return array(
            array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
        );
    }
}


コマンドを作成する


作成したテンプレートファイルを元に中身を編集していきます。

プロパティの$nameはコマンド名、$descriptionはコマンドの概要を記載しておきます。

この内容はartsanコマンド実行時に表示されるのでコマンドの中身がわかるように編集しておきましょう。

バッチ処理の具体的な中身はfire()メソッドの中に定義します。


public function fire()
{
    $obj = App::make('SomeClass');
    echo "hello" . PHP_EOL;
}

基本的にLaravelと同様の文法が使えるので、パスが通っていれば上記のようにSomeClassのオブジェクトを生成するというようなこともできます。

バッチ処理が書けたらコマンドをartisanコマンドから実行できるように登録します。

登録するには、laravel/app/start/artisan.phpに下記のように追加します。


<?php

Artisan::add(new FooCommand);

これで、再度artisanコマンドを実行してみると


$ php artisan
-snip-
Foo
  Foo:echoHello               hello出力バッチ
  changes                     Display the framework change list
  clear-compiled              Remove the compiled class file
-snip-

というようにコマンドが登録されています。

余談にはなりますが、「Laravelでサブシステム用のディレクトリを分離する 」に書いたような独自のディレクトリ構成をとった場合は、サービスプロバイダー用 のファイルからコマンドを追加することも出来ます。


public function boot()
{
    \ClassLoader::addDirectories(array(
        __DIR__ . '/../Commands',
    ));
    require __DIR__ . '/../routes.php';
}

public function register()
{
    $this->commands('FooCommand');
}

コマンドを実行するには


$ php artisan Foo:echoHello
hello

というように実行できます。

コマンドには引数とオプションを指定できます。

それぞれ、コマンドファイルのgetArguments()、getOptions()にて指定でき必須の引数などを指定できます。


protected function getArguments()
{
    return array(
        array('name', InputArgument::REQUIRED, 'your name'),
    );
}

protected function getOptions()
{
    return array(
        array('test', 't', InputOption::VALUE_OPTIONAL, 'run test mode', 'false'),
    );
}

上記の場合、引数の名前を必須とし、オプションとしてtestを用意しています。

fire()を少し変更してみます。


public function fire()
{
    if ($this->option('test') === 'true') {
        echo "run test mode" . PHP_EOL;
    }
    echo "hello " . $this->argument('name') . PHP_EOL;
}

オプションにtestが指定された場合はテストモードでの実行であることを表示し、引数nameに指定された名前を結合して出力するようにしています。

これで、下記のように実行してみると


$ php artisan Foo:echoHello itboy --test=true                                  
run test mode
hello itboy

のような結果が出力されます。

この状態では引数が必須(REQUIRED)となっているため、引数を指定しない場合は下記のようなエラーがでます。


$ php artisan Foo:echoHello
  [RuntimeException]
  Not enough arguments.

Foo:echoHello [--test[="..."]] name

引数を任意にしたい場合は


array('name', InputArgument::OPTIONAL, 'your name'),

とします。

オプションは動かし方に好みがあったりするのですが、オプション自体に値を指定したくない場合(--testでテストモード扱いにしたい)は、値を受け取らないこともできます。


array('test', 't', InputOption::VALUE_NONE, 'run test mode', null),

この場合、fire()の中では


if ($this->option('test') === TRUE) {
    echo "run test mode" . PHP_EOL;
}

のようにすることでオプションが指定されたかどうかだけで判別ができるようになります。

また、getOptions()で戻している配列の第2引数は短縮系を表すのでシンプルに


$ php artisan Foo:echoHello -t

というような実行も出来ます(--testまたは-tの両方が利用可能)。

あとは、コマンド実行スクリプトをCronなりジョブ管理ツールなどに登録するなりで定期的に実行すればいいかもしれません。