7.3. フロントコントローラ

7.3.1. 概要

Zend_Controller_FrontModel-View-Controller (MVC) アプリケーションで用いられる フロントコントローラパターン を実装したものです。 その役割は、リクエスト環境を初期化してリクエストの配送先を決定し、 見つかった配送先に処理を引き渡すことです。また、 レスポンスの内容を取得してそれをコール元に返します。

Zend_Controller_Frontシングルトンパターン も実装しています。つまり、どんな場合でもひとつのインスタンスしか存在しないことになります。 これを利用すると、コントローラをレジストリとして扱えるようになります。

Zend_Controller_Frontプラグインブローカ を持っています。これにより、さまざまなイベントをプラグインで処理できるようになります。 開発者は、ディスパッチ処理をカスタマイズして機能を追加する際に フロントコントローラ自体を継承したクラスを作成する必要がなくなります。

アクションコントローラ へのパスを含むディレクトリを最低ひとつは指定しないと、 フロントコントローラは動作しません。 フロントコントローラの動作環境やそのヘルパークラスを変更するために、 さまざまな手法が用意されています。

[注意] デフォルトの挙動

デフォルトでは、フロントコントローラは ErrorHandler プラグインと ViewRenderer アクションヘルパープラグインを読み込みます。 これらにより、コントローラ内でのエラー処理やビューのレンダリングがシンプルに行えるようになります。

エラーハンドラを無効にするには、 dispatch() をコールする前に以下のいずれかの方法を使用します。

<?php
// プラグインの登録を解除します
$front->unregisterPlugin('Zend_Controller_Plugin_ErrorHandler');

// あるいは単に無効にします
$front->setParam('noErrorHandler', true);

ビューレンダラを無効にするには、 dispatch() をコールする前に以下のいずれかの方法を使用します。

<?php
// アクションヘルパーをブローカから削除します
Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer');

// あるいは単に無効にします
$front->setParam('noViewRenderer', true);

どちらの場合についても、フロンとコントローラのパラメータを設定する方法のほうが 手っ取り早く高速です。また、この方法なら、設定を変更することも簡単です。

7.3.2. 主要なメソッド

フロントコントローラには、その環境設定用のメソッドがいくつか用意されています。 そのうち、フロントコントローラの機能の鍵となる主要なメソッドは、以下の3つです。

7.3.2.1. getInstance()

getInstance() は、フロントコントローラのインスタンスを取得します。 フロントコントローラはシングルトンパターンを実装しているので、 フロントコントローラのインスタンスを作成する唯一の方法はこのメソッドをコールすることとなります。

<?php
$front = Zend_Controller_Front::getInstance();
?>

7.3.2.2. setControllerDirectory() および addControllerDirectory

setControllerDirectory() は、ディスパッチャアクションコントローラ クラスファイルをどこから探せばよいのかを指定するメソッドです。 単一のパスを指定することもできますし、複数のパスを連想配列で指定することもできます。

いくつか例を示します。

// デフォルトのコントローラディレクトリを設定します
$front->setControllerDirectory('../application/controllers');

// 複数のモジュールのディレクトリを一度に指定します
$front->setControllerDirectory(array(
    'default' => '../application/controllers',
    'blog'    => '../modules/blog/controllers',
    'news'    => '../modules/news/controllers',
));

// 'foo' モジュールのディレクトリを追加します
$front->addControllerDirectory('../modules/foo/controllers', 'foo');
?>
[注意] 注意

addControllerDirectory() でモジュール名を省略すると、default モジュールが指定されたものとみなします。 もしすでに存在する場合は、それを上書きします。

コントローラディレクトリの現在の設定を取得するには getControllerDirectory() を使用します。 これは、モジュールとディレクトリの組を配列で返します。

7.3.2.3. dispatch()

dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) は、フロントコントローラでもっとも重要な仕事を担当します。 オプションで リクエストオブジェクトレスポンスオブジェクト を受け取り、それぞれ独自のオブジェクトを指定することができます。

