# Объект запроса

## Введение

Объект запроса - это простой "объект значений" (value object), который передается между 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. Он также позволяет обращаться к значениям, содержащимся в суперглобальных массивах, как к своим открытым членам, и управляет текущими базовым URL и URI запроса. Суперглобальные значения не могут устанавливаться в объекте запроса, вместо этого используйте методы setParam/getParam для установки или получения пользовательских параметров.

Суперглобальные данные

Когда получаете доступ к суперглобальным данным через Zend_Controller_Request_Http как к публичным свойствам, то необходимо помнить, что имя свойства (ключ суперглобального массива) сопоставляются с суперглобальными массивами в определенной последовательности: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV.

Отдельные значения из суперглобальных массивов можно также получить через открытые методы. Например, необработанное значение `$_POST['user']` может быть получено через вызов метода `getPost('user')` объекта запроса. Эти методы включают в себя `getQuery()` для получения элементов массива `$_GET` и `getHeader()` для получения заголовков запроса.

Данные GET и POST

Будьте осторожны, когда извлекаете данные из объекта запроса, поскольку они совсем не фильтруются. Маршрутизатор и диспетчер производят проверку на допустимость и фильтрацию данных для использования в своих целях, но оставляют их нетронутыми в объекте запроса.

Извлечение Raw POST данных

Начиная с версии 1.5.0 вы можете также извлекать данные POST в том виде, в котором они присутствуют в теле запроса, используя метод `getRawPost()`. Этот метод возвращает false, если данные POST отсутствуют в теле запроса, иначе - все тело POST.

Этот метод в основном полезен для получения содержимого при разработке RESTful приложений.

Вы можете также устанавливать пользовательские параметры в объекте запроса, используя `setParam()`, и извлекать их после, используя `getParam()`. Маршрутизатор использует этот функционал для установки параметров, обнаруженных в URI запроса, в объекте запроса.

getParam() извлекает не только пользовательские параметры

`getParam()` извлекает значения из нескольких источников. В порядке следования эти источники включают в себя: установленные через метод `setParam()` пользовательские параметры, параметры `GET`, и, наконец, параметры `POST`. Помните об этом, когда извлекаете данные через этот метод.

Если вы хотите извлекать только те параметры, которые установили через `setParam()`, то используйте `getUserParam()`.

Кроме этого, начиная с версии 1.5.0, вы можете ограничивать набор доступных для поиска источников параметров. `setParamSources()` позволяет указывать пустой массив или массив с одним или более значений, это могут быть'_GET' и '_POST' (по умолчанию оба разрешены). Через этот массив задается набор источников параметров, которым можно пользоваться для поиска. Если вы хотите ограничить доступ источником '_GET', то указывайте `setParamSources(array('_GET'))`.

Причуды Apache

Если вы используете обработчик ошибок 404 веб-сервера Apache для передачи приходящих запросов фронт-контроллеру или используете флаг PT с правилами перезаписи, то нужный вам URI будет содержаться в `$_SERVER['REDIRECT_URL']`, а не в `$_SERVER['REQUEST_URI']`. Если вы используете такие установки и получаете неверную маршрутизацию, то должны использовать для своего объекта запроса класс Zend_Controller_Request_Apache404 вместо Zend_Controller_Request_Http, используемого по умолчанию.

    $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 (основа перезаписи) должен быть установлен в `/projects/myapp`. Эта строка будет удаляться из начала пути до того, как будут производиться поиск соответствующего маршрута. Это освобождает от необходимости ее указания в начале каждого маршрута. Маршрут `'user/:username'` будет соответствовать URI вида `http://localhost/projects/myapp/user/martel` и `http://example.com/user/martel`.

Определение URL чувствительно к регистру

Автоматическое определение базового URL чувствительно к регистру, поэтому убедитесь, что ваш URL соответствует имени поддиректории в файловой системе (даже на платформе Windows). Если не соответствует, то будет сгенерировано исключение.

Если базовый URL определяется некорректно, то вы можете заменить его своим базовым путем с помощью метода `setBaseUrl()`, который есть в классах Zend_Http_Request, Zend_Controller_Request_Http и Zend_Controller_Front. Легче всего установить его через Zend_Controller_Front, который в свою очередь установит его в объекте запроса. Пример установки своего базового URL:

    /**
     * Обработка запроса со своим базовым URL через Zend_Controller_Front
     */
    $router     = new Zend_Controller_Router_Rewrite();
    $controller = Zend_Controller_Front::getInstance();
    $controller->setControllerDirectory('./application/controllers')
               ->setRouter($router)
               ->setBaseUrl('/projects/myapp'); // установка базового URL!
    $response   = $controller->dispatch();

### Определение HTTP-метода запроса

`getMethod()` позволяет определить HTTP-метод текущего запроса. Кроме этого, есть набор методов, позволяющий проверить, использовался ли тот или иной HTTP-метод при произведении текущего запроса. Все они возвращают ответ булевого типа:

- `isGet()`

- `isPost()`

- `isPut()`

- `isDelete()`

- `isHead()`

- `isOptions()`

Эти методы могут использоваться в основном для создания т.н. RESTful-архитектуры.

### Определение запросов 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();
    }

Объект запроса является контейнером для переменных запроса. Цепочке контроллеров надо знать только то, как устанавливать и получать контроллер, действие, опциональные параметры и флаг диспетчеризации. По умолчанию объект запроса будет искать в своих параметрах, используя ключи контроллера и действия, для определения текущих контроллера и действия.

Расширяйте этот класс или один из его производных классов, если вам нужен класс запроса, взаимодействующий с определенной средой для получения данных, использующихся в упомянутых выше задачах. Примерами могут быть среда HTTP, среда CLI или PHP-GTK.