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

5.4.1. 導入

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

5.4.2. Zend_Controller_Request_Http

5.4.2.1. 導入

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

5.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') をコールします。

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

Zend_Controller_Request_Http は、 サブディレクトリで Zend_Controller_RewriteRouter を使用することができます。 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_RewriteRouter();
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./application/controllers')
           ->setRouter($router)
           ->setBaseUrl('/projects/myapp'); // ベース URL を指定します!
$response   = $controller->dispatch();

5.4.3. Zend_Controller_RewriteRouter

5.4.3.1. 導入

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

Zend_Controller_RewriteRouter は、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 

RewriteRouter は 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")

5.4.3.2. ルータの使用法

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

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

$router = new Zend_Controller_RewriteRouter();
$router->addRoute(
	'user',
	new Zend_Controller_Router_Route('user/:username', array('controller' => 'user', 'action' => 'info'))
);

/* それをコントローラに設定します */

$ctrl = Zend_Controller_Front::getInstance();
$ctrl->setRouter($router);

5.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 を起動します。

5.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 を実行します。

5.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 に設定されます。この機能は将来変更される予定で、 このマニュアルを書いている時点ではまだ議論中です。

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

もとのルータとは異なり、現在の RewriteRouter はサブディレクトリ内でも使用可能です。 もとのルータの setRewriteBase() メソッドは、現在は使用できなくなっています。 そのかわりに、ベース URL の自動検出が Zend_Controller_Request_Http によって行われます。

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

5.4.3.7. デフォルトのルート

Zend_Controller_RewriteRouter では、デフォルトのルートがひとつ事前に定義されています。 このルートは、以前のバージョンのルータとの互換性を保つために提供されています。 これは 'controller/action' 形式の URI にマッチします。 また、URI に追加されたパラメータにもマッチします。設定内容は以下のとおりです。

// ルータ v1 との互換性のためのルート
$compat = new Zend_Controller_Router_Route(':controller/:action/*', array('controller' => 'index', 'action' => 'index'));
$this->addRoute('default', $compat);
[注意] マッチする URI

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

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

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

5.4.3.8. 静的なルート

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

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

5.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_StaticRoute"
 * routes.news.route = "news"
 * routes.news.defaults.controller = "news"
 * routes.news.defaults.action = "list"
 */
$config = new Zend_Config_Ini($file);
$router = new Zend_Controller_RewriteRouter();
$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_StaticRoute を使用するようにしています。

5.4.4. Zend_Controller_Response_Http

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

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

5.4.5. Zend_Controller_Response_Cli

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