リクエストオブジェクトやレスポンスオブジェクトを省略すると、 dispatch() は事前にオブジェクトが登録されているかどうかを確認します。 もし登録されていればそれを使用し、登録されていなければデフォルトのオブジェクトを作成して使用します (どちらの場合についても、HTTP リクエスト/レスポンス オブジェクトをデフォルトで使用します)。

同様に、dispatch()ルータディスパッチャ オブジェクトについても登録済みのものがあるかどうかを確認します。 もしあればそれを使用し、なければデフォルトのオブジェクトを作成して使用します。

ディスパッチ処理は、次の三段階に分けられます。

  • ルーティング

  • ディスパッチ

  • レスポンス

ルーティングは一度だけ発生します。これは、dispatch() がコールされた際のリクエストオブジェクトの内容を使用して行います。 ディスパッチは繰り返し行われます。 ひとつのリクエストが複数のアクションを指定している場合や、 コントローラまたはプラグインがリクエストオブジェクトを設定しなおして 別のアクションへディスパッチさせた場合などです。 すべてが終了したら、フロントコントローラはレスポンスを返します。

7.3.2.4. run()

Zend_Controller_Front::run($path) は静的メソッドで、コントローラを含むディレクトリへのパスを指定します。 このメソッドは getInstance() を使用してフロントコントローラのインスタンスを取得し、 setControllerDirectory() を使用してパスを登録し、最後に ディスパッチ します。

run() は、サイト単位の設定などで フロントコントローラのカスタマイズが不要な場合に便利なメソッドです。

<?php
// フロントコントローラを作成してコントローラディレクトリを設定し、
// ディスパッチするまでをいちどでお手軽に行います
Zend_Controller_Front::run('../application/controllers');
?>

7.3.3. 環境へのアクセス用メソッド群

これまでに説明したメソッド以外にもさまざまなアクセス用メソッドが用意されており、 これらを使用してフロンとコントローラの環境にアクセスすることができます。 つまり、フロントコントローラが処理を委譲しているクラスの環境にもアクセスできるということです。

  • resetInstance() は、現在の設定をすべて消去します。 主にテスト目的で使用しますが、 複数のフロントコントローラを連結させたい場合などに使用することもあります。

  • (set|get)DefaultControllerName() で、デフォルトのコントローラとして使用する名前を指定したり (指定しなければ 'index' となります) 現在の設定を取得したりできます。 これらメソッドは、 ディスパッチャ へのプロキシです。

  • (set|get)DefaultActionName() で、デフォルトのアクションとして使用する名前を指定したり (指定しなければ 'index' となります) 現在の設定を取得したりできます。 これらのメソッドは ディスパッチャ へのプロキシです。

  • (set|get)Request() は、ディスパッチ処理で使用する リクエスト クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。 リクエストオブジェクトを指定するときに、クラス名を指定することができます。 この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。

  • (set|get)Router() は、ディスパッチ処理で使用する ルータ クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。 ルータオブジェクトを指定するときに、クラス名を指定することができます。 この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。

    ルータオブジェクトを取得する際には、まずルータが存在するかどうかを調べ、 存在しない場合にはデフォルトのルータ (rewrite ルータ) のインスタンスを作成します。

  • (set|get)BaseUrl() は、リクエストのルーティング時に URL から取り除く 基底 URL を指定したり、現在の値を取得したりします。 この値は、ルーティングの直前にリクエストオブジェクトに渡されます。

  • (set|get)Dispatcher() は、ディスパッチ処理で使用する ディスパッチャ クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。 ディスパッチャオブジェクトを指定するときに、クラス名を指定することができます。 この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。

    ディスパッチャオブジェクトを取得する際には、まずディスパッチャが存在するかどうかを調べ、 存在しない場合にはデフォルトのディスパッチャのインスタンスを作成します。

  • (set|get)Response() は、ディスパッチ処理で使用する レスポンス クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。 レスポンスオブジェクトを指定するときに、クラス名を指定することができます。 この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。

  • (un)registerPlugin() は、 プラグインオブジェクト を登録したり登録を解除したりします。

  • throwExceptions($flag) で、ディスパッチの際に発生した例外をスローするかどうかを切り替えます。 デフォルトでは、例外はスローされず、 レスポンスオブジェクト に保存されます。throwExceptions() をオンにすると、この挙動を変更できます。

    詳細は 項7.12. 「MVC での例外」 を参照ください。

  • returnResponse($flag) は、フロントコントローラが dispatch() からのレスポンスを返す (true) かレスポンスを自動的に発行する (false) かを切り替えます。デフォルトでは、レスポンスは (Zend_Controller_Response_Abstract::sendResponse() によって) 自動的に発行されます。returnResponse() をオンにすると、この挙動を変更できます。 behaviour.

    レスポンスを返すようにする理由としては、 実際に発行する前に例外のチェックを行いたり レスポンスの情報 (ヘッダなど) をログに記録したりなどが考えられます。

