7.4. 提供されるサブクラス群
前のページ | 第7章 Zend_Controller | 次のページ

## 7.4. 提供されるサブクラス群

### 7.4.1. 導入

Zend Framework では、デフォルトで提供されるクラス以外の選択肢も用意しています。 たとえばリクエストオブジェクト、ルータ、 そしてレスポンスオブジェクトなどについて別の選択肢があります。

### 7.4.2. Zend_Controller_Request_Http

#### 7.4.2.1. 導入

`Zend_Controller_Request_Http` は、HTTP 環境で使用するリクエストオブジェクトです `Zend_Controller_Request_Http` はデフォルトのリクエストクラスであり、 `Zend_Controller_Dispatcher` で用いられます。

#### 7.4.2.2. リクエストデータへのアクセス

`Zend_Controller_Request_Http` は、関連する値へのアクセスをカプセル化します。 たとえばコントローラやアクションルータの変数のキー名や値、 URI からパースした追加のパラメータの値などにアクセスできます。 `Zend_Controller_Request_Http` のプロキシとして動作することで、 スーパーグローバルの値にパブリックメンバとしてアクセスしたり、 現在のベース URL やリクエスト URI を管理することもできます。 スーパーグローバルの値はリクエストオブジェクトに設定することはできません。 そのかわりに setParam/getParam メソッドを使用して、 パラメータを設定あるいは取得します。

| スーバーグローバルデータ
`Zend_Controller_Request_Http` のパブリックプロパティを使用して スーパーグローバルデータにアクセスする際に注意すべき点は、 プロパティ名 (スーバーグローバル配列のキー) は以下の優先順位でマッチするということです。 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV.

特定のスーパーグローバルにアクセスするには、 パブリックメソッドを使用する方法もあります。たとえば、 `$_POST['user']` の値を取得するには、リクエストオブジェクト上で `getPost('user')` をコールします。

#### 7.4.2.3. ベース URL およびサブディレクトリ

`Zend_Controller_Request_Http` は、 サブディレクトリで Zend_Controller_Router_Rewrite を使用することができます。 Zend_Controller_Request_Http は自動的にベース URL を検出し、 それを適切に設定します。

たとえば、`index.php` をウェブサーバのサブディレクトリ `/projects/myapp/index.php` においた場合は、ベース URL (rewrite base) は `/projects/myapp` にしなければなりません。 マッチするルートを見つける前に、この文字列がパスの先頭から取り除かれます。 これにより、すべてのルートに余計な文字を追加する必要がなくなります。 ルート `'user/:username'` は、 `http://localhost/projects/myapp/user/martel` および `http://example.com/user/martel` の両方にマッチするようになります。

| URL の検出は大文字小文字を区別します
自動的なベース URL の検出処理は大文字小文字を区別します。そのため、 URL とファイルシステムのサブディレクトリ名が確実に一致する必要があります (たとえ Windows マシンであっても同様です)。大文字小文字が一致しなかった場合は noRoute アクションがコールされます。

ベース URL の検出に失敗する場合は、 `Zend_Controller_Request_Http` クラス、あるいは `Zend_Controller_Front` クラスの `setBaseUrl()` メソッドを使用して ベースパスを上書き指定することができます。 一番簡単な方法は `Zend_Controller_Front` で設定することです。 この設定はリクエストオブジェクトに引き継がれます。 独自のベース URL を設定する例を示します。

    /**
     * Zend_Controller_Front で独自のベース URL を指定することによるリクエストのディスパッチ
     */
    $router     = new Zend_Controller_Router_Rewrite();
    $controller = Zend_Controller_Front::getInstance();
    $controller->setControllerDirectory('./application/controllers')
               ->setRouter($router)
               ->setBaseUrl('/projects/myapp'); // ベース URL を指定します!
    $response   = $controller->dispatch();

### 7.4.3. Zend_Controller_Router_Rewrite

#### 7.4.3.1. 導入

