Edited at

Symfonyのconsoleコンポーネントを使ってCLIコマンドを作成する

More than 3 years have passed since last update.

Httpで出力させているものをCLIでみたいとの要望があったので対応した。色々躓いた点があったのでメモ。


CLI対応の流れ


  1. symfony/consoleコンポーネントをインストール

  2. Commandファイルを作成

  3. composerのautoloaderにCommandファイルの名前空間を指定し読み込まれるようにする

  4. 実行ファイル(app/console)を作成

  5. 実行


詳細


1. symfony/consoleコンポーネントをインストール


composer.json

{

"require":{
"symfony/http-foundation":"2.1.x-dev",
"pimple/pimple": "1.0.0",
"guzzlehttp/guzzle": "~5.0",
"symfony/console": "2.4.*" ←追加
}
}

その後composerを実行。

$ composer install

//もしくは下記で実行してもok。下記はautoloadだけを更新するのでよりスマート。
$ composer dumpautoload

ちゃんとコンポーネントがインストールされているかチェック。

$ vendor/symfony/console

これでok。つぎにこれらコンポーネントが自動読み込みされるようにbootstrap.phpに追加。composerに追加されたコンポーネントはすべてvendor/autoload.phpを読み込むことで自動読み込みされる。


bootstrap.php

require 'vendor/autoload.php'; //←追加

require 'config.php';
require 'model.php';
require 'controller.php';
require 'service/apiService.php';


2. Commandファイルを作成

つぎにCommandファイルを作成する。

$ mkdir Command

$ vim Command/AnalizeCommand.php

コマンドファイルの接尾語はxxxCommand.phpである必要があるので注意。


AnalizeCommand.php

namespace Command;

use Command\CommandWrapper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;

class AnalizeCommand extends CommandWrapper
{
protected function configure()
{
$this
->setName('traintrack:analize')
->setDescription('Analize location infomation')
;
}
protected function execute(Inputinterface $input, OutputInterface $output)
{
$muchData = $this->container['model.allData'];
foreach($muchData as $data):
$text = 'id:'.$data['id'].' user_id:'.$data['user_id'];
$output->writeln('<info>'.$text.'</info>');
endforeach;
}
}


execute時にcontainerを使いたかったのでCommand\CommandWrapperクラスをつくりそれを継承する形で実装した。


CommandWrapper.php

namespace Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

abstract class CommandWrapper extends Command
{
protected $container;
public function __construct($container)
{
$this->container = $container;
parent::__construct(null);
}
}


ここらへんはSymfony2のクックブックを参照のこと。

コンソール/コマンドラインツールとしてのコマンドの作成方法


3. composerのautoloaderにCommandファイルの名前空間を指定し読み込まれるようにする

Commandファイル中で名前空間を利用しているので、これを認識させる必要がある。ここでもcomposerの自動読み込みを使う。


composer.json

{

"require":{
"symfony/http-foundation":"2.1.x-dev",
"pimple/pimple": "1.0.0",
"guzzlehttp/guzzle": "~5.0",
"symfony/console": "2.4.*"
},
"autoload":{
"classmap":["Command/"] ←追加
}
}

autoloaderへの追加の仕方は、名前空間の指定、クラスマップの指定、ファイル自体の指定などができる。そちらに関してはこちらのブログを参照。

composer.jsonに登録したらアップデートしてやる。

$ composer dumpautoload

実際に登録されたかどうかを確認するには下記をみてみる。


vendor/composer/autoload_classmap.php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'Command\\AnalizeCommand' => $baseDir . '/Command/AnalizeCommand.php', //←登録済
'Command\\CommandWrapper' => $baseDir . '/Command/CommandWrapper.php', //←登録済
);


これでok。


4. 実行ファイル(app/console)を作成

最後に実行ファイルを作成する。

$ mkdir app

$ vim app/console


conosole

#!/usr/bin/env php

<?php
set_time_limit(0);

require dirname(__FILE__).'/../bootstrap.php';

use Symfony\Component\Console\Application;
use Command\AnalizeCommand;

$app = new Application();
$app->add(new AnalizeCommand($container));
$app->run();


ここでは触れていないが、bootstrap.phpで読み込んでいるconfig.phpでPimpleオブジェクトの$containerを生成している。

ここでいくつか注意点がある。


  • bootstrapの読み込み:dirname(FILE)は参照元のファイル(console)からの相対パスを表す。これがないと実行元のファイルからの相対パスになってしまい、bootstrapがfile not foundとなってしまう。


  • app/consoleに実行権限を与える:chmod +x app/consoleをしてやる必要あり。


  • shebang(シバン)をつけてやる必要がある:一行目の #!/usr/bin/env php のことをシバンという。シェルなどのインタプリタを起動するためのもの。



5. 実行

$ app/console traintrack:analize

これできちんと実行できればok。実行場所はappと同じディレクトリであること。