第7章 Zend_Controller
前のページ |  | 次のページ

## 第7章 Zend_Controller

## 7.1. 概要

### 7.1.1. 導入

`Zend_Controller` は、モデル - ビュー - コントローラ (MVC) パターンに基づいたウェブサイトを構築するための基本機能を提供します。

`Zend_Controller` は軽量で部品化されており、拡張しやすいように設計されています。 この設計は、柔軟性および利用者に対する自由度を確保するための最低限のものであり、 `Zend_Controller` を使用して構築したシステムは、 ほぼ同じようなコード配置・規約を共有することができます。

`Zend_Controller` の処理の流れは、 いくつかの部品にわかれて実装されています。 これらの部品のすべてを完璧に理解する必要はありませんが、 処理の概要を知っておくことは有用です。

- `Zend_Controller_Front` は、 `Zend_Controller` の処理全体を取りまとめます。 FrontController パターンであるといえます。 サーバから受け取ったすべてのリクエストを `Zend_Controller_Front` が処理し、最終的にリクエストを ActionController (`Zend_Controller_Action`) に委譲します。

- `Zend_Controller_Request_Abstract` はリクエスト環境を表し、コントローラ名やアクション名 そしてリクエストパラメータを設定したり取得したりする機能を提供します。 さらに、アクションが `Zend_Controller_Dispatcher` でディスパッチされたかどうかを追跡する機能もあります。 この抽象リクエストオブジェクトを拡張し、 リクエスト情報をカプセル化します。それによって、 ルータはリクエストの情報を取得して コントローラとアクションを決定できるようになります。

  デフォルトでは `Zend_Controller_Request_Http` が用いられます。これは、HTTP リクエスト環境全体へのアクセス機能を提供します。

- `Zend_Controller_Router_Interface` を使用してルータを定義します。 ルーティングとは、リクエストの内容を調べて、 そのリクエストを処理するコントローラとアクションを決定する処理のことです。 このコントローラとアクション、そしてリクエストパラメータがリクエストオブジェクトに設定され、 `Zend_Controller_Dispatcher_Standard` で処理されます。 ルーティングが発生するのは一度だけ、 つまり最初にリクエストを受け取ってから 最初のコントローラにディスパッチされるまでの間だけです。

  デフォルトのルータは `Zend_Controller_Router_Rewrite` です。

  デフォルトのルータである `Zend_Controller_Router_Rewrite` は、 `Zend_Controller_Request_Http` で指定された URI を受け取ってそれを分解し、コントローラや アクション、そして URL に含まれたパスのパラメータを取得します。 たとえば、`http://localhost/foo/bar/key/value` のような URL の場合は `foo` がコントローラ、 `bar` がアクション、そしてパラメータ `key` の値として `value` を取得します。

  `Zend_Controller_Router_Rewrite` は、任意のパスにマッチさせることもできます。 詳細は 項7.4.3. 「Zend_Controller_Router_Rewrite」 を参照ください。

- `Zend_Controller_Dispatcher_Interface` を使用してディスパッチャを定義します。ディスパッチとは、 コントローラとアクションをリクエストオブジェクトから受け取り、 それを実際のコントローラファイル/クラスとメソッドに対応させる処理のことです。 コントローラやアクションが存在しない場合は、 デフォルトのコントローラやアクションにディスパッチします。

  実際のディスパッチ処理では、 コントローラクラスのインスタンスの作成と そのクラスのアクションメソッドのコールを行います。 ルーティングは一度しか発生しませんが、 それとは異なりディスパッチは繰り返し発生します。 リクエストオブジェクトのディスパッチ状態がリセットされるとループが再開され、 現在リクエストオブジェクトに設定されているアクションがコールされます。 リクエストオブジェクトのディスパッチ状態が (true に) 設定された状態でループが終了すると、処理が終了します。

  デフォルトのディスパッチャは `Zend_Controller_Dispatcher_Standard` です。 これは、CamelCasedClasses 形式の名前の最後に Controller がついたクラスをコントローラとして使用し、 アクションメソッドの名前は camelCasedMethods 形式 (最後に Action をつける) となります。たとえば `SomeFooController::barAction` のような場合、コントローラは `somefoo`、アクションは `bar` となります。

- `Zend_Controller_Action` はコントローラの基底コンポーネントです。 各コントローラはこの `Zend_Controller_Action` クラスを継承して作成します。このクラスではアクションメソッドを定義します。

- `Zend_Controller_Response_Abstract` は基底レスポンスクラスで、アクションコントローラからの応答内容を収集し、 それをレスポンスとして返します。これはヘッダと本文の両方を収集します。 また、`__toString()` を実装しているので、 それを直接出力してヘッダと本文を一度に送信することができます。

  デフォルトのレスポンスクラスは `Zend_Controller_Response_Http` で、 これは HTTP 環境での使用に適しています。