`Zend_Controller_Router_Rewrite` は、標準のルータです。 ルーティングとは、URI (ベース URL から取得した URI の一部) を展開し、どのコントローラのどのアクションが リクエストを処理するのかを決める処理のことです。 コントローラの値やアクション、そしてその他のパラメータが `Zend_Controller_Request_Http` オブジェクトにまとめられます。 このオブジェクトを処理するのが `Zend_Controller_Dispatcher_Standard` です。 ルーティングが行われるのは一度だけ、すなわちリクエストを最初に受け取ってから 最初のコントローラに処理が渡される際だけです。

`Zend_Controller_Router_Rewrite` は、mod_rewrite 風の機能を PHP だけで実現できるように設計されています。 この処理は Ruby on Rails のルーティングを多少参考にしており、 ウェブサーバの URL 書き換えに関する前提知識を必要としません。 以下の単純な mod_rewrite ルール (のいずれか) で動作するように設計されています。

    RewriteEngine on
    RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

あるいは

    RewriteEngine on
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1

Rewrite ルータを IIS ウェブサーバで使用するには Isapi_Rewrite を Isapi 拡張モジュールとしてインストールします。そして次のようなルールを記述します。

    RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css)$)[\w\%]*$)? /index.php [I]

| IIS Isapi_Rewrite
IIS を使用すると、`$_SERVER['REQUEST_URI']` が存在しないか空の文字列に設定されます。このような場合、 `Zend_Controller_Request_Http` は `$_SERVER['HTTP_X_REWRITE_URL']` の値を使用します。これは Isapi_Rewrite 拡張モジュールが設定します。

Lighttpd の場合は、次のようなルールを使用します。

    url.rewrite-once = ( ".*\.(js|ico|gif|jpg|png|css)$" => "$0", "" => "/index.php")

#### 7.4.3.2. ルータの使用法

Rewrite ルータを適切に使用するには、まずそのインスタンスを作成し、 次にユーザ定義のルーティングを追加し、それをコントローラに注入しなければなりません。 以下にコードの例を示します。

    /* ルータを作成します */

    $router = $ctrl->getRouter(); // デフォルトで rewrite ルータを返します
    $router->addRoute(
    	'user',
    	new Zend_Controller_Router_Route('user/:username', array('controller' => 'user', 'action' => 'info'))
    );

#### 7.4.3.3. 基本的なルーティング

RewriteRouter で最も重要なのが、ユーザ定義のルーティングです。 これは、RewriteRouter の addRoute メソッドをコールして作成します。 このメソッドに、`Zend_Controller_Router_Route` の新しいインスタンスを渡します。

    $router->addRoute('user', new Zend_Controller_Router_Route('user/:username'));

最初のパラメータがこのルートの名前です。現在は多少冗長性が残ってしまっていますが、 将来は、URL ビューヘルパーの中でこれを使用し、ビュー内で簡単に URL を生成できるようになる予定です。 ここで定義したルートを使用する方法も知っておく必要があるでしょう。 事前に定義したルートを取得するには、RewriteRouter の getRoute メソッドを使用します。二番目のパラメータは、 `Zend_Controller_Router_Route` のインスタンスです。

`Zend_Controller_Router_Route` のコンストラクタの最初のパラメータは、 その URL に関連付けるルートです。 例えば、上の例で示したルートは `http://example.com/user/martel` に対応します。ルート内のコロンは URL 変数を意味します。ルーティングに成功すると、 これらの変数は Zend_Controller_Request に注入されます。 その後は Zend_Controller_Request::getParam や Zend_Controller_Action::_getParam メソッドでアクセスできるようになります。 今回の例では、username という名前のパラメータに 'martel' という値が設定されます。

| 定義の順番
一番最後にマッチしたルートが適用されるので、 汎用的なルートは最初に定義するようにしましょう。

| 許可される文字
現在の実装では、変数の識別子としてスラッシュ (/) 以外のあらゆる文字を使用可能ですが、できるだけ PHP の変数で使用可能な範囲の文字のみを使用することを強く推奨します。 この実装は将来変更される予定ですので、(PHP の変数で使用できない文字を用いていると) バグを引き起こす可能性があります。

ルートで使用される変数のうち、':controller' および ':action' のふたつは特別な扱いとなります。これらの特殊変数は、URL から コントローラとアクションを決定するために使用されます。 ':action' 変数は、そのルートあるいはデフォルトパラメータとして 常に定義されていなければなりません。 ':controller' 変数がもし定義されていない場合は、デフォルト値として IndexController が使用されます。

