Laravel Artisanコマンドアプリケーションを作ろう

これは Laravelリファレンス発売記念、販売促進アドベントカレンダー www.adventar.org の2015年12月13日分です(1日遅れ更新中)。

Laravel Artisan

今回はArtisanコマンドアプリケーション開発について紹介します。
Artisanコマンドなんてすでに作ってるぜ!

という方も多いでしょう。

書籍では全てに触れてはいないため(もちろんページの都合上)、
スピンオフ電子版でもこのあたりは詳しく解説する予定ですが、
おさらいも兼ねて見ていきましょう。 (スピンオフ電子版は内容的には高度になる予定です)

まずは簡単な書籍データを取得するサンプルです。

下記の簡単なデータを扱います。

    /** @var array */
    protected $data = [
        'title'     => 'Laravel リファレンス[Ver.5.1 LTS 対応]',
        'sub_title' => 'Web職人好みの新世代PHPフレームワーク',
        'authors'   => [
            '新原 雅司',
            '竹澤 有貴',
            '川瀬 裕久',
            '大村 創太郎',
            '松尾 大',
        ],
        'chapters'  => [
            "1 Laravelの概要",
            "2 Laravelの基本",
            "3 データベース",
            "4 フレームワークの機能",
            "5 フレームワークの拡張",
            "6 テスト",
            "7 実践的なアプリケーション構築",
            "8 Laravelの実践",
        ],
        'contents'  => [
            [
                "1-1 Laravelとは",
                "2-1 はじめてのLaravel",
                "3-1 データベースへの接続設定",
                "4-1 認証",
                "5-1 サービスコンテナ",
                "6-1 ユニットテストの基本",
                "7-1 セキュリティ対策",
                "8-1 サンプルアプリケーションの概要と設計",
            ],
        (略)
    ];

    /**
     * @return array
     */
    public function getData()
    {
        return $this->data;
    }

Laravelプロジェクト配下に適当にディレクトリを作成して、クラスを作成します。
ここでは src/DataAccess/Book.phpとしておきましょう。
composer.jsonnは下記のとおりになります。

  "autoload": {
    "classmap": [
      "database"
    ],
    "psr-4": {
      "App\\": "app/",
      "Sample\\": "src/"
    }
  },

作成したクラスはSample\DataAccess\Bookとなります。
(ComposerについてもLaravelリファレンスで解説しています。)

次にこのクラスを利用するコマンドクラスを作成します。

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Sample\DataStorage\Book;
use Symfony\Component\Console\Helper\FormatterHelper;

/**
 * Class BookConsole
 * シンプルな書籍データを表示するコンソールです
 */
class BookConsole extends Command
{
    /** @var string */
    protected $name = 'book:information';

    /** @var string  */
    protected $description = 'laravel reference book(jp) information';

    /**
     * @param Book $book
     */
    public function handle(Book $book)
    {
        $result = $book->getData();

        $formatHelper = new FormatterHelper();
        $formattedLine = $formatHelper->formatSection(
            'authors',
            implode(', ', $result['authors'])
        );
        $this->output->writeln($formattedLine);
        $this->output->writeln("<fg=cyan;bg=black>{$result['title']}</> <fg=yellow;bg=black>{$result['sub_title']}</>");
        $this->table($result['chapters'], $result['contents']);

        $this->error("JPY " . number_format("{$result['price']}", 2));
    }
}

handleメソッドはコマンド実行時に実行されるメソッドです。
コンソールに表示するフォーマットやroute:listでおなじみのテーブルを利用しています。
実行すると先のSample\DataStorage\Bookクラスの配列が整形されて表示されます。

このコマンドクラスはSymfony\Consoleをラップしたクラスなので、
Symfony\Consoleで提供されているものを自由に利用できます。
文字の表示色なども自由に変更できます。

次にこのコマンドをArtisanコマンドとして実行できるように登録しましょう。
Kernelを利用する方法とサービスプロバイダを利用する方法があります。

ここではサービスプロバイダを利用します。

namespace App\Providers;

use App\Console\Commands\BookConsole;
use Illuminate\Support\ServiceProvider;

/**
 * Class PackageServiceProvider
 */
class PackageServiceProvider extends ServiceProvider
{
    /** @var bool  */
    protected $defer = true;

    public function register()
    {
        $this->app->singleton('command.book.list', function () {
            return new BookConsole();
        });
        $this->commands([
            'command.book.list',
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function provides()
    {
        return [
            'command.book.list',
        ];
    }
}

コマンドアプリケーションは遅延読み込みにします。
Artisanコマンドとして登録するためにcommandsメソッドを使います。
必要なのはサービスコンテナに登録したコマンドのサービス名です。

これでコマンドが実行できるようになりました。

$ php artisan book:information

で書籍情報が表示されます。

もうひとつ、簡単なコマンドラインTwitterクライアントを作成してみましょう。
これも同様にコマンドクラスを作成して、サービスコンテナで登録するだけです。

class TwitterConsole extends Command
{
    /** @var string */
    protected $name = 'twitter:timeline';

    /** @var string */
    protected $description = 'simple twitter client for console';

    /**
     * @param Twitter $client
     */
    public function handle(Twitter $client)
    {
        // https://apps.twitter.com/ でアプリケーションを作成してから利用してください。
        $account = $this->ask('What is your name on Twitter?');
        $appKey = $this->ask('Please enter your Application Consumer Key', 'Consumer Key');
        $appSecret = $this->ask('Please enter your Application Consumer Secret', 'Consumer Secret');
        $result = $client->getCredential($appKey, $appSecret);
        $result = $client->getTimeLine($result->access_token, $account);
        $header = ['created_at', 'text'];
        $murmurs = [];
        foreach ($result as $row) {
            $murmurs[] = [
                $row->created_at,
                $row->text,
            ];
        }
        $this->table($header, $murmurs);
    }
}

このクラスではaskメソッドを利用して、コンソールでユーザーが入力した値を利用するようになっています。
Twitter Appsでアプリケーションを作成し、
API Key、API Secretを入力すれば自分のつぶやきがテーブルで表示されます。
これらを応用するだけで簡単にリッチなコンソールアプリケーションが開発できます。

サンプルはこちら github.com

Laravelリファンレンスではコンソールアプリケーションのテスト、開発時のポイントも紹介しています。
詳しくは書籍をご覧ください。

Laravel リファレンス[Ver.5.1 LTS 対応] Web職人好みの新世代PHPフレームワーク