`Zend_Controller` の処理の流れは比較的シンプルです。 `Zend_Controller_Front` がリクエストを受け取り、 `Zend_Controller_Router_Rewrite` をコールして、 配送先となるコントローラ (そしてコントローラ内のアクション) を決定します。`Zend_Controller_Router_Rewrite` は URI を分解し、リクエストからコントローラ名とアクション名を取得します。 その後、`Zend_Controller_Front` はディスパッチループに突入します。 まず `Zend_Controller_Dispatcher_Standard` をコールしてそこにリクエストを渡し、 リクエストで指定されたコントローラとアクションを取得します (あるいはデフォルトを使用します)。 コントローラが終了すると、処理は `Zend_Controller_Front` に戻ります。リクエストのディスパッチ状態がリセットされ、 別のコントローラをディスパッチするように指示された場合は、 ループが続けられて次の配送処理が行われます。 それ以外の場合は、処理がそこで終了します。それ以外の場合は、 処理が終了します。

### 7.1.2. リクエストオブジェクト

リクエストオブジェクトとは `Zend_Controller_Front` とルータ、 ディスパッチャそしてコントローラクラスの間でやり取りされる単純なバリューオブジェクトです。 これはコントローラ、アクションそして環境 (HTTP、CLI、PHP-GTK など) に応じたその他のパラメータの内容をまとめたものです。

- コントローラ名へのアクセスは `getControllerName()` および `setControllerName()` によって行います。

- コントローラ内からコールされるアクションの名前へのアクセスは `getActionName()` および `setActionName()` によって行います。

- アクションに渡されるパラメータは キー/値 の組み合わせからなる連想配列で、 `getParams()` および `setParams()` によってアクセスします。 あるいは、その個々のデータには `getParam()` および `setParam()` でアクセスします。

リクエストの形式によっては、それ以外のメソッドも使用可能です。 たとえば、デフォルトのリクエストで使用される `Zend_Controller_Request_Http` では、リクエスト URI やパス情報、$_GET や $_POST パラメータを取得するメソッドなどがあります。

リクエストオブジェクトはフロントコントローラに渡されます。 もしリクエストオブジェクトがなかった場合は、 ディスパッチ処理の最初 (ルーティングが発生する前) にインスタンスが作成されます。これは、 ディスパッチチェインのすべてのオブジェクトに渡されていきます。

さらに、リクエストオブジェクトはテストの際にも有用です。 開発者がリクエストを作成し、コントローラやアクション、 パラメータや URI などを指定してそれをフロントコントローラに渡すことで、 アプリケーションの流れをテストすることができます。 レスポンスオブジェクトと組み合わせて使用すると、 MVC アプリケーションの精密で正確な単体テストが可能となります。

### 7.1.3. ルーティング処理

はじめてのコントローラを作り始める前に、ルーティング処理が `Zend_Controller_Router_Rewrite` でどのように実装されているのかを知る必要があるでしょう。 処理手順として、一度だけ発生するルーティングと繰り返し発生するディスパッチがあることを覚えておきましょう。

`Zend_Controller_Front` は `Zend_Controller_Router_Rewrite` (あるいは別に登録されたルータ) をコールし、 URI をコントローラとアクションに対応させます。 `Zend_Controller_Router` は URI を受け取り、 チェイン内のルータオブジェクトに渡します。 デフォルトでは、`Zend_Controller_Router_Route_Module` を使用して入力 URL のマッチを行います。ルータオブジェクトは URL を分解し、コントローラとアクション、そしてパスに含まれた URL パラメータを取得します。そしてルータがそれらをリクエストオブジェクトに格納します。

`Zend_Controller_Router_Route_Module` は、 非常にシンプルな対応ルールでコントローラ名とアクション名を取得します。

    http://framework.zend.com/controller/action/

上の例で、最初の部分が常にコントローラの名前となり、 二番目の部分が常にアクションの名前となります。

オプションで、コントローラに渡すパラメータを URI に含めることができます。 これは キー/値 の組み合わせの形式になります。

    http://framework.zend.com/controller/action/key1/value1/

コントローラやアクションが URI パスに含まれない場合は、 `Zend_Controller_Dispatcher_Standard` はリクエストオブジェクトのパラメータから値を取得しようとします。 それも見つからなかった場合はデフォルト値を使用します。 デフォルト値は、コントローラもアクションも "`index`" となります。以下に例を示します。

    http://framework.zend.com/roadmap/future/
    コントローラ: roadmap
    アクション  : future

    http://framework.zend.com/roadmap/
    コントローラ: roadmap
    アクション  : index

    http://framework.zend.com/
    コントローラ: index
    アクション  : index

| 柔軟性
より柔軟な機能を使用したい場合は、 項7.4.3. 「Zend_Controller_Router_Rewrite」 を調べてみましょう。

