Zend Framework предоставляет некоторые альтернативы принятым по умолчанию классам, в которые входят объекты запросов, маршрутизаторы и объекты ответов.
Zend_Controller_Request_Http
предоставляет
объект запроса для использования в среде HTTP.
Zend_Controller_Request_Http
является классом
запроса, используемым Zend_Controller_Dispatcher
по умолчанию.
Zend_Controller_Request_Http
инкапсулирует доступ
к релевантным значениям, таким, как ключевое имя и значение
для переменных маршрутизатора и все дополнительные параметры,
полученные из URI. Посредством передачи к
Zend_Controller_Request_Http
он также предоставяет
доступ к значениям, содержащимся в суперглобальных переменных
как к открытым членам и управляет текущим базовым URL и URI
запроса. Суперглобальные значения не могут быть установлены в
объекте запроса, за исключением методов setParam/getParam
для установки или извлечения пользовательских переменных.
Суперглобальные данные | |
---|---|
Когда обращаетесь к суперглобальным переменным через
|
К определенным суперглобальным массивам можно также обращаться
через открытые методы. Например, можно получить необработанное
значение $_POST['user']
посредством вызова метода
getPost('user')
в объекте запроса.
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:
$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();
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, то
|
Если используется Lighttpd, то валидным будет следующее правило перезаписи:
url.rewrite-once = ( ".*\.(js|ico|gif|jpg|png|css)$" => "$0", "" => "/index.php")
Чтобы использовать Rewrite Router, нужно инстанцировать его, добавить маршруты и установить его в контроллере. Следующий код демонстрирует эту процедуру:
/* Создание маршрутизатора */ // возвращает используемый по умолчанию маршрутизатор $router = $ctrl->getRouter(); $router->addRoute( 'user', new Zend_Controller_Router_Route('user/:username', array('controller' => 'user', 'action' => 'info')) );
Сущностью 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
, если не была определена.
Специальные переменные | |
---|---|
Имена специальных переменных могут отличаться, если вы
измените значения по умолчанию в
|
$router->addRoute( 'user', new Zend_Controller_Router_Route(':controller/:action') );
Если вы наберете в вашем броузере адрес
'http://example.com/news/latest', то при сопоставлении с таким
маршрутом Zend_Controller_Dispatcher
вызовет метод
latestAction в вашем классе контроллера NewsController.
Любая переменная в маршруте может иметь значение по умолчанию.
Для его определения вы должны добавить второй параметр для
конструктора 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.
Можно добавить третий параметр в вызове конструктора
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
|
Rewrite Router может использоваться в поддиректориях, базовый URL автоматически определяется в Zend_Controller_Request_Http.
Если базовый URL определяется некорректно, то вы можете
переопределить его через метод setBaseUrl()
объекта
Zend_Controller_Request_Http
(см.
Раздел 7.4.2.3, «Базовый URL и поддиректории»).
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 | |
---|---|
|
Если вы не хотите использовать маршрут по умолчанию, то можете
удалить его, используя метод removeDefaultRoutes()
:
// Удаление маршрута по умолчанию $router->removeDefaultRoutes();
В примерах выше все импользуемые маршруты были динамическими – маршруты, которые содержат паттерны для сопоставления с URI. Тем не менее, определенные маршруты могут быть неизменными, и применение к ним методов регулярных выражений будет совершенно излишним. Решением данной ситуации будет использование статических маршрутов:
$loginRoute = new Zend_Controller_Router_Route_Static('login', array('controller' => 'login', 'action' => 'form')); $router->addRoute('login', $loginRoute);
In addition to the default and static route types, a Regular Expression route type is available. This route offers more power and flexibility than the others, but at a slight cost of performance, due to its use of the PCRE engine.
Zend_Controller_Router_Route_Regex
provides a
regex-based route type for use with the rewrite router. Some
usage rules to consider:
It uses the #
character for a delimiter. This
means that you will not need to escape forward slashes
('/'), but will need to escape hash characters ('#').
Line start and line end anchors ('^' and '$', respectively) are automatically pre- and appended to all expressions. Thus, you should not use these in your regular expressions. Also, it means that you should write your expressions to match the entire URL. As an example, given the URL 'http://example.com/foo/bar/baz/bat', if you simply wish to match 'foo/bar', you should write your expression as 'foo/bar(/.*)?'.
The leading and trailing slash are trimmed prior to a match. As a result, matching the URL "http://example.com/foo/bar/" would involve a regex of "foo/bar".
One strength of using regular expressions is the ability to
capture matching segments for use later.
Zend_Controller_Router_Regex_Route
makes use of
this capability in two ways, either:
Setting parameters in the request object as match index (integer) => match. As an example:
<?php // Anything after /foo/bar in the path would be retrieved via the key '1' in the // request object: $route = new Zend_Controller_Router_Route_Regex( 'foo/bar(/.*)?', array('controller' => 'foo', 'action' => 'bar') ); // After routing: $fooPath = $request->getParam('1');
Using a map list from the third parameter passed to the route constructor to map indices to parameter keys. As an example:
<?php // Place anything after /foo/bar in the path into the 'fooPath' request key: $route = new Zend_Controller_Router_Route_Regex( 'foo/bar(/.*)?', array('controller' => 'foo', 'action' => 'bar'), array(1 => 'fooPath') );
As some examples of creating regex routes to use with your router:
// View archived blogs with urls like: // http://example.com/blog/archive/01-Using_the_Regex_Router.html // placing '01' as the 'id' key, and 'Using_the_Regex_Router' as the 'title' key $blogArchive = new Zend_Controller_Router_Route_Regex( 'blog/archive/(\d+)-(.*)\.html', array('controller' => 'blog', 'action' => 'view'), array(1 => 'id', 2 => 'title') ); $router->addRoute('blogArchive', $blogArchive); // View news items with urls like: // http://example.com/news/1193328 // placing '1193328' as the 'id' key $newsItem = new Zend_Controlelr_Router_Route_Regex( 'news/(\d+)', array('controller' => 'news', 'action' => 'view'), array(1 => 'id') ); $router->addRoute('newsItem', $newsItem);
Иногда было бы более удобным обновлять конфигурационные данные
для новых маршрутов, чем изменять код. Это возможно через метод
addConfig()
. По существу, вы создаете конфигурацию,
совместимую с Zend_Config, считываете ее в своем коде и
передаете RewriteRouter.
В качестве примера рассмотрим следующий INI-файл:
[production] 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"
Этот INI-файл может быть затем прочитан в объект
Zend_Config
как показано ниже:
$config = new Zend_Config_Ini('/path/to/config.ini', 'production'); $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
.
Zend_Controller_Response_Http
является объектом ответа,
пригодным к использованию в среде HTTP. Он содержит методы для
установки, получения и удаления заголовков, а также метод
__toString()
, который отправляет все заголовки
одновременно до того, как будет возвращено содержимое ответа.
setHeader()
принимает два аргумента – тип заголовка и
значение заголовка. Если передан третий необязательный параметр и он
имеет значение true
, то производится принудительная
замена значения заголовка с тем же типом, если он уже был
зарегистрирован.