1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.controller.front">
4 <title>Фронт-контроллер</title>
6 <sect2 id="zend.controller.front.overview">
10 <classname>Zend_Controller_Front</classname> реализует
11 <ulink url="http://www.martinfowler.com/eaaCatalog/frontController.html">паттерн
12 Front Controller</ulink>, используемый в приложениях <ulink
13 url="http://en.wikipedia.org/wiki/Model-view-controller">MVC</ulink>.
14 Его назначение состоит в инициализации окружения запроса, проложении
15 маршрута приходящего запроса и последующем запуске выявленных
16 действий. Он агрегирует все ответы и возвращает их по завершении
21 <classname>Zend_Controller_Front</classname> также реализует
22 <ulink url="http://en.wikipedia.org/wiki/Singleton_pattern">паттерн
23 Singleton</ulink>, это означает, что в любое время может быть
24 доступен только один экземпляр этого класса. Это позволяет ему также
25 выступать в качестве реестра, в котором хранятся другие объекты,
26 участвующие в процессе диспетчеризации.
30 <classname>Zend_Controller_Front</classname> регистрирует в себе <link
31 linkend="zend.controller.plugins">брокер плагинов</link> (plugin
32 broker), что позволяет с помощью плагинов отслеживать события,
33 инициируемые фронт-контроллером.
34 В большинстве случаев это дает возможность подгонять
35 процесс диспетчеризации под конкретный сайт без расширения
36 фронт-контроллера для добавления функциональности.
40 Фронт-контроллеру для его работы необходим, как минимум,
41 один или более путей к директориям, содержащим
42 <link linkend="zend.controller.action">контроллеры действий</link>.
43 Можно также использовать различные методы для дальнейшей
44 настройки конфигураций фронт-контроллера и его помощников.
48 <title>Поведение по умолчанию</title>
50 По умолчанию фронт-контроллер загружает плагин <link
51 linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler</link>
52 и помощник действий <link
53 linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
54 Это сделано для упрощения обработки ошибок и рендеринга видов в
55 контроллерах, соответственно.
59 Для того, чтобы отключить <code>ErrorHandler</code>, произведите
60 следующее до вызова метода <code>dispatch()</code>:
63 <programlisting language="php"><![CDATA[
64 // Отключение плагина ErrorHandler:
65 $front->setParam('noErrorHandler', true);
69 Для того, чтобы отключить <code>ViewRenderer</code>, сделайте
70 следующее до вызова метода <code>dispatch()</code>:
73 <programlisting language="php"><![CDATA[
74 // Отключение помощника ViewRenderer:
75 $front->setParam('noViewRenderer', true);
81 <sect2 id="zend.controller.front.methods.primary">
82 <title>Ключевые методы</title>
85 Фронт-контроллер имеет несколько аксессоров для настройки его
86 конфигурации. Тем не менее, он имеет несколько ключевых в
87 его функционале методов.
90 <sect3 id="zend.controller.front.methods.primary.getinstance">
91 <title>getInstance()</title>
94 <code>getInstance()</code> используется для получения экземпляра
95 фронт-контроллера. Поскольку фронт-контроллер реализует паттерн
96 Singleton, то это также единственно доступный способ
97 инстанцирования объекта фронт-контроллера.
100 <programlisting language="php"><![CDATA[
101 $front = Zend_Controller_Front::getInstance();
105 <sect3 id="zend.controller.front.methods.primary.setcontrollerdirectory">
106 <title>setControllerDirectory() и addControllerDirectory()</title>
109 <code>setControllerDirectory()</code> используется для того,
111 linkend="zend.controller.dispatcher">диспетчеру</link>, где
112 искать файлы классов <link
113 linkend="zend.controller.action">контроллеров действий</link>.
114 Он принимает один путь или ассоциативный массив пар
115 модуль => путь в качестве параметра.
122 <programlisting language="php"><![CDATA[
123 // Установка директории контроллеров, используемой по умолчанию:
124 $front->setControllerDirectory('../application/controllers');
126 // Одновременная установка нескольких директорий модулей:
127 $front->setControllerDirectory(array(
128 'default' => '../application/controllers',
129 'blog' => '../modules/blog/controllers',
130 'news' => '../modules/news/controllers',
133 // Добавление директории модуля 'foo':
134 $front->addControllerDirectory('../modules/foo/controllers', 'foo');
139 Если вы используете <code>addControllerDirectory()</code>
140 без имени модуля, то он установит директорию для модуля
141 <code>default</code>. Если директория уже существует, то она
147 Можно получить текущие установки для директорий
148 контроллеров, используя метод
149 <code>getControllerDirectory()</code>. Он вернет массив пар
150 модуль => директория.
154 <sect3 id="zend.controller.front.methods.primary.addmoduledirectory">
155 <title>addModuleDirectory() и getModuleDirectory()</title>
158 Одной из возможностей фронт-контроллера является то, что вы
160 linkend="zend.controller.modular">определять модульную
161 структуру директорий</link> для создания отдельных компонент,
162 которые называются "модулями".
166 Каждый модуль должен находиться в собственной директории и
167 отражать структуру директорий используемого по умолчанию
168 модуля - т.е., он должен содержать, как минимум, поддиректорию
169 "controllers"; с ней, как правило, присутствует поддиректория
170 "views" и другие поддиректории приложения.
174 Метод <code>addModuleDirectory()</code> позволяет передавать имя
175 директории, содержащей один или более директорий модулей.
176 Он их сканирует и добавляет в качестве директорий контроллеров
181 Если вы хотите получить путь к определенному модулю или к
182 текущему модулю, то можете использовать метод
183 <code>getModuleDirectory()</code>, при передаче имени модуля он
184 возвращает путь к нему, иначе возвращается путь к текущему
189 <sect3 id="zend.controller.front.methods.primary.dispatch">
190 <title>dispatch()</title>
193 <code>dispatch(Zend_Controller_Request_Abstract $request = null,
194 Zend_Controller_Response_Abstract $response = null)</code>
195 является "рабочей лошадкой" фронт-контроллера. Он может
196 опционально принимать
197 <link linkend="zend.controller.request">объект
199 <link linkend="zend.controller.response">объект
200 ответа</link>, что дает разработчикам возможность передавать
205 Если методу <code>dispatch()</code> не были переданы объект
206 запроса или ответа, то он будет проверять, были ли ранее
207 зарегистрированы объекты, и использовать их, либо инстанцировать
208 версии по умолчанию (в обоих случаях по умолчанию будут
209 использоваться разновидность HTTP).
213 Аналогичным образом <code>dispatch()</code> производит проверку
214 на уже зарегистрированные объекты
215 <link linkend="zend.controller.router">маршрутизатора</link> и
216 <link linkend="zend.controller.dispatcher">диспетчера</link>, и
217 если они не найдены, то инстанцирует версии по умолчанию.
221 Процесс диспетчеризации имеет три отдельных события:
237 Маршрутизация производится только один раз, когда вызывается
238 <code>dispatch()</code>, при этом используются значения в
239 объекте запроса. Диспетчеризация производится циклически. Запрос
240 может означать вызов нескольких действий, контроллер или плагин
241 могут сбрасывать объект запроса для дополнительного вызова
242 других действий. Когда все действия выполнены, фронт-контроллер
247 <sect3 id="zend.controller.front.methods.primary.run">
251 <code>Zend_Controller_Front::run($path)</code> - статический
252 метод, принимающий только путь к директории контроллеров. Он
253 извлекает экземпляр фронт-контроллера через
254 <link linkend="zend.controller.front.methods.primary.getinstance">getInstance()</link>),
255 регистрирует этот путь через
256 <link linkend="zend.controller.front.methods.primary.setcontrollerdirectory">setControllerDirectory()</link>, и в конце вызывает метод <link linkend="zend.controller.front.methods.primary.dispatch">dispatch()</link>.
260 В сущности, <code>run()</code> представляет собой удобный
261 метод, который можно использовать при разработке сайта, не
262 требующего специальной настройки фронт-контроллера.
265 <programlisting language="php"><![CDATA[
266 // Инстанцирование фронт-контроллера, установка директории контроллера и
267 // выполнение диспетчеризации в одном вызове:
268 Zend_Controller_Front::run('../application/controllers');
273 <sect2 id="zend.controller.front.methods.environment">
274 <title>Методы-аксессоры для конфигурирования</title>
277 Кроме методов, перечисленных выше, есть методы-аксессоры, которые
278 можно использовать для управления конфигурацией фронт-контроллера -
279 и одновременно конфигурацией классов, которым фронт-контроллер
280 делегирует выполнение.
286 <code>resetInstance()</code> может использоваться для сброса
287 всех текущих настроек. Он в основном предназначен для
288 тестирования, но может также использоваться в тех случаях,
289 когда нужно связать между собой несколько
296 <code>(set|get)DefaultControllerName()</code> позволяют
297 установить другое имя используемого
298 по умолчанию контроллера (иначе используется 'index') и
299 получить текущее значение. Они служат посредниками к
300 <link linkend="zend.controller.dispatcher">диспетчеру</link>.
306 <code>(set|get)DefaultAction()</code> позволяют
307 установить другое имя используемого по умолчанию действия
308 (иначе используется 'index') и получить текущее
309 значение. Они служат посредниками к
310 <link linkend="zend.controller.dispatcher">диспетчеру</link>.
316 <code>(set|get)Request()</code> позволяют установить
317 класс <link linkend="zend.controller.request">запроса</link>
318 или его объект для использования в процессе диспетчеризации
319 и получить текущий объект. При установке объекта
320 запроса вы можете передать имя класса запроса, в этом случае
321 метод загрузит файл класса и инстанцирует его.
327 <code>(set|get)Router()</code> позволяют установить
329 <link linkend="zend.controller.router">маршрутизатора</link>
330 или его объект, используемые в течение процесса
331 диспетчеризации, и получить текущий объект. Когда
332 устанавливается объект маршрутизатора, вы можете передать
333 имя класса маршрутизатора, в этом случае метод загрузит файл
334 класса и инстанцирует его.
338 При извлечении объекта маршрутизатора сначала производится
339 проверка, представлен ли во фронт-контроллере такой объект и
340 в случае его отсутствия инстанцирует используемый по
341 умолчанию маршрутизатор (Rewrite Router).
347 <code>(set|get)BaseUrl()</code> дают возможность установить
348 <link linkend="zend.controller.request.http.baseurl">базовый
349 URL</link>, который удаляется из начала при
350 маршрутизации запросов, и получить его текущее значение.
351 Это значение передается объекту запроса непосредственно до
358 <code>(set|get)Dispatcher()</code> дают возможность
360 <link linkend="zend.controller.dispatcher">диспетчера</link>
361 или его объекта для использования в течение диспетчеризации,
362 и получения текущего объекта. При установке объекта
363 диспетчера можно передать имя класса диспетчера, в этом
364 случае метод загрузит файл класса и инстанцирует его.
368 При извлечении объекта диспетчера, метод сначала производит
369 проверку того, представлен ли во фронт-контроллере такой
370 объект и в случае его отсутствия инстанцирует диспетчер,
371 используемый по умолчанию.
377 <code>(set|get)Response()</code> дают возможность установить
378 класс <link linkend="zend.controller.response">ответа</link>
379 или его объект для использования в процессе диспетчеризации,
380 и извлечь текущий объект. При установке объекта
381 ответа можно передать имя класса ответа, в этом случае метод
382 загрузит файл класса и инстанцирует его.
388 <code>registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null)</code>
389 позволяет регистрировать <link
390 linkend="zend.controller.plugins">объекты плагинов</link>.
391 Путем установки опционального параметра
392 <varname>$stackIndex</varname>, вы можете
393 контролировать порядок, в котором выполняются плагины.
399 <code>unregisterPlugin($plugin)</code> позволяет отменять
401 linkend="zend.controller.plugins">объектов плагинов</link>.
402 <varname>$plugin</varname> может быть как объектом плагина, так и строкой, обозначающей класс плагина, регистрацию которого надо отменить.
408 <code>throwExceptions($flag)</code> используется для
409 включения/отключения возможности генерации исключений в
410 течение процесса диспетчеризации. По умолчанию исключения
411 отлавливаются и размещаются в
412 <link linkend="zend.controller.response">объекте
413 ответа</link>; включение <code>throwExceptions()</code>
414 переопределит это поведение
418 Более полробную информацию читайте в <xref linkend="zend.controller.exceptions"/>.
424 <code>returnResponse($flag)</code> используется для того,
425 чтобы указать фронт-контроллеру - возвращать ли ответ
426 из <code>dispatch()</code> (<constant>TRUE</constant>), либо ответ
427 должен быть отправлен автоматически (<constant>FALSE</constant>). По
428 умолчанию ответ отправляется автоматически
430 <code>Zend_Controller_Response_Abstract::sendResponse()</code>);
431 включение <code>returnResponse()</code> переопределит это
436 Ситуации, в которых может потребоваться возврат ответа,
437 включают в себя проверку на предмет исключений до отправки
438 ответа клиенту, необходимость журналирования различных
439 аспектов ответа (таких, как заголовки) и т.д.
445 <sect2 id="zend.controller.front.methods.params">
446 <title>Параметры фронт-контроллера</title>
449 Во введении мы указали на то, что фронт-контроллер также выступает
450 как реестр для различных компонент контроллера. Это реализуется
451 через группу методов для параметров. Эти методы позволяют
452 регистрировать произвольные данные - объекты и переменные - во
453 фронт-контроллере, чтобы их можно было извлечь в любой точке цепочки
454 диспетчеризации. Эти значения передаются маршрутизатору, диспетчеру,
455 и контроллерам действий. Эти методы включают в себя:
461 <code>setParam($name, $value)</code> дает возможность
462 установить единственный параметр с именем <varname>$name</varname>
463 и значением <varname>$value</varname>.
469 <code>setParams(array $params)</code> позволяет
470 установить несколько параметров одновременно с помощью
471 ассоциативного массива.
477 <code>getParam($name)</code> дает возможность извлечь один
478 параметр за один раз, используя его имя <varname>$name</varname> в
479 качестве идентификатора.
485 <code>getParams()</code> позволяет извлечь все
486 параметры за один раз.
492 <code>clearParams()</code> позволяет удалить один параметр
493 (путем передачи строкового идентификатора), нескольких
494 параметров (путем передачи массива строковых
495 идентификаторов) или весь стек параметров (без передачи
502 Есть несколько предопределенных параметров специально для
503 использования в цепочке диспетчеризации:
509 <code>useDefaultControllerAlways</code> используется для
511 <link linkend="zend.controller.dispatcher">диспетчеру</link>,
512 что следует использовать контроллер по умолчанию в модуле
513 по умолчанию для любых запросов, диспетчеризация которых
514 невозможна (т.е. модуль, контроллер и/или действие не
515 существуют). По умолчанию он отключен.
519 См. <xref linkend="zend.controller.exceptions.internal"/> за
520 более подробной информацией об использовании этого параметра
527 <code>disableOutputBuffering</code> используется для
529 <link linkend="zend.controller.dispatcher">диспетчеру</link>,
530 что не следует использовать буферизацию вывода для сбора
531 данных на вывод, генерируемых контроллерами действий. По
532 умолчанию диспетчер собирает весь вывод и присоединяет его к
533 телу содержимого в объекте ответа.
539 <code>noViewRenderer</code> используется для отключения
541 linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
542 Установите этот параметр в true для его отключения.
548 <code>noErrorHandler</code> используется для отключения
550 linkend="zend.controller.plugins.standard.errorhandler">плагина
552 Установите этот параметр в true для его отключения.
558 <sect2 id="zend.controller.front.subclassing">
559 <title>Расширение фронт-контроллера</title>
562 При наследовании от фронт-контроллера, необходимо, как
563 минимум, переопределить метод <code>getInstance()</code>.
566 <programlisting language="php"><![CDATA[
567 class My_Controller_Front extends Zend_Controller_Front
569 public static function getInstance()
571 if (null === self::$_instance) {
572 self::$_instance = new self();
575 return self::$_instance;
581 Такое переопределение метода <code>getInstance()</code> гарантирует
582 то, что последующий вызов
583 <code>Zend_Controller_Front::getInstance()</code> вернет экземпляр
584 созданного вами подкласса вместо экземпляра
585 <classname>Zend_Controller_Front</classname> - это особенно полезно
586 для некоторых альтернативных маршрутизаторов и помощников видов.
590 Как правило, нет необходимости создавать подклассы
591 фронт-контроллера, если только не нужно добавить новый
592 функционал (например, автозагрузку плагинов или способ
593 определения путей к помощникам действий). Целями, для достижения
594 которых может потребоваться изменение поведения фронт-контроллера,
595 могут быть изменение принципа хранения директорий
596 контроллеров, установка других используемых по умолчанию
597 маршрутизатора и диспетчера и т.д.