Symfony2のコマンド(タスク)システム

symfony 1.xでシステムを開発する場合、結構手放せないのがタスクの仕組みです。組み込みのコマンドはもちろん、バッチ処理から、ちょっとしたヘルパータスクなど、私はシステムを開発する上で結構使っています。

このタスクシステム、Symfony2ではどうなっているのでしょう?

用語としては、「タスク」ではなく「コマンド」という用語になっているようです。

コマンドはバンドル単位で作る

symfony 1.xでは、symfonyコアのタスク、プラグインのタスク、プロジェクトレベルのlib/taskにあるタスクが自動的に読み込まれていました。

Symfony2では、「アプリケーション」という概念が変更され、プラグインに近い「バンドル」という単位でアプリケーションも管理されるようになります。

そして、このバンドルという単位でコマンドが読み込まれます。

※Symfony2のコアもバンドルの1つで、他のバンドルと同じ様式でコマンドの一覧が読み込まれます。


具体的には、バンドルのルートディレクトリに「Command」というディレクトリで、「〜Command.php」というファイル名の、「Symfony\Component\Console\Command\Command」を継承したクラスが読み込まれます。

symfony 1.xのタスクとSymfony2のコマンドの比較

symfony 1.x Symfony2
名称 タスク コマンド
親クラス sfBaseTask Symfony\Component\Console\Command\Command
ディレクト (project)/lib/task、(plugin)/lib/task (bundle)/Command
ファイル名 〜Task.class.php 〜Command.php

コマンド登録処理の流れ

  • app/console - Applicationのインスタンス
  • Symfony\Bundle\FrameworkBundle\Console\Application __construct()
  • Symfony\Bundle\FrameworkBundle\Console\Application registerCommands()
    • 登録されているバンドルの一覧をforeach
      • バンドルごとにregisterCommands()
      • (各バンドルでオーバーライドされていなければ)Symfony\Component\HttpKernel\Bundle\Bundle registerCommands()
<?php
    public function registerCommands(Application $application)
    {
        if (!$dir = realpath($this->getPath().'/Command')) {
            return;
        }

        $finder = new Finder();
        $finder->files()->name('*Command.php')->in($dir);

        $prefix = $this->namespacePrefix.'\\'.$this->name.'\\Command';
        foreach ($finder as $file) {
            $r = new \ReflectionClass($prefix.strtr($file->getPath(), array($dir => '', '/' => '\\')).'\\'.basename($file, '.php'));
            if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract()) {
                $application->addCommand($r->newInstance());
            }
        }
    }

注意

このことから、バンドルのルートディレクトリ直下のCommandという名前のディレクトリは特別な意味を持つので、(ファイル名等が上記コマンドの規則でなければ読み込まれることはありませんが)Symfony2準拠のコマンドを格納する用途以外ではCommandというディレクトリを使わない方がよさそうです。