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

## 導入

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

- モジュール名にアクセスするには `getModuleName()` および `setModuleName()` を使用します。

- コントローラ名にアクセスするには `getControllerName()` および `setControllerName()` を使用します。

- コントローラ内でコールするアクションの名前にアクセスするには `getActionName()` および `setActionName()` を使用します。

- アクションからアクセスできるパラメータは キー/値 の組み合わせの連想配列となります。これらを取得するには `getParams()` を、そして設定するには `setParams()` を使用します。各パラメータを個別に扱うには `getParam()` および `setParam()` を使用します。

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

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

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

## HTTP リクエスト

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

`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')` をコールします。同様に、 `$_GET` 要素の場合は `getQuery()`、 リクエストヘッダの場合は `getHeader()` を使用します。

#### GET および POST データ

リクエストオブジェクトのデータを扱う際には注意しましょう。 これらのデータは、一切フィルタリングを行っていません。 ルータやディスパッチャのほうで適切な検証とフィルタリングを行うので、 リクエストオブジェクト内のデータはそのままにしておきましょう。

#### 生の POST データの取得

1.5.0 以降では、生の投稿データを `getRawBody()` メソッドで取得することができます。 このメソッドは、データが送信されていない場合は `FALSE` を返します。 送信されている場合は、投稿内容の本文全体を返します。

これは、RESTful な MVC アプリケーションを開発するにあたって非常に有用です。

ユーザパラメータをリクエストオブジェクトに設定するには `setParam()` を、後でそれを取得するには `getParam()` を使用します。 ルータは、リクエスト URI にマッチしたパラメータを リクエストオブジェクトに設定する際にこの機能を使用します。

#### getParam() でのユーザパラメータ以外の取得

`getParam()` は、実際にはユーザパラメータ以外のところからも情報を取得しています。 優先順位の高い順に並べると、まず最初は `setParam()` で設定したパラメータ、それから `GET` パラメータ、 `POST` パラメータの順になります。 このメソッドを使用する際には、この点に注意しましょう。

`setParam()` で設定したパラメータからだけ取得したい場合は、 `getUserParam()` を使用します。

さらに、1.5.0 以降では どのパラメータから検索するかを制限することができます。 `setParamSources()` に空の配列あるいは 値 '_GET' や '_POST' を含む配列を指定して使用します (デフォルトでは両方が指定されています)。'_GET' からのみに制限したい場合は `setParamSources(array('_GET'))` とします。

#### Apache のおかしな挙動

Apache の 404 ハンドラを使用して リクエストをフロントコントローラに渡したり、 PT フラグを rewrite ルールで使用したりする場合は、 必要な URI 情報が含まれるのが `$_SERVER['REQUEST_URI']` ではなく `$_SERVER['REDIRECT_URL']` であることに注意しましょう。 この設定を使用して無効なルーティングを取得したい場合は、 デフォルトの Http クラスではなく `Zend_Controller_Request_Apache404` クラスを使用してリクエストオブジェクトを作成しなければなりません。

    $request = new Zend_Controller_Request_Apache404();
    $front->setRequest($request);

このクラスは `Zend_Controller_Request_Http` クラスを継承したもので、リクエスト URI を自動で検出できるように変更しています。 これは、単純にもとのクラスと差し替えて使用できます。

### ベース 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 マシンであっても同様です)。大文字小文字が一致しなかった場合は、 例外が発生します。

ベース 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();

### リクエストメソッドの判定

`getMethod()` では、 現在のリソースへのリクエストの際に使用した HTTP メソッドを判定することができます。 さらに、指定した型のリクエストであったかどうかを判定するための メソッドも用意されています。

- `isGet()`

- `isPost()`

- `isPut()`

- `isDelete()`

- `isHead()`

- `isOptions()`

これらの主な使用法は、RESTfult な MVC アーキテクチャを作成することです。

### AJAX リクエストの検出

`Zend_Controller_Request_Http` には、 AJAX リクエストを検出するための基本的なメソッド `isXmlHttpRequest()` が用意されています。 このメソッドは、HTTP リクエストヘッダ X-Requested-With に 'XMLHttpRequest' という値が設定されているかどうかを調べ、 設定されている場合に `TRUE` を返します。

現時点では、次の JS ライブラリがデフォルトでこのヘッダを渡すようです。

- Prototype/Scriptaculous (その他 Prototype 系のライブラリ)

- Yahoo! UI Library

- jQuery

- MochiKit

大半の AJAX ライブラリは、独自の HTTP リクエストヘッダを送信することができます。 ご利用のライブラリがこのヘッダを送信していない場合は、 自分でこのヘッダを追加することで `isXmlHttpRequest()` メソッドの動作を期待通りにすることができます。

## リクエストオブジェクトのサブクラスの作成

すべてのリクエストオブジェクトクラスは、抽象クラス `Zend_Controller_Request_Abstract` を継承しています。 このクラスでは、次のようなメソッドを定義しています。

    abstract class Zend_Controller_Request_Abstract
    {
        /**
         * @return string
         */
        public function getControllerName();

        /**
         * @param string $value
         * @return self
         */
        public function setControllerName($value);

        /**
         * @return string
         */
        public function getActionName();

        /**
         * @param string $value
         * @return self
         */
        public function setActionName($value);

        /**
         * @return string
         */
        public function getControllerKey();

        /**
         * @param string $key
         * @return self
         */
        public function setControllerKey($key);

        /**
         * @return string
         */
        public function getActionKey();

        /**
         * @param string $key
         * @return self
         */
        public function setActionKey($key);

        /**
         * @param string $key
         * @return mixed
         */
        public function getParam($key);

        /**
         * @param string $key
         * @param mixed $value
         * @return self
         */
        public function setParam($key, $value);

        /**
         * @return array
         */
         public function getParams();

        /**
         * @param array $array
         * @return self
         */
        public function setParams(array $array);

        /**
         * @param boolean $flag
         * @return self
         */
        public function setDispatched($flag = true);

        /**
         * @return boolean
         */
        public function isDispatched();
    }

リクエストオブジェクトは、リクエスト環境のコンテナとなります。 コントローラチェインが知っておくべきことは、 コントローラやアクション、オプションパラメータ、ディスパッチ状況 を取得したり設定したりする方法だけです。 デフォルトでは、リクエストオブジェクトが コントローラおよびアクションを決定する際には キー controller あるいは action を使用します。

このクラスかその派生クラスのいずれかを継承したクラスを作成することで、 上で説明した作業を独自のものに変更したクラスを作成することができます。 例としては、たとえば HTTP 環境用 のクラスや CLI 環境用、PHP-GTK 環境用のクラスがあります。