コントローラの名前、コントローラ内のアクションの名前、 そしてオプションのパラメータの内容が、 リクエストオブジェクトにまとめられます。 `Zend_Controller_Front` がディスパッチループに入ると、 リクエストオブジェクトが `Zend_Controller_Dispatcher_Standard` に渡されます。

### 7.1.4. ディスパッチ処理

ディスパッチ処理は、リクエストオブジェクトを受け取り、 そこに含まれる情報 (コントローラ名、アクション名およびオプションのパラメータ) を展開し、コントローラのインスタンスを作成してそのコントローラのアクションをコールします。 コントローラやアクションが見つからない場合は、 デフォルト値を使用します。`Zend_Controller_Dispatcher_Standard` では、コントローラとアクションのデフォルトはどちらも `index` です。しかし、 `setDefaultController()` メソッドや `setDefaultAction()` メソッドでこれらを変更することもできます。

ディスパッチ処理が発生するのは、フロントコントローラでのループの内部です。 ディスパッチ処理を行う前に、フロントコントローラはルーティングを行い、 ユーザが指定したコントローラとアクション、そして追加のパラメータを取得します。 それからディスパッチループに入り、リクエストを配送します。

ループ内では、まず最初にリクエストオブジェクトのフラグを設定します。 このフラグは、アクションがディスパッチされたことを示すものです。 アクション内や pre/postDispatch プラグインでこのフラグをリセットすると、 ディスパッチループがそのまま継続され、もう一度リクエストを処理しようとします。 リクエスト内のコントローラやアクションを変更してフラグをリセットすることで、 さまざまなリクエストを続けて実行させることができます。

このようなディスパッチ処理を制御する アクションコントローラのメソッドが `_forward()` です。 このメソッドを pre/postDispatch() やアクションメソッドでコールし、 コントローラやアクション、 そして新しいアクションに送りたい追加のパラメータを指定します。

    public function myAction()
    {
        // 何かの処理をして...
        // 現在のモジュール内の別のアクション FooController::barAction() に転送します
        $this->_forward('bar', 'foo', null, array('baz' => 'bogus'));
    }

### 7.1.5. レスポンスオブジェクト

レスポンスオブジェクトは、リクエストオブジェクトと対になるものです。 その目的は、コンテンツやヘッダを収集し、それを返すことです。 さらに、フロントコントローラで捕捉した例外はすべてレスポンスオブジェクトに渡されます。 これにより、例外の処理がやりやすくなります。 この挙動を変更するには `Zend_Controller_Front::throwExceptions(true)` を設定します。

    $front->throwExceptions(true);

ヘッダを含むレスポンス出力を送信するには、 `sendOutput()` を使用します。

    $response->sendOutput();

開発者は、アクションコントローラの中でレスポンスオブジェクトを使用しなければなりません。 出力を直接レンダリングしたり直接ヘッダを送信したりするのではなく、 それらをレスポンスオブジェクトに格納するようにします。

    // アクションコントローラのアクション内で、
    // ヘッダを設定します
    $this->getResponse()
        ->setHeader('Content-Type', 'text/html')
        ->appendBody($content);

こうすることで、すべてのヘッダを一度に送信し、 その後でコンテンツを表示することができます。

アプリケーションで例外が発生したかどうかを調べるには、 レスポンスオブジェクトの `isException()` フラグを調べます。例外を取得するには `getException()` を使用します。さらに、独自のレスポンスオブジェクトを作成して、 エラーページへのリダイレクトや例外メッセージのログ出力、 例外をわかりやすく表示する (開発用) などを行うことができます。

レスポンスオブジェクトは、フロントコントローラの dispatch() から受け取ることになります。あるいは、 出力のレンダリングを行わない状態のレスポンスオブジェクトを フロントコントローラから受け取ることもできます。

    // dispatch の後に取得します
    $front->dispatch();
    $response = $front->getResponse();
    if ($response->isException()) {
        // ログへの記録、メール送信など...
    }

    // あるいは、フロントコントローラの dispatch() の返り値を使用します
    $front->returnResponse(true);
    $response = $front->dispatch();

    // 何かの処理...

    // 最後に結果を表示します
    $response->sendResponse();

デフォルトでは、例外メッセージは表示されません。 この挙動をオーバーライドするには `renderExceptions()` メソッドを使用するか、あるいは上で示したようにフロントコントローラで throwExceptions() を有効にします。

    $response->renderExceptions(true);
    $front->dispatch($request, $response);

    // あるいは
    $front->returnResponse(true);
    $response = $front->dispatch();
    $response->renderExceptions();
    $response->sendOutput();

    // あるいは
    $front->throwExceptions(true);
    $front->dispatch();

前のページ |  | 次のページ
6.4. Zend_Console_Getopt の設定 | ホーム | 7.2. さあ、はじめましょう