| 特殊変数
これらの特殊変数の名前を変更することもできます。その場合は `Zend_Controller_Request_Http` の setControllerKey メソッドや setActionKey メソッドを使用します。

    $router->addRoute(
        'user', new Zend_Controller_Router_Route(':controller/:action')
    );

このルートが定義されているときにブラウザで 'http://example.com/news/latest' を選択すると、 `Zend_Controller_Dispatcher` は NewsController クラスの latestAction を起動します。

#### 7.4.3.4. 変数のデフォルト値

ルートの中の変数には、すべてデフォルト値を設定することができます。 デフォルト値を設定するには、`Zend_Controller_Router_Route` のコンストラクタの二番目のパラメータを使用します。 このパラメータは配列形式となります。配列のキーに変数名、 そのキーに対応する値としてデフォルト値を設定します。

    $router->addRoute(
        'archive', new Zend_Controller_Router_Route('archive/:year', array('year' => 2006))
    );

ちょっとわかりにくいかもしれませんが、このルートは例えば 'http://example.com/archive/2005' および 'http://example.com/archive' にマッチします。後者の場合、変数 year の値は 2006 となります。

上の例は、単に year 変数の内容をリクエストに注入するだけのものです。 コントローラやアクションを設定していないので、ルーティングは行われません。 この例が使い物になるようにするには、 コントローラとアクションのデフォルト値を設定しなければなりません。

    $router->addRoute(
        'archive',
        new Zend_Controller_Router_Route('archive/:year', array('year' => 2006, 'controller' => 'archive', 'action' => 'show')
    );

このルートは、ArchiveController の showAction を実行します。

#### 7.4.3.5. 変数の制限

`Zend_Controller_Router_Route` に三番目のパラメータを追加し、 変数に関する制限事項を設定することができます。 この制限は、正規表現で設定します。

    $router->addRoute(
        'archive',
        new Zend_Controller_Router_Route('archive/:year', array('year' => 2006), array('year' => '\d+'))
    );

| ルートのマッチング
Ruby on Rails とは異なり、ZF の RewriteRouter は 三番目のパラメータの制限を満たさない場合にもルートにマッチし、 デフォルト値を使用するようになっています。 そのため、URL 'http://example.com/archive/test' は上のルートにマッチし、 year は 2006 に設定されます。この機能は将来変更される予定で、 このマニュアルを書いている時点ではまだ議論中です。

#### 7.4.3.6. ベース URL およびサブディレクトリ

Rewrite ルータはサブディレクトリ内でも使用可能です。 ベース URL の自動検出が `Zend_Controller_Request_Http` によって行われます。

ベース URL の検出に失敗する場合は、 `Zend_Controller_Request_Http` のメソッド `setBaseUrl()` を使用してベースパスを上書き指定することができます (項7.4.2.3. 「ベース URL およびサブディレクトリ」 を参照ください)。

#### 7.4.3.7. デフォルトのルート

Zend_Controller_Router_Rewrite では、デフォルトのルートがひとつ事前に定義されています。 これは `'controller/action'` 形式の URI にマッチします。 さらに、モジュール名を最初のパス要素として指定することができます。これにより、 `'module/controller/action` 形式の URI が使用できます。 また、URI に追加されたパラメータにもデフォルトでマッチします。

ルートがどのようにマッチするのか、例を見てみましょう。

    // 以下のようになっているものとします
    // $ctrl->setControllerDirectory(array(
    //     'default' => '/path/to/default/controllers',
    //     'news'    => '/path/to/blog/controllers',
    //     'blog'    => '/path/to/blog/controllers'
    // ));

    モジュールのみ:
    http://example/news
        module == news

    無効なモジュールとコントローラとの対応:
    http://example/foo
        controller == foo

    モジュール + コントローラ:
    http://example/blog/archive
        module     == blog
        controller == archive

    モジュール + コントローラ + アクション:
    http://example/blog/archive/list
        module     == blog
        controller == archive
        action     == list

    モジュール + コントローラ + アクション + パラメータ:
    http://example/blog/archive/list/sort/alpha/date/desc
        module     == blog
        controller == archive
        action     == list
        sort       == alpha
        date       == desc

デフォルトのルータは、 `Zend_Controller_Router_Route_Module` オブジェクトに何も設定せずに作成したインスタンスです。

    // ルータ v1 との互換性のためのルート
    $compat = new Zend_Controller_Router_Route_Module();
    $this->addRoute('default', $compat);

| マッチする URI
`Zend_Controller_Router_Rewrite` は、過去との互換性を考慮して設定されています。 `controller/action` 形式の URI にパラメータが付加されたパターンにも自動的にマッチします。 デフォルト値や必須値を持っている限り、 パラメータを付加したからといって新しいルートを追加する必要はありません。 これらの追加パラメータにアクセスするには `Zend_Controller_Action::_getParam()` メソッドを使用します。

デフォルトのルートを使用したくない場合は、 `removeDefaultRoutes()` で削除します。

    // 互換性のためのデフォルトルートを削除します
    $router->removeDefaultRoutes();

#### 7.4.3.8. 静的なルート

これまでの例では、すべて動的なルートを使用していました。 つまり、特定のパターンにマッチするものについてのルートです。 しかし、時には特定のルートを固定してしまい、 わざわざ正規表現エンジンを動かしたくない場合もあるでしょう。 そんなときには静的なルートを使用します。

    $loginRoute = new Zend_Controller_Router_Route_Static('login', array('controller' => 'login', 'action' => 'form'));
    $router->addRoute('login', $static);

#### 7.4.3.9. RewriteRouter での Zend_Config の使用法

新しいルートを追加する際に、 いちいちコードを書き換えるのではなく設定ファイルの変更で対応できると便利でしょう。 そんなときには `addConfig()` メソッドを使用します。基本的な使用法は、 まず Zend_Config 互換の設定を作成し、それをコードに読み込み、 そして RewriteRouter に渡すことです。

    /**
     * サンプルの INI ファイル
     * routes.archive.route = "archive/:year/*"
     * routes.archive.defaults.controller = archive
     * routes.archive.defaults.action = show
     * routes.archive.defaults.year = 2000
     * routes.archive.reqs.year = "\d+"
     *
     * routes.news.type = "Zend_Controller_Router_Route_Static"
     * routes.news.route = "news"
     * routes.news.defaults.controller = "news"
     * routes.news.defaults.action = "list"
     */
    $config = new Zend_Config_Ini($file);
    $router = new Zend_Controller_Router_Rewrite();
    $router->addConfig($config, 'routes');

上の例では、INI ファイルの 'routes' セクションを使用してルートを決めるよう、 ルータに指定しています。このセクションの第一レベルのキーがルート名に対応します。 上の例だと 'archive' と 'news' がこれにあたります。 ルートの各エントリには、最低限 'route' エントリとひとつ以上の 'defaults' エントリが必要となります。また、オプションでひとつ以上の 'reqs' ('required' の略) も指定できます。ここで指定したものが、それぞれ `Zend_Controller_Router_Route_Interface` オブジェクトに対する引数となります。オプションのキー 'type' を使用すると、 特定のルートで使用するルートクラスの型を指定できます。デフォルトでは、これは `Zend_Controller_Router_Route` となります。上の例では、 'news' ルートで `Zend_Controller_Router_Route_Static` を使用するようにしています。

### 7.4.4. Zend_Controller_Response_Http

`Zend_Controller_Response_Http` は、 HTTP 環境での使用に適したレスポンスオブジェクトです。 ヘッダの設定/取得/消去の機能があります。また、 `__toString()` メソッドを使用して、 レスポンス本体の前に全ヘッダを一括送信することもできます。

`setHeader()` は、二つの引数を受け取ります。 最初がヘッダの型で、次がヘッダの値です。三番目のオプションのパラメータを true にすると、同じ型の既存のヘッダを強制的に上書きします。

### 7.4.5. Zend_Controller_Response_Cli

`Zend_Controller_Response_Cli` は、 CLI 環境での使用に適したレスポンスオブジェクトです。 ヘッダの処理などの機能は持たず、 `__toString()` が起動された際には単純に本文のみを返します。

前のページ | 上に戻る | 次のページ
7.3. サブクラス化 | ホーム | 7.5. アクションコントローラ