7.3.4. フロントコントローラのパラメータ

最初のほうで、フロントコントローラはレジストリとしても使用できると説明しました。 その際に使用するのが "param" 系のメソッド群です。 これらのメソッドを使用すると、任意のデータ (オブジェクトや変数) をフロントコントローラに登録することができます。 登録したデータは、ディスパッチチェイン内のどこででも使用できます。 これらの値は、ルータやディスパッチャそしてアクションコントローラにも渡されます。 各メソッドについて、以下にまとめます。

  • setParam($name, $value) は、 パラメータ $name の値を $value に設定します。

  • setParams(array $params) は、 連想配列を使用して複数のパラメータを一度に設定します。

  • getParam($name) は、 $name で指定した名前のパラメータの値を取得します。

  • getParams() は、 すべてのパラメータの一覧を一度に取得します。

  • clearParams() は、 単一のパラメータ (文字列で指定した場合) か 複数のパラメータ (文字列の配列で指定した場合)、 またはすべてのパラメータ (何も指定しなかった場合) を消去します。

ディスパッチチェイン内で特定の目的で使用するために、 いくつかのパラメータが事前に定義されています。

  • useDefaultControllerAlways は、 ディスパッチできない (モジュール、コントローラ、アクションのいずれかが存在しない) リクエストに対して、 デフォルトモジュールのデフォルトコントローラにディスパッチするよう ディスパッチャ に指示します。デフォルトではこの機能は無効になっています。

    この設定の使用法についての詳細は 項7.12.3. 「MVC で遭遇するであろう例外」 を参照ください。

  • disableOutputBuffering は、 アクションコントローラの出力をバッファリングしないよう ディスパッチャ に指示します。デフォルトでは、 ディスパッチャがいったんすべての出力をキャプチャして、 レスポンスオブジェクトに追加しています。

7.3.5. フロントコントローラのサブクラスの作成

フロントコントローラのサブクラスを作成する際は、 最低限 getInstance() メソッドをオーバーライドしなければなりません。

class My_Controller_Front extends Zend_Controller_Front
{
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
}

getInstance() メソッドをオーバーライドすることで、それ以降の Zend_Controller_Front::getInstance() のコールが Zend_Controller_Front ではなく新しいサブクラスのインスタンスを返すようになります。 これは、デフォルト以外のルータやビューヘルパーを使用する場合などに便利です。

何か新しい機能 (たとえばプラグインの自動ローダーや、 アクションヘルパーのパスの指定方法) を追加したいというのでもない限り、 ふつうはフロントコントローラのサブクラスを作成する必要はありません。 ほかに変更したくなるような箇所としては、 コントローラディレクトリの保存方法や デフォルトルータ/デフォルトディスパッチャを使用するかどうかなどがあるでしょう。