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

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

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

    $router     = new Zend_Controller_Router_Rewrite();
    $controller = Zend_Controller_Front::getInstance();
    $controller->setControllerDirectory('./application/controllers')
               ->setRouter($router)
               ->setBaseUrl('/projects/myapp'); // set the base url!
    $response   = $controller->dispatch();

### 7.4.3. Zend_Controller_Router_Rewrite

#### 7.4.3.1. Введение

`Zend_Controller_Router_Rewrite` является стандартным маршрутизатором фреймворка. Маршрутизация является процессом принятия конечной точки URI (той части URI, которая идет после базового URL) и ее разложения на параметры для определения того, какой контроллер и какое действие этого контроллера должны получить запрос. Значения контроллера, действия и необязательных параметров упаковывается в объект `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 Router может также использоваться с веб-сервером 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, нужно инстанцировать его, добавить маршруты и установить его в контроллере. Следующий код демонстрирует эту процедуру:

    /* Создание маршрутизатора */

    // возвращает используемый по умолчанию маршрутизатор
    $router = $ctrl->getRouter();

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

#### 7.4.3.3. Основные маршруты

Сущностью RewriteRouter является определение пользовательских маршрутов. Маршруты создаются вызовом метода `addRoute()` и передачей ему нового экземпляра `Zend_Controller_Router_Route`:

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

Первым параметром является имя маршрута. Сейчас он является избыточным, но в будущем будет использоваться в вспомогательном классе вида (view) для легкой генерации URL в ваших видах. Если нужно воспользоваться ранее сконфигурированным маршрутом, то можно получить его с помощью метода `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. Есть вероятность, что в будущем реализация изменится, и это может вызвать ошибки в вашем коде.

Есть две специальные переменные, которые можно использовать в маршрутах — ':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` вызовет метод latestAction в вашем классе контроллера NewsController.

#### 7.4.3.4. Значения по умолчанию

Любая переменная в маршруте может иметь значение по умолчанию. Для его определения вы должны добавить второй параметр для конструктора `Zend_Controller_Router_Route`. Этот параметр является массивом с ключами, соответствующими именам переменных, и значениями, соответствующими желаемым значениям этих переменных по умолчанию.

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

Этот маршрут будет соответствовать таким URL, как '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')
    );

Результатом будет вызов действия showAction в классе контроллера ArchiveController.

#### 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` год будет равен 2006. Это поведение может быть изменено в будущем, так как все еще было предметом обсуждения во время написания этой документации.

#### 7.4.3.6. Базовый URL и поддиректории

Rewrite Router может использоваться в поддиректориях, базовый URL автоматически определяется в Zend_Controller_Request_Http.

Если базовый URL определяется некорректно, то вы можете переопределить его через метод `setBaseUrl()` объекта `Zend_Controller_Request_Http` (см. Раздел 7.4.2.3, «Базовый URL и поддиректории»).

#### 7.4.3.7. Маршруты по умолчанию

`Zend_Controller_Router_Rewrite` изначально сконфигурирован с одним маршрутом по умолчанию. Он будет соответствовать URI вида `'controller/action'`. Кроме этого, имя модуля может быть определено как первый элемент пути, что позволяет использовать URI вида `'module/controller/action`. Он будет также соответствовать любым дополнительным параметрам, по умолчанию добавляемым в конец 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`, инстанцированный без значений по умолчанию.

    // Маршрут для совместимости с первой версией маршрутизатора
    $compat = new Zend_Controller_Router_Route_Module();
    $this->addRoute('default', $compat);

| Сопоставление URI
`Zend_Controller_Router_Rewrite` сконфигурирован c учетом обратной совместимости. Он будет автоматически использовать маршрут `controller/action` с дополнительными параметрами. Дополнительные параметры не требуют добавления новых маршрутов, если они не должны иметь значений по умолчанию или требований к переменным. Эти дополнительные параметры будут доступны через метод `Zend_Controller_Action::_getParam`.

Если вы не хотите использовать маршрут по умолчанию, то можете удалить его, используя метод `removeDefaultRoutes()`:

    // Удаление маршрута по умолчанию
    $router->removeDefaultRoutes();

#### 7.4.3.8. Статические маршруты

В примерах выше все импользуемые маршруты были динамическими – маршруты, которые содержат паттерны для сопоставления с URI. Тем не менее, определенные маршруты могут быть неизменными, и применение к ним методов регулярных выражений будет совершенно излишним. Решением данной ситуации будет использование статических маршрутов:

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

#### 7.4.3.9. Использование Zend_Config вместе с RewriteRouter

Иногда было бы более удобным обновлять конфигурационные данные для новых маршрутов, чем изменять код. Это возможно через метод `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');

В примере выше мы говорим маршрутизатору, чтобы он использовал раздел 'routes' в файле INI для определения своих маршрутов. Ключ первого уровня в этом разделе используется для имени маршрута, в примере выше определяются маршруты '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. Контроллеры действий