1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.controller.router" xmlns:xi="http://www.w3.org/2001/XInclude">
4 <title>Стандартный маршрутизатор</title>
5 <sect2 id="zend.controller.router.introduction">
6 <title>Введение</title>
8 <classname>Zend_Controller_Router_Rewrite</classname> является стандартным
9 маршрутизатором фреймворка. Маршрутизация - это процесс принятия
10 конечной точки URI (той части URI, которая
11 идет после базового URL) и ее разложения на параметры
12 для определения того, какой контроллер и какое действие этого
13 контроллера должны получить запрос. Значения контроллера,
14 действия и необязательных параметров сохраняются в объекте
15 <classname>Zend_Controller_Request_Http</classname>, который затем
16 обрабатывается диспетчером
17 <classname>Zend_Controller_Dispatcher_Standard</classname>. Маршрутизация
18 производится только один раз – когда вначале
19 получен запрос и до того, как первый контроллер будет запущен.
23 <classname>Zend_Controller_Router_Rewrite</classname> спроектирован для
24 того, чтобы обеспечить функциональность, подобную mod_rewrite,
25 с использованием чистого PHP. Он отчасти основан на маршрутизации,
26 используемой в Ruby on Rails и не требует каких-либо предварительных
27 знаний о перезаписи URL веб-сервером. Он спроектирован для работы с
28 единственным правилом mod_rewrite, пример которого приведен
32 <programlisting language="php"><![CDATA[
34 RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ index.php
38 или (более предпочтительный вариант):
41 <programlisting language="php"><![CDATA[
43 RewriteCond %{REQUEST_FILENAME} -s [OR]
44 RewriteCond %{REQUEST_FILENAME} -l [OR]
45 RewriteCond %{REQUEST_FILENAME} -d
46 RewriteRule ^.*$ - [NC,L]
47 RewriteRule ^.*$ index.php [NC,L]
51 Rewrite Router может также использоваться с веб-сервером IIS версии
53 <ulink url="http://www.isapirewrite.com">Isapi_Rewrite</ulink>
54 был установлен как расширение Isapi со следующими правилами
58 <programlisting language="php"><![CDATA[
59 RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css|html)$)[\w\%]*$)? /index.php [I]
63 <title>IIS Isapi_Rewrite</title>
65 Если используется IIS, то <varname>$_SERVER['REQUEST_URI']</varname>
66 не будет определен, либо будет установлен как пустая
68 <classname>Zend_Controller_Request_Http</classname> попытается
69 использовать <varname>$_SERVER['HTTP_X_REWRITE_URL']</varname>,
70 значение которого устанавливается расширением Isapi_Rewrite.
75 IIS 7.0 имеет свой собственный модуль перезаписи URL,
76 и он может быть сконфигурирован следующим образом:
79 <programlisting language="xml"><![CDATA[
80 <?xml version="1.0" encoding="UTF-8"?>
85 <rule name="Imported Rule 1" stopProcessing="true">
87 <conditions logicalGrouping="MatchAny">
88 <add input="{REQUEST_FILENAME}"
89 matchType="IsFile" pattern=""
91 <add input="{REQUEST_FILENAME}"
92 matchType="IsDirectory"
93 pattern="" ignoreCase="false" />
95 <action type="None" />
97 <rule name="Imported Rule 2" stopProcessing="true">
99 <action type="Rewrite" url="index.php" />
108 Если используется Lighttpd, то корректным будет следующее
112 <programlisting language="lighttpd"><![CDATA[
114 ".*\?(.*)$" => "/index.php?$1",
115 ".*\.(js|ico|gif|jpg|png|css|html)$" => "$0",
121 <sect2 id="zend.controller.router.usage">
122 <title>Использование маршрутизатора</title>
125 Для того, чтобы правильно использовать маршрутизатор, вы должны
126 инстанцировать его, добавить пользовательские маршруты, и внедрить
127 его во фронт-контроллер. Следующий код иллюстрирует эту процедуру:
130 <programlisting language="php"><![CDATA[
131 // Создание маршрутизатора
133 $router = $ctrl->getRouter(); // по умолчанию возвращает rewrite router
136 new Zend_Controller_Router_Route('user/:username',
137 array('controller' => 'user',
143 <sect2 id="zend.controller.router.basic">
144 <title>Базовые операции Rewrite Router</title>
147 Сущностью RewriteRouter (перезаписывающий маршрутизатор) является
148 определение пользовательских маршрутов. Маршруты добавляются
149 посредством вызовом метода <code>addRoute()</code> и передачей ему
150 экземпляра класса, реализующего
151 <classname>Zend_Controller_Router_Route</classname>. Например:
154 <programlisting language="php"><![CDATA[
155 $router->addRoute('user',
156 new Zend_Controller_Router_Route('user/:username'));
160 Rewrite Router поставляется вместе с шестью базовыми типами
161 маршрутов (один из которых является специальным):
164 <itemizedlist mark="opencircle">
166 <xref linkend="zend.controller.router.routes.standard" />
169 <xref linkend="zend.controller.router.routes.static" />
172 <xref linkend="zend.controller.router.routes.regex" />
175 <xref linkend="zend.controller.router.routes.hostname" />
178 <xref linkend="zend.controller.router.routes.chain" />
181 <xref linkend="zend.controller.router.default-routes" /> *
186 Маршруты могут использоваться несколько раз для создания цепочки или
187 пользовательской схемы маршрутизации в приложении. Вы можете
188 использовать любое количество маршрутов в любой конфигурации, за
189 исключением маршрута Module, который предпочтительно должен
190 использоваться один раз и, возможно, как наиболее общий маршрут
191 (например, в качестве используемого по умолчанию). Каждый маршрут
192 будет в подробностях описан ниже.
196 Первым параметром метода <code>addRoute()</code> является имя
197 маршрута. Он используется в качестве идентификатора для получения
198 маршрутов из маршрутизатора (например, в целях генерации URL).
199 Вторым параметром является сам маршрут.
204 Наиболее часто имя маршрута используется через хелпер для URL
205 компоненты <classname>Zend_View</classname>:
208 <programlisting language="php"><![CDATA[
210 "<?php echo $this->url(array('username' => 'martel'), 'user') ?>">Martel</a>
214 В результате значением атрибута href будет
215 <code>user/martel</code>.
220 Маршрутизация - простой процесс итерации по всем предоставленным
221 маршрутам и сопоставления их определений с текущим URI запроса.
222 Когда найдено соответствие, то из объекта маршрута возвращаются
223 значения переменных и добавляются в объект
224 <classname>Zend_Controller_Request</classname> для дальнейшего использования в
225 диспетчере и пользовательских контроллерах. Если соответствие не
226 найдено, то проверяется следующий маршрут в цепочке.
230 Если нужно определить выбранный маршрут,
231 то можно использовать метод <code>getCurrentRouteName()</code>,
232 он возвращает идентификатор, который использовался при регистрации
233 маршрута в маршрутизаторе. Если требуется получить объект,
234 то используйте <code>getCurrentRoute()</code>.
238 <title>Обратный порядок сопоставления</title>
240 Маршруты сопоставляются в обратном порядке, поэтому
241 удостоверьтесь, что наиболее общие маршруты определены
247 <title>Возвращаемые значения</title>
249 Значения, возвращаемые при маршрутизации, получаются из
250 параметров URL или определенных пользователем значений по
251 умолчанию. Эти переменные позднее могут быть позднее получены
252 через методы <code>Zend_Controller_Request::getParam()</code>
253 и <code>Zend_Controller_Action::_getParam()</code>
258 Есть три специальные переменные, которые могут использоваться в
259 маршрутах: 'module', 'controller' и 'action'. Эти
260 переменные используются диспетчером <classname>Zend_Controller_Dispatcher</classname>
261 для нахождения контроллера и действия, которым передается
266 <title>Специальные переменные</title>
268 Имена этих переменных могут быть другими, если вы измените их
269 через методы <code>setControllerKey</code> и
270 <code>setActionKey</code>.
276 <sect2 id="zend.controller.router.default-routes">
277 <title>Маршруты, используемые по умолчанию</title>
280 <classname>Zend_Controller_Router_Rewrite</classname> изначально
281 сконфигурирован с одним маршрутом по умолчанию, который будет
282 соответствовать URI вида <code>контроллер/действие</code>. Кроме
283 того, в качестве первого элемента пути может быть указано имя
284 модуля, это позволяет использовать URI вида
285 <code>модуль/контроллер/действие</code>.
286 Этот маршрут будет также соответствовать любым дополнительным
287 параметрам, по умолчанию добавляемым в конец URI -
288 <code>контроллер/действие/переменная1/значение1/переменная2/значение2</code>.
292 Некоторые примеры того, чему будут соответствовать такие маршруты:
295 <programlisting language="php"><![CDATA[
296 // Допустим, есть следующие настройки:
297 $ctrl->setControllerDirectory(
299 'default' => '/path/to/default/controllers',
300 'news' => '/path/to/news/controllers',
301 'blog' => '/path/to/blog/controllers'
309 Если модуль не найден, то считается, что это имя контроллера:
314 http://example/blog/archive
316 controller == archive
318 Модуль + контроллер + действие:
319 http://example/blog/archive/list
321 controller == archive
324 Модуль + контроллер + действие + параметры:
325 http://example/blog/archive/list/sort/alpha/date/desc
327 controller == archive
334 Маршрутом, используемым по умолчанию, является объект
335 <classname>Zend_Controller_Router_Route_Module</classname>, сохраненный в
336 RewriteRouter под именем (индексом) 'default'. Он создается
337 приблизительно следующим образом:
340 <programlisting language="php"><![CDATA[
341 $compat = new Zend_Controller_Router_Route_Module(array(),
344 $this->addRoute('default', $compat);
348 Если вы не хотите использовать этот маршрут по умолчанию в своей
349 схеме маршрутизации, то можете переопределить его путем создания
350 собственного маршрута по умолчанию (т.е. сохранения его под именем
351 'default') или полностью удалить его через метод
352 <code>removeDefaultRoutes()</code>:
355 <programlisting language="php"><![CDATA[
356 // Удаление всех маршрутов по умолчанию
357 $router->removeDefaultRoutes();
362 <sect2 id="zend.controller.router.rewritebase">
363 <title>Базовый URL и поддиректории</title>
366 RewriteRouter может использоваться в поддиректориях (например,
367 <code>http://domain.com/~user/application-root/</code>), в этом
368 случае базовый URL приложения (<code>/~user/application-root</code>)
369 должен автоматически определяться в объекте
370 <classname>Zend_Controller_Request_Http</classname> и соответствующим образом
375 Если базовый URL определяется некорректно, то вы можете
376 переопределить его через метод <code>setBaseUrl()</code> объекта
377 <classname>Zend_Controller_Request_Http</classname> (см.
378 <xref linkend="zend.controller.request.http.baseurl" />):
381 <programlisting language="php"><![CDATA[
382 $request->setBaseUrl('/~user/application-root/');
387 <sect2 id="zend.controller.router.global.parameters">
388 <title>Глобальные параметры</title>
391 Используя метод <code>setGlobalParam</code>, вы можете устанавливать
392 глобальные параметры в маршрутизаторе, которые будут автоматически
393 подставляться в маршрут при сборке. Если был установлен глобальный
394 параметр, но при сборке тот же параметр был передан напрямую,
395 то переданное значение параметра заменяет собой глобальное.
396 Вы можете устанавливать глобальный параметр следующим образом:
399 <programlisting language="php"><![CDATA[
400 $router->setGlobalParam('lang', 'en');
404 <sect2 id="zend.controller.router.routes">
405 <title>Типы маршрутов</title>
406 <xi:include href="Zend_Controller-Router-Route.xml">
407 <xi:fallback><xi:include href="../../en/module_specs/Zend_Controller-Router-Route.xml" /></xi:fallback>
409 <xi:include href="Zend_Controller-Router-Route-Static.xml">
410 <xi:fallback><xi:include href="../../en/module_specs/Zend_Controller-Router-Route-Static.xml" /></xi:fallback>
412 <xi:include href="Zend_Controller-Router-Route-Regex.xml">
413 <xi:fallback><xi:include href="../../en/module_specs/Zend_Controller-Router-Route-Regex.xml" /></xi:fallback>
415 <xi:include href="Zend_Controller-Router-Route-Hostname.xml">
416 <xi:fallback><xi:include href="../../en/module_specs/Zend_Controller-Router-Route-Hostname.xml" /></xi:fallback>
418 <xi:include href="Zend_Controller-Router-Route-Chain.xml">
419 <xi:fallback><xi:include href="../../en/module_specs/Zend_Controller-Router-Route-Chain.xml" /></xi:fallback>
423 <sect2 id="zend.controller.router.add-config">
424 <title>Использование Zend_Config вместе с RewriteRouter</title>
427 Иногда может быть более удобным обновлять конфигурационный файл
428 с новыми маршрутами, чем изменять код. Это возможно благодаря методу
429 <code>addConfig()</code>. В сущности, вы создаете конфигурацию,
430 совместимую с <classname>Zend_Config</classname>, считываете ее в своем коде и
431 передаете RewriteRouter.
435 В качестве примера рассмотрим следующий INI-файл:
438 <programlisting language="php"><![CDATA[
440 routes.archive.route = "archive/:year/*"
441 routes.archive.defaults.controller = archive
442 routes.archive.defaults.action = show
443 routes.archive.defaults.year = 2000
444 routes.archive.reqs.year = "\d+"
446 routes.news.type = "Zend_Controller_Router_Route_Static"
447 routes.news.route = "news"
448 routes.news.defaults.controller = "news"
449 routes.news.defaults.action = "list"
451 routes.archive.type = "Zend_Controller_Router_Route_Regex"
452 routes.archive.route = "archive/(\d+)"
453 routes.archive.defaults.controller = "archive"
454 routes.archive.defaults.action = "show"
455 routes.archive.map.1 = "year"
456 ; ИЛИ: routes.archive.map.year = 1
460 Этот INI-файл может быть затем прочитан в объект
461 <classname>Zend_Config</classname> как показано ниже:
464 <programlisting language="php"><![CDATA[
465 $config = new Zend_Config_Ini('/path/to/config.ini', 'production');
466 $router = new Zend_Controller_Router_Rewrite();
467 $router->addConfig($config, 'routes');
471 В примере выше мы говорим маршрутизатору, чтобы он использовал
472 раздел 'routes' в файле INI для своих маршрутов. Ключ первого уровня
473 в этом разделе используется для определения имени маршрута, в
474 примере выше определяются маршруты 'archive' и
475 'news'. Каждый маршрут требует, как минимум, запись 'route' и
476 одну или более записей 'defaults'; опционально может быть одна
477 или более записей 'reqs' (сокращение от 'required'). Все это
478 соответствует трем аргументам, передаваемым объекту
479 <classname>Zend_Controller_Router_Route_Interface</classname>.
480 Опция с ключом 'type' может использоваться для определения класса,
481 используемого для данного маршрута; по умолчанию используется
482 класс <classname>Zend_Controller_Router_Route</classname>. В примере выше
483 для маршрута 'news' должен использоваться класс
484 <classname>Zend_Controller_Router_Route_Static</classname>.
488 <sect2 id="zend.controller.router.subclassing">
489 <title>Создание подклассов маршрутизатора</title>
492 Стандартный RewriteRouter создан с тем, чтобы предоставлять полный
493 набор тех функциональных возможностей, которые могут вам
494 понадобиться. Как правило, вам нужно будет только создать новый тип
495 маршрута для того, чтобы получить новый или измененный функционал
496 сверх уже существующих типов маршрутов.
500 В какой-то момент вы можете захотеть использовать другую парадигму
501 маршрутизации. Интерфейс
502 <classname>Zend_Controller_Router_Interface</classname> дает минимальную
503 информацию, необходимую для создания маршрута и содержит всего один
507 <programlisting language="php"><![CDATA[
508 interface Zend_Controller_Router_Interface
511 * @param Zend_Controller_Request_Abstract $request
512 * @throws Zend_Controller_Router_Exception
513 * @return Zend_Controller_Request_Abstract
515 public function route(Zend_Controller_Request_Abstract $request);
520 Маршрутизация производится только один раз - когда в систему
521 поступил первый запрос. Назначение маршрутизатора состоит в
522 определении контроллера, действия и опциональных параметров,
523 основываясь на переменных запроса, и установке их в запросе. Затем
524 объект запроса передается диспетчеру. Если не найден соответствующий
525 маршрут, то маршрутизатор не должен ничего делать с объектом