# プラグイン

## 導入

コントローラにはプラグイン機構が組み込まれており、 コントローラの処理中にイベントが発生した際にユーザのコードをコールできます。 フロントコントローラは、プラグインブローカにユーザのプラグインを登録します。 そして、イベントメソッドがコールされた際に、 フロントコントローラに登録されているプラグインをプラグインブローカが実行します。

イベントメソッドは、抽象クラス `Zend_Controller_Plugin_Abstract` で定義されています。 ユーザが作成するプラグインクラスは、これを継承させます。

- `routeStartup()` は、`Zend_Controller_Front` が ルータ をコールしてルートに対するリクエストの評価を始める前にコールされます。

- `routeShutdown()` は、 ルータ がリクエストのルーティングを終了した後にコールされます。

- `dispatchLoopStartup()` は、`Zend_Controller_Front` がディスパッチループに入る前にコールされます。

- `preDispatch()` は、アクションが ディスパッチャ でディスパッチされる前にコールされます。 このコールバックは、プロキシやフィルタ的な動作をさせることができます。 リクエストの内容を変更してディスパッチフラグをリセット (`Zend_Controller_Request_Abstract::setDispatched(false)` を使用します) することで、現在のアクションをスキップさせたり置き換えたりできます。

- `postDispatch()` は、アクションが ディスパッチャ でディスパッチされた後にコールされます。 このコールバックは、プロキシやフィルタ的な動作をさせることができます。 リクエストの内容を変更してディスパッチフラグをリセット (`Zend_Controller_Request_Abstract::setDispatched(false)` を使用します) することで、新しいディスパッチ先アクションを指定できます。

- `dispatchLoopShutdown()` は、`Zend_Controller_Front` がディスパッチループを抜けた後にコールされます。

## プラグインの書き方

プラグインクラスを書くには、単に抽象クラス `Zend_Controller_Plugin_Abstract` をインクルードしてそれを継承するだけです。

    class MyPlugin extends Zend_Controller_Plugin_Abstract
    {
        // ...
    }

`Zend_Controller_Plugin_Abstract` には抽象メソッドはありません。 つまり、上に示したイベントメソッドを、 プラグインクラスでかならず実装しなければならないわけではありません。 プラグインの作者が、必要なものだけを選んで実装できます。

`Zend_Controller_Plugin_Abstract` では、 リクエストオブジェクトやレスポンスオブジェクトをプラグインから操作できます。 それぞれ、`getRequest()` メソッドおよび `getResponse()` メソッドを使用します。

## プラグインの使用法

プラグインクラスを登録するには、 `Zend_Controller_Front::registerPlugin()` をコールします。 これは、いつでも行うことができます。 次の例は、コントローラチェインでプラグインを使用する方法を示すものです。

    class MyPlugin extends Zend_Controller_Plugin_Abstract
    {
        public function routeStartup(Zend_Controller_Request_Abstract $request)
        {
            $this->getResponse()
                 ->appendBody("<p>routeStartup() がコールされました</p>\n");
        }

        public function routeShutdown(Zend_Controller_Request_Abstract $request)
        {
            $this->getResponse()
                 ->appendBody("<p>routeShutdown() がコールされました</p>\n");
        }

        public function dispatchLoopStartup(
            Zend_Controller_Request_Abstract $request)
        {
            $this->getResponse()
                 ->appendBody("<p>dispatchLoopStartup() がコールされました</p>\n");
        }

        public function preDispatch(Zend_Controller_Request_Abstract $request)
        {
            $this->getResponse()
                 ->appendBody("<p>preDispatch() がコールされました</p>\n");
        }

        public function postDispatch(Zend_Controller_Request_Abstract $request)
        {
            $this->getResponse()
                 ->appendBody("<p>postDispatch() がコールされました</p>\n");
        }

        public function dispatchLoopShutdown()
        {
            $this->getResponse()
                 ->appendBody("<p>dispatchLoopShutdown() がコールされました</p>\n");
        }
    }

    $front = Zend_Controller_Front::getInstance();
    $front->setControllerDirectory('/path/to/controllers')
          ->setRouter(new Zend_Controller_Router_Rewrite())
          ->registerPlugin(new MyPlugin());
    $front->dispatch();

他に何かの出力を行うアクションがなく、ひとつのアクションのみがコールされたとしましょう。 上のプラグインは、次のような出力を行います。

    <p>routeStartup() がコールされました</p>
    <p>routeShutdown() がコールされました</p>
    <p>dispatchLoopStartup() がコールされました</p>
    <p>preDispatch() がコールされました</p>
    <p>postDispatch() がコールされました</p>
    <p>dispatchLoopShutdown() がコールされました</p>

プラグインは、フロントコントローラの実行時ならいつでも登録できます。 しかし、プラグインがイベントメソッドを登録しようとしているイベントが終わった後では、 そのメソッドは実行されません。

## プラグインの取得と操作

時には、プラグインの登録を解除したりプラグインの情報を取得したいこともあるでしょう。 フロントコントローラには、そのような場合のために次のメソッドが用意されています。

- `getPlugin($class)` は、指定したクラス名のプラグインを取得します。 一致するプラグインがない場合は `FALSE` を返します。 同じクラス名のプラグインが複数登録されている場合は、結果を配列で返します。

- `getPlugins()` は、プラグインスタック全体を取得します。

- `unregisterPlugin($plugin)` は、プラグインをスタックから登録解除します。 パラメータには、プラグインオブジェクト自体かそのクラス名を渡します。 クラス名を渡すと、一致するプラグインがすべて削除されます。

## 標準の配布パッケージに含まれるプラグイン

Zend Framework の配布パッケージには、 エラー処理用のプラグインが標準で組み込まれています。