[MANUAL] English:
[zend.git] / documentation / manual / ru / module_specs / Zend_Controller-ActionController.xml
blobf45b5c67764304c0e0e4fce8644f5190563134cf
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.controller.action">
4     <title>Контроллеры действий</title>
6     <sect2 id="zend.controller.action.introduction">
7         <title>Введение</title>
8         <para>
9             <classname>Zend_Controller_Action</classname> - абстрактный класс,
10             который можно использовать для реализации контроллеров действий
11             для последующего их использования с фронт-контроллером при
12             разработке сайта, основанного на паттерне Model-View-Controller
13             (MVC).
14         </para>
16         <para>
17             Для того, чтобы использовать <classname>Zend_Controller_Action</classname>,
18             нужно создать его подкласс в своей действующей директории
19             контроллеров (или расширить его для создания своего базового класса
20             контроллеров действий). Работа с ним в основном сводится к
21             созданию его подкласса и написании методов действий, соответствующих
22             различным действиям, которые должен обрабатывать этот контроллер.
23             Маршрутизатор и диспетчер компоненты <classname>Zend_Controller</classname>
24             будут считать за методы действий все методы в классе
25             контроллера с именем, заканчивающимся на 'Action'.
26         </para>
28         <para>
29             Для примера предположим, что ваш класс определен следующим образом:
30         </para>
32         <programlisting language="php"><![CDATA[
33 class FooController extends Zend_Controller_Action
35     public function barAction()
36     {
37         // делает что-нибудь
38     }
40     public function bazAction()
41     {
42         // делает что-нибудь
43     }
45 ]]></programlisting>
47         <para>
48             Приведенный выше класс <code>FooController</code> (контроллер
49             <code>foo</code>) определяет два действия - <code>bar</code> и
50             <code>baz</code>.
51         </para>
53         <para>
54             Класс может быть дополнен инициализирующим методом, методом
55             действия по умолчанию (если не был вызван метод, либо
56             вызван несуществующий метод), перехватчиками pre- и post-dispatch и
57             различными вспомогательными методами. Этот раздел служит обзором
58             функционала контроллера действий.
59         </para>
61         <note>
62             <title>Поведение по умолчанию</title>
64             <para>
65                 По умолчанию <link
66                 linkend="zend.controller.front">фронт-контроллер</link>
67                 активирует помощника действий <link
68                 linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
69                 Этот помощник обеспечивает добавление объекта вида в контроллер
70                 и автоматический рендеринг видов. Вы можете отключить его в
71                 своем контроллере действия, используя один из следующих методов:
72             </para>
74             <programlisting language="php"><![CDATA[
75 class FooController extends Zend_Controller_Action
77     public function init()
78     {
79         // Локально, только для данного контроллера:
80         $this->_invokeArgs['noViewRenderer'] = true;
82         // Глобально:
83         $this->_helper->removeHelper('viewRenderer');
85         // Тоже глобально, но должен использоваться вместе
86         // с локальной версией для того, чтобы распространить
87         // действие на данный контроллер:
88         Zend_Controller_Front::getInstance()
89             ->setParam('noViewRenderer', true);
90     }
92 ]]></programlisting>
94             <para>
95                 <code>initView()</code>, <code>getViewScript()</code>,
96                 <code>render()</code> и <code>renderScript()</code> служат
97                 посредниками для <code>ViewRenderer</code>, пока этот помощник
98                 находится в брокере помощников и не установлен флаг
99                 <code>noViewRenderer</code>.
100             </para>
102             <para>
103                 Вы можете также отключить рендеринг для отдельного вида
104                 посредством установки флага <code>noRender</code> в
105                 <code>ViewRenderer</code>:
106             </para>
108             <programlisting language="php"><![CDATA[
109 class FooController extends Zend_Controller_Action
111     public function barAction()
112     {
113         // отключение авторендеринга для этого действия:
114         $this->_helper->viewRenderer->setNoRender();
115     }
117 ]]></programlisting>
119             <para>
120                 Основные причины для отключения <code>ViewRenderer</code> - вам
121                 просто не нужен объект вида или если вы не производите рендеринг
122                 через скрипты вида (например, когда используется контроллер
123                 действий для обслуживания протоколов веб-сервисов, таких, как
124                 SOAP, XML-RPC, или REST). В большинстве случаев не
125                 нужно будет глобально отключать <code>ViewRenderer</code>,
126                 только избирательно в отдельных контроллерах или действиях.
127             </para>
128         </note>
129     </sect2>
131     <sect2 id="zend.controller.action.initialization">
132         <title>Инициализация объекта</title>
134         <para>
135             Несмотря на то, что вы всегда можете переопределить конструктор
136             контроллера действий, мы не рекомендуем делать это.
137             <code>Zend_Controller_Action::__construct()</code>
138             выполняет некоторые важные
139             задачи, такие, как регистрация объектов запроса и ответа, аргументов
140             вызова, переданных из фронт-контроллера. Если необходимо
141             переопределить контроллер, то всегда вызывайте конструктор
142             родительского класса <code>parent::__construct($request, $response,
143             $invokeArgs)</code> в конструкторе подкласса.
144         </para>
146         <para>
147             Более подходящим способом настройки инстанцирования
148             является использование метода <code>init()</code>, который
149             вызывается в конце выполнения <code>__construct()</code>. Например,
150             если вы хотите устанавливать соединение с БД при инстанцировании:
151         </para>
153         <programlisting language="php"><![CDATA[
154 class FooController extends Zend_Controller_Action
156     public function init()
157     {
158         $this->db = Zend_Db::factory('Pdo_Mysql', array(
159             'host'     => 'myhost',
160             'username' => 'user',
161             'password' => 'XXXXXXX',
162             'dbname'   => 'website'
163         ));
164     }
166 ]]></programlisting>
167     </sect2>
169     <sect2 id="zend.controller.action.prepostdispatch">
170         <title>Перехватчики Pre- и Post-Dispatch</title>
172         <para>
173             <classname>Zend_Controller_Action</classname> определяет два метода, которые
174             вызываются до и после требуемого действия,
175             <code>preDispatch()</code> и <code>postDispatch()</code>. Они
176             могут быть полезны в различных случаях - например, проверка
177             аутентификации и списка управления доступом до запуска действия
178             (при вызове метода <code>_forward()</code> в
179             <code>preDispatch()</code> текущее действие будет пропущено) или
180             размещение сгенерированного содержимого в шаблоне боковой части
181             сайта (метод <code>postDispatch()</code>).
182         </para>
183     </sect2>
185     <sect2 id="zend.controller.action.accessors">
186         <title>Аксессоры</title>
188         <para>
189             С объектом контроллера регистрируется несколько объектов
190             и переменных, они имеют свои методы-аксессоры.
191         </para>
193         <itemizedlist>
194             <listitem><para>
195                 <emphasis>Объект запроса</emphasis>: через метод
196                 <code>getRequest()</code> извлекается объект запроса, который
197                 использовался для вызова данного действия.
198             </para></listitem>
200             <listitem>
201                 <para>
202                     <emphasis>Объект ответа</emphasis>:
203                     через метод <code>getResponse()</code> извлекается объект
204                     ответа, объединяющий в себе заголовки и содержимое ответа.
205                     Некоторые типичные вызовы могут выглядеть следующим образом:
206                 </para>
208                 <programlisting language="php"><![CDATA[
209 $this->getResponse()->setHeader('Content-Type', 'text/xml');
210 $this->getResponse()->appendBody($content);
211 ]]></programlisting>
212             </listitem>
214             <listitem>
215                 <para>
216                     <emphasis>Аргументы вызова</emphasis>: фронт-контроллер
217                     может добавлять параметры в маршрутизатор, диспетчер и
218                     контроллер действий. Для их получения используйте
219                     <code>getInvokeArg($key)</code>, можно также извлечь весь список
220                     аргументов, используя метод <code>getInvokeArgs()</code>.
221                 </para>
222             </listitem>
224             <listitem>
225                 <para>
226                     <emphasis>Параметры запроса</emphasis>: Объект запроса
227                     заключает в себе параметры запроса, такие, как значения
228                     _GET, _POST, или пользовательские параметры, определенные в
229                     пути URL. Для их получения используйте
230                     <code>_getParam($key)</code> или
231                     <code>_getAllParams()</code>. Вы можете также установить
232                     параметры запроса, используя метод <code>_setParam()</code>,
233                     это полезно при перенаправлении на другие действия через
234                     метод <code>_forward()</code>.
235                 </para>
237                 <para>
238                     Для определения того, существует ли параметр или нет
239                     (полезно для логического ветвления), используйте
240                     <code>_hasParam($key)</code>.
241                 </para>
243                 <note>
244                     <para>
245                         <code>_getParam()</code> может принимать опциональный
246                         второй аргумент, содержащий значение по умолчанию,
247                         которое используется, если параметр не установлен или
248                         пустой. Его использование устраняет необходимость
249                         вызова <code>_hasParam()</code> до получения значения:
250                     </para>
252                     <programlisting language="php"><![CDATA[
253 // Используется значение по умолчанию 1, если id не установлен
254 $id = $this->_getParam('id', 1);
256 // Вместо:
257 if ($this->_hasParam('id') {
258     $id = $this->_getParam('id');
259 } else {
260     $id = 1;
262 ]]></programlisting>
263                 </note>
264             </listitem>
265         </itemizedlist>
266     </sect2>
268     <sect2 id="zend.controller.action.viewintegration">
269         <title>Интеграция вида</title>
271         <note id="zend.controller.action.viewintegration.viewrenderer">
272             <title>По умолчанию интеграция вида производится через ViewRenderer</title>
274             <para>
275                 Изложенное в этом разделе действительно только в том случае,
276                 если вы явным образом отключили
277                 <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
278                 Иначе вы можете спокойно пропустить этот раздел.
279             </para>
280         </note>
282         <para>
283             <classname>Zend_Controller_Action</classname> предоставляет простейший и
284             гибкий механизм интеграции видов. Два метода осуществляют это:
285             <code>initView()</code> и <code>render()</code>. Первый метод
286             выполняет отложенную загрузку открытого свойства <varname>$view</varname>,
287             второй выполняет рендеринг вида, основываясь на запрошенном в данный
288             момент действии, используя иерархию директорий для определения пути
289             к скрипту.
290         </para>
292         <sect3 id="zend.controller.action.viewintegration.initview">
293             <title>Инициализация вида</title>
295             <para>
296                 <code>initView()</code> инициализирует объект вида.
297                 <code>render()</code> вызывает <code>initView()</code> для
298                 извлечения объекта вида, но этот объект может быть
299                 инициализирован в любое время. По умолчанию
300                 <code>initView()</code> заполняет свойство <varname>$view</varname>
301                 объектом <classname>Zend_View</classname>, но может также использоваться
302                 любой класс, реализующий интерфейс
303                 <classname>Zend_View_Interface</classname>. Если <varname>$view</varname> уже
304                 инициализирован, то просто возвращается это свойство.
305             </para>
307             <para>
308                 Реализация, используемая по умолчанию, делает следующие
309                 предположения по структуре директорий:
310             </para>
312             <programlisting language="php"><![CDATA[
313 applicationOrModule/
314     controllers/
315         IndexController.php
316     views/
317         scripts/
318             index/
319                 index.phtml
320         helpers/
321         filters/
322 ]]></programlisting>
324             <para>
325                 Другими словами, предполагается, что скрипты вида находятся в
326                 поддиректории <code>views/scripts/</code> и поддиректория
327                 <code>views</code> должна содержать родственный функционал того
328                 же уровня (это могут быть помощники, фильтры). Когда
329                 определяется имя и путь к скрипту вида, то в качестве базового
330                 пути используется директория <code>views/scripts/</code>
331                 с директориями, именованными в соответствии с отдельными
332                 контроллерами, что дает иерархию скриптов вида.
333             </para>
334         </sect3>
336         <sect3 id="zend.controller.action.viewintegration.render">
337             <title>Рендеринг видов</title>
339             <para>
340                 <code>render()</code> имеет следующую сигнатуру:
341             </para>
343             <programlisting language="php"><![CDATA[
344 string render(string $action = null,
345               string $name = null,
346               bool $noController = false);
347 ]]></programlisting>
349             <para>
350                 <code>render()</code> рендерит скрипт вида. Если не были
351                 переданы аргументы, то предполагается, что запрашивается скрипт
352                 <code>[controller]/[action].phtml</code> (где
353                 <code>.phtml</code> - значение свойства
354                 <varname>$viewSuffix</varname>). Передача значения для
355                 <varname>$action</varname> вызовет генерацию этого шаблона в
356                 поддиректории <code>[controller]</code>. Для того, чтобы
357                 отменить использование поддиректории <code>[controller]</code>,
358                 передавайте значение true для <varname>$noController</varname>.
359                 Шаблоны рендерятся в объект ответа, если же вы хотите сохранить
360                 результат в
361                 <link linkend="zend.controller.response.namedsegments">именованный
362                 сегмент</link> объекта ответа, то передавайте значение для
363                 <varname>$name</varname>.
364             </para>
366             <note><para>
367                     Поскольку имена контроллера и действия могут содержать
368                     символы-ограничители слов, такие, как '_', '.', и '-', то
369                     <code>render()</code> нормализует их к '-', когда
370                     определяет имя скрипта.
371                     Внутри себя для такой нормализации он использует
372                     ограничители слов и путей для диспетчера. Таким образом,
373                     запрос к <code>/foo.bar/baz-bat</code> приведет к рендерингу
374                     скрипта <code>foo-bar/baz-bat.phtml</code>. Если ваш метод
375                     действия содержит camelCase, то следует иметь в виду, что
376                     при определении имени скрипта вида результатом будут
377                     разделенные '-' слова.
378             </para></note>
380             <para>
381                 Некоторые примеры:
382             </para>
384             <programlisting language="php"><![CDATA[
385 class MyController extends Zend_Controller_Action
387     public function fooAction()
388     {
389         // Рендеринг my/foo.phtml
390         $this->render();
392         // Рендеринг my/bar.phtml
393         $this->render('bar');
395         // Рендеринг baz.phtml
396         $this->render('baz', null, true);
398         // Рендеринг my/login.phtml в сегмент 'form' объекта ответа
399         $this->render('login', 'form');
401         // Рендеринг site.phtml в сегмент 'page' объекта ответа,
402         // при этом не используется поддиректория 'my/'
403         $this->render('site', 'page', true);
404     }
406     public function bazBatAction()
407     {
408         // Рендеринг my/baz-bat.phtml
409         $this->render();
410     }
412 ]]></programlisting>
413         </sect3>
414     </sect2>
416     <sect2 id="zend.controller.action.utilmethods">
417         <title>Сервисные методы</title>
419         <para>
420             Кроме аксессоров и методов интеграции видов,
421             <classname>Zend_Controller_Action</classname> имеет несколько сервисных
422             методов для выполнения распространенных зачач в методах действий
423             (или в методах pre- и post-dispatch).
424         </para>
426         <itemizedlist>
427             <listitem>
428                 <para>
429                     <code>_forward($action, $controller = null, $module = null,
430                     array $params = null)</code>: выполяет другое действие.
431                     Если был вызван в <code>preDispatch()</code>, то
432                     запрошенноое в данный момент
433                     действие будет пропущено в пользу нового. Иначе
434                     действие, запрошенное в _forward(), будет выполнено после
435                     того, как было выполнено текущее действие.
436                 </para>
437             </listitem>
439             <listitem>
440                 <para>
441                     <code>_redirect($url, array $options =
442                         array())</code>: производит перенаправление по другому
443                     адресу. Этот метод принимает URL и опционально набор опций.
444                     По умолчанию он производит перенаправление HTTP 302.
445                 </para>
447                 <para>
448                     Опции могут включать в себя одну или более из следующих:
449                 </para>
451                 <itemizedlist>
452                     <listitem>
453                         <para>
454                             <emphasis>exit:</emphasis> производить или нет выход
455                             после этого. Если установлена, то будет произведены
456                             надлежащее закрытие всех открытых сессий и
457                             перенаправление.
458                         </para>
460                         <para>
461                             Вы можете установить эту опцию глобально в
462                             контроллере, используя аксессор
463                             <code>setRedirectExit()</code>.
464                         </para>
465                     </listitem>
467                     <listitem>
468                         <para>
469                             <emphasis>prependBase:</emphasis> добавлять или нет
470                             базовый URL из объекта запроса в начало данного URL.
471                         </para>
473                         <para>
474                             Вы можете установить эту опцию глобально в
475                             контроллере, используя аксессор
476                             <code>setRedirectPrependBase()</code>.
477                         </para>
478                     </listitem>
480                     <listitem>
481                         <para>
482                             <emphasis>code:</emphasis> какой код HTTP
483                             использовать при перенаправлении. По умолчанию
484                             используется HTTP 302. Могут использоваться любые
485                             коды от 301 до 306.
486                         </para>
488                         <para>
489                             Вы можете установить эту опцию глобально в
490                             контроллере, используя аксессор
491                             <code>setRedirectCode()</code>.
492                         </para>
493                     </listitem>
494                 </itemizedlist>
495             </listitem>
496         </itemizedlist>
497     </sect2>
499     <sect2 id="zend.controller.action.subclassing">
500         <title>Создание подклассов контроллера действий</title>
502         <para>
503             Задумано, что в порядке создания контроллеров действий должны
504             создаваться подклассы от <classname>Zend_Controller_Action</classname>.
505             Как минимум, вам нужно будет определить методы действий, которые
506             может вызывать контроллер.
507         </para>
509         <para>
510             Помимо создания полезного функционала для своих веб-приложений, вы
511             можете также обнаружить, что большинство установок или сервисных
512             методов повторяются в ваших различных контроллерах. В этом случае
513             создание общего базового контроллера, расширяющего
514             <classname>Zend_Controller_Action</classname>, может решить проблему
515             избыточности.
516         </para>
518         <example id="zend.controller.action.subclassing.example-call">
519             <title>Обрабаботка обращений к несуществующим действиям</title>
521             <para>
522                 Если сделан запрос к контроллеру, который содержит в себе
523                 не определенный в контроллере метод действия, то вызывается метод
524                 <code>Zend_Controller_Action::__call()</code>.
525                 <code>__call()</code> является магическим методом для перегрузки
526                 методов в PHP.
527             </para>
529             <para>
530                 По умолчанию этот метод бросает исключение
531                 <classname>Zend_Controller_Action_Exception</classname>, означающее, что
532                 требуемый метод не найден в контроллере. Если требуемый метод
533                 заканчивается строкой 'Action', то предполагается, что было
534                 запрошено действие и оно не существует; такая ошибка приводит к
535                 исключению с кодом 404. В остальных случаях бросается исключение
536                 с кодом 500. Это позволяет легко дифференцировать в обработчике
537                 ошибок случаи, когда страница не найдена, и когда произошла
538                 ошибка приложения.
539             </para>
541             <para>
542                 Например, если вы хотите выводить сообщение об ошибке, то можете
543                 написать нечто подобное:
544             </para>
546             <programlisting language="php"><![CDATA[
547 class MyController extends Zend_Controller_Action
549     public function __call($method, $args)
550     {
551         if ('Action' == substr($method, -6)) {
552             // Если метод действия не найден, то рендерится шаблон ошибки
553             return $this->render('error');
554         }
556         // все другие методы бросают исключение
557         throw new Exception('Invalid method "'
558                             . $method
559                             . '" called',
560                             500);
561     }
563 ]]></programlisting>
565             <para>
566                 Другая возможность состоит в том, что вы можете
567                 производить переход на страницу контроллера по умолчанию:
568             </para>
570             <programlisting language="php"><![CDATA[
571 class MyController extends Zend_Controller_Action
573     public function indexAction()
574     {
575         $this->render();
576     }
578     public function __call($method, $args)
579     {
580         if ('Action' == substr($method, -6)) {
581             // Если метод действия не был найден, то производится
582             // переход к действию index
583             return $this->_forward('index');
584         }
586         // все другие методы бросают исключение
587         throw new Exception('Invalid method "'
588                             . $method
589                             . '" called',
590                             500);
591     }
593 ]]></programlisting>
594         </example>
596         <para>
597             Как и метод <code>__call()</code>, любые аксессоры,
598             сервисные методы, методы инициализации, вида и перехвата, упомянутые
599             ранее в этом разделе, могут быть переопределены для того, чтобы
600             приспособить свои контроллеры под конкретные нужды. Например, если
601             вы храните свои объекты вида в реестре, то можете модифицировать
602             свой метод <code>initView()</code>:
603         </para>
605         <programlisting language="php"><![CDATA[
606 abstract class My_Base_Controller extends Zend_Controller_Action
608     public function initView()
609     {
610         if (null === $this->view) {
611             if (Zend_Registry::isRegistered('view')) {
612                 $this->view = Zend_Registry::get('view');
613             } else {
614                 $this->view = new Zend_View();
615                 $this->view->setBasePath(dirname(__FILE__) . '/../views');
616             }
617         }
619         return $this->view;
620     }
622 ]]></programlisting>
624         <para>
625             Надеемся, из написанного в этом разделе вы смогли увидеть, насколько
626             гибка эта компонента, и как можно заточить ее под нужды своего
627             приложения или сайта.
628         </para>
629     </sect2>
630 </sect1>
631 <!--
632 vim:se ts=4 sw=4 et: