1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.controller.migration">
4 <title>Переход с предыдущих версий</title>
7 API компонент системы MVC претерпевал изменения со временем. Если вы
8 начали использование Zend Framework с его ранних версий, то следуйте
9 приведенным ниже рекомендациям по переносу вашего кода на новую
13 <sect2 id="zend.controller.migration.fromoneseventooneeight">
14 <title>Переход с 1.7.x на 1.8.0 и более поздние версии</title>
16 <sect3 id="zend.controller.migration.fromoneseventooneeight.router">
17 <title>Изменения в стандартном маршруте</title>
20 Поскольку в новый стандартный маршрут были добавлены
21 переводимые сегменты, символ <code>@</code> стал
22 специальным символом в начале сегмента маршрута.
23 Для того, чтобы можно было использовать его в статических
24 сегментах, вы должны экранировать его путем добавления второго
25 символа <code>@</code>. То же самое правило теперь применяется
26 и к символу <code>:</code>.
31 <sect2 id="zend.controller.migration.fromonesixtooneseven">
32 <title>Переход с 1.6.x на 1.7.0 и более поздние версии</title>
34 <sect3 id="zend.controller.migration.fromonesixtooneseven.dispatcher">
35 <title>Изменения в интерфейсе диспетчера</title>
38 Пользователи обратили наше внимание на тот факт, что
39 <classname>Zend_Controller_Action_Helper_ViewRenderer</classname>
40 использует не присутствующий в интерфейсе метод из
41 абстрактного класса диспетчера. Мы добавили
42 этот метод в интерфейс диспетчера для того,
43 чтобы гарантировать работу созданного вами диспетчера с
44 классами, входящими в поставку Zend Framework:
49 <code>formatModuleName()</code>: должен принимать
50 необработанное имя контроллера (в том виде, в котором оно
51 хранится в объекте запроса) и преобразовывать его в имя
52 класса контроллера, наследующего от
53 <classname>Zend_Controller_Action</classname>.
59 <sect2 id="zend.controller.migration.fromoneohtoonesix">
60 <title>Переход с 1.5.x на 1.6.0 и более поздние версии</title>
62 <sect3 id="zend.controller.migration.fromoneohtoonesix.dispatcher">
63 <title>Изменения в интерфейсе диспетчера</title>
66 Пользователи обратили наше внимание на тот факт, что
67 <classname>Zend_Controller_Front</classname> и
68 <classname>Zend_Controller_Router_Route_Module</classname> используют
69 методы диспетчера, которые не определены в его интерфейсе.
70 Мы добавили следующие три метода в его интерфейс для того,
71 чтобы гарантировать работу созданного вами диспетчера с
72 классами, входящими в поставку Zend Framework:
77 <code>getDefaultModule()</code>: должен возвращать имя
78 используемого по умолчанию модуля.
82 <code>getDefaultControllerName()</code>: должен возвращать
83 имя используемого по умолчанию контроллера.
87 <code>getDefaultAction()</code>: должен возвращать имя
88 используемого по умолчанию действия.
94 <sect2 id="zend.controller.migration.fromoneohtoonefive">
95 <title>Переход с 1.0.x на 1.5.0 и более поздние версии</title>
98 Хотя основной набор функциональных возможностей остался тем же, и
99 все документированные возможности не претерпели изменений, есть одна
100 <emphasis>недокументированная</emphasis> "возможность", которая была
105 При написании URL-ов, документированным способом написания имен
106 действий в формате camelCase является использование разделителей
107 слов. По умолчанию это '.' или '-', но они могут быть заменены на
108 другие символы путем настройки диспетчера. Диспетчер внутри себя
109 приводит имена действий к нижнему регистру и использует эти
110 разделители слов для "пересборки" имен действий с использованием
111 формата camelCase. Но из-за того, что функции PHP не чувствительны к
112 регистру, вы <emphasis>могли</emphasis> по-прежнему писать URL-ы в
113 формате camelCasе, и результатом был запуск тех же методов
114 действий. Например, 'camel-cased' должен был преобразовываться
115 диспетчером в 'camelCasedAction', а 'camelCased' - в
116 'camelcasedAction', но из-за нечувствительности PHP к регистру имен
117 функций в обоих случаях будет произведен вызов одного и того же
122 Это вызывало проблемы с ViewRenderer при определении имени скрипта
123 вида. Документированный способ состоит в том, что все разделители
124 слов преобразуются в тире, и слова приводятся к нижнему регистру.
125 Это создает семантическую связь между действиями и скриптами видов,
126 а нормализация гарантирует, что скрипты могут быть найдены. Тем не
127 менее, если вызывается действие с именем 'camelCased' и благополучно
128 обработано, то разделитель слов более не присутствует в имени, и
129 ViewRenderer пытается вызвать другой скрипт вида -
130 'camelcased.phtml' вместо 'camel-cased.phtml'.
134 Некоторые разработчики полагались на эту незапланированную
135 "возможность". Тем не менее, некоторые изменения в дереве 1.5.0,
136 привели к тому, что ViewRenderer более не ищет такие пути;
137 семантическая связь теперь усилена. Главное, диспетчер
138 теперь чувствителен к регистру в именах действий. Это значит, что
139 ссылка на действие через URL с использованием формата camelCase
140 не будет приводить к вызову того же метода, что и с использованием
141 разделителей слов (т.е. 'camel-casing').
145 Если получилось, что вы используете эту "возможность", то в имеете
146 несколько вариантов решения:
151 Наилучший вариант: переименуйте ваши скрипты вида. Плюсы:
152 будущая совместимость. Минусы: если вы имеете много скриптов
153 вида, которые полагаются на старое, незапланированное
154 поведение, то вам придется сделать много переименований.
159 Второй лучший вариант: ViewRenderer теперь делегирует
160 определение скриптов вида инфлектору
161 <classname>Zend_Filter_Inflector</classname>; вы можете изменить
162 правила инфлектора так, чтобы он более не разделял слова в
163 имени действия знаком тире:
166 <programlisting language="php"><![CDATA[
168 Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
169 $inflector = $viewRenderer->getInflector();
170 $inflector->setFilterRule(':action', array(
171 new Zend_Filter_PregReplace(
172 '#[^a-z0-9' . preg_quote(DIRECTORY_SEPARATOR, '#') . ']+#i',
180 Приведенный выше код изменит инфлектор таким образом, чтобы
181 он более не разделял слова в имени действия знаком тире; вы
182 можете также убрать фильтр 'StringToLower', если хотите,
183 чтобы реальные имена скриптов вида тоже были в формате
188 Если переименование скриптов вида слишком утомительно или
189 требует много времени, то этот вариант будет наилучшим
190 решением на тот период, пока вы не найдете время на
197 Менее желательное решение: Вы можете заставить диспетчер
198 принимать имена действий в формате camelCase, установив
199 новый флаг фронт-контроллера 'useCaseSensitiveActions':
202 <programlisting language="php"><![CDATA[
203 $front->setParam('useCaseSensitiveActions', true);
207 Это позволит вам использовать camelCase в URL-ах и они будут
208 приводить к запуску тех действий, что и при использовании
209 разделителей слов. Тем не менее, это будет означать, что
210 исходная проблема может повлечь за собой другие; возможно,
211 вам потребуется также использовать описанный выше второй
212 вариант, чтобы все работало наверняка.
216 Также заметьте, что использование этого флага приведет к
217 появлению предупреждения (notice) о том, что его
218 использование не рекомендуется.
224 <sect2 id="zend.controller.migration.fromzeroninethree">
225 <title>Переход с 0.9.3 на 1.0.0RC1 и более поздние версии</title>
228 Основные изменения, появившиеся в 1.0.0RC1 - это добавление
229 включенного по умолчанию плагина
230 <link linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler</link>
231 и помощника действий <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
232 Пожалуйста, прочитайте внимательно документацию к ним, чтобы понять,
233 как они работают, и как они могут повлиять на работу ваших
238 Плагин <code>ErrorHandler</code> производит в методе
239 <code>postDispatch()</code> проверку на предмет исключений и
240 переход (forwarding) к определенному контроллеру-обработчику
241 исключений. Вы можете отключить его путем установки параметра
242 <code>noErrorHandler</code> во фронт-контроллере:
245 <programlisting language="php"><![CDATA[
246 $front->setParam('noErrorHandler', true);
250 Помощник действий <code>ViewRenderer</code> автоматизирует
251 добавление вида в контроллеры действий и производит авторендеринг
252 скрипта вида, выбранного по текущему действию. Первая проблема, с
253 которой вы можете встретиться - у вас есть действия,
254 которые не производят рендеринг скриптов вида и не производят
255 переход или перенаправление, поскольку <code>ViewRenderer</code>
256 будет пытаться запустить скрипт вида, выбранного по имени действия.
260 Есть несколько стратегий, используя которые, вы можете обновить свой
261 код. В краткострочной перспективе решением может быть глобальное
262 отключение <code>ViewRenderer</code> во фронт-контроллере до
263 начала процесса диспетчеризации:
266 <programlisting language="php"><![CDATA[
267 // $front является экземпляром Zend_Controller_Front
268 $front->setParam('noViewRenderer', true);
272 Но в долгосрочной перспективе это не лучшее решение, поскольку
273 оно означает, что вам в будущем придется писать больше кода.
277 Когда вы будете готовы начать использование функционала
278 <code>ViewRenderer</code>, то необходимо проверить некоторые места в
279 коде контроллеров. Первое, просмотрите методы действий (методы,
280 заканчивающиеся на 'Action') и определите, что делает каждый метод.
281 Если не происходит ничего из следующего, то нужно произвести
287 Вызов <varname>$this->render()</varname>
290 Вызов <varname>$this->_forward()</varname>
293 Вызов <varname>$this->_redirect()</varname>
296 Вызов помощника действий <code>Redirector</code>
301 Наиболее легким способом будет отключение авторендеринга в данном
305 <programlisting language="php"><![CDATA[
306 $this->_helper->viewRenderer->setNoRender();
310 Если вы обнаружили, что ни один из методов действий не производит
311 рендеринг, переход или перенаправление, то, скорее всего, нужно
312 поместить эту строку в методы
313 <code>preDispatch()</code> или <code>init()</code>:
316 <programlisting language="php"><![CDATA[
317 public function preDispatch()
319 // отключение авторендеринга скриптов вида
320 $this->_helper->viewRenderer->setNoRender()
326 Если вы вызываете <code>render()</code> и используете
327 <link linkend="zend.controller.modular">определенную соглашением
328 модульную структуру директорий</link>, то нужно
329 изменить свой код так, чтобы использовался авторендеринг:
335 Если производится рендеринг нескольких скриптов вида в
336 одном действии, то не нужно ничего изменять.
341 Если производится простой вызов метода
342 <code>render()</code> без аргументов, то можете удалить
343 соответствующие строки.
348 Если вызывается <code>render()</code> с аргументами и не
349 производится впоследствии каких-либо действий или рендеринга
350 нескольких скриптов вида, то можно заменить эти вызовы на
351 чтение <varname>$this->_helper->viewRenderer()</varname>.
357 На тот случай, если вы не используете определенную соглашением
358 модульную структуру директорий, есть набор методов для
359 установки базового пути к видам и спецификаций пути ко скрипту,
360 поэтому вы сможете и в этом случае использовать
361 <code>ViewRenderer</code>. Информацию об этих методах вы найдете в
362 <link linkend="zend.controller.actionhelpers.viewrenderer">документации
363 по ViewRenderer</link>
367 Если вы используете объект вида из реестра, создали свой объект
368 вида, либо используете другие реализации встроенного, то может
369 потребоваться добавить этот объект в <code>ViewRenderer</code>. Это
370 легко можно сделать в любой момент времени.
376 До начала диспетчеризации экземпляра фронт-контроллера:
379 <programlisting language="php"><![CDATA[
380 // Предполагается, что $view уже определен
381 $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
382 Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
388 В любой точке процесса загрузки (bootstrap process):
391 <programlisting language="php"><![CDATA[
393 Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
394 $viewRenderer->setView($view);
400 Есть много способов модификации <code>ViewRenderer</code>, включая
401 установку других скриптов вида для рендеринга, определение замещений
402 для всех замещаемых элементов пути ко скрипту вида (включая
403 суффикс), выбор именованного сегмента ответа в качестве
404 используемого и др. Если вы не используете определенную соглашением
405 модульную структуру директорий, то можете ассоциировать с
406 <code>ViewRenderer</code> другие спецификации путей.
410 Рекомендуется адаптировать свой код для использования
411 <code>ErrorHandler</code> и <code>ViewRenderer</code>, так как
412 сейчас это лежащий в основе фреймворка функционал.
416 <sect2 id="zend.controller.migration.fromzeroninetwo">
417 <title>Переход с 0.9.2 на 0.9.3 и более поздние версии</title>
420 В версии 0.9.3 были добавлены <link
421 linkend="zend.controller.actionhelpers">помощники действий</link>
423 Это изменение включает в себя удаление перечисленных ниже методов
424 из-за того, что сейчас они инкапсулированы в
425 <link linkend="zend.controller.actionhelpers.redirector">помощнике
426 перенаправлений</link> (redirector action helper):
432 <code>setRedirectCode()</code>; используйте
433 <code>Zend_Controller_Action_Helper_Redirector::setCode()</code>.
438 <code>setRedirectPrependBase()</code>; используйте
439 <code>Zend_Controller_Action_Helper_Redirector::setPrependBase()</code>.
444 <code>setRedirectExit()</code>; используйте
445 <code>Zend_Controller_Action_Helper_Redirector::setExit()</code>.
451 Более подробную информацию о том, как извлекать и работать с
452 объектами действий, читайте в <link
453 linkend="zend.controller.actionhelpers">документации по помощникам
454 действий</link>. Об установке опций перенаправления и альтернативных
455 методах перенаправления читайте в <link
456 linkend="zend.controller.actionhelpers.redirector">документации по
457 помощнику перенаправлений</link>.
461 <sect2 id="zend.controller.migration.fromzerosix">
462 <title>Переход с 0.6.0 на 0.8.0 и более поздние версии</title>
465 Базовое использование компонент MVC не изменилось:
468 <programlisting language="php"><![CDATA[
469 Zend_Controller_Front::run('/path/to/controllers');
473 Тем не менее, структура директорий была подвергнута пересмотру,
474 некоторые компоненты были удалены, другие добавлены или
475 переименованы. Изменения включают в себя следующее:
481 <classname>Zend_Controller_Router</classname> удален в пользу
482 использования Rewrite Router.
488 <classname>Zend_Controller_RewriteRouter</classname> переименован в
489 <classname>Zend_Controller_Router_Rewrite</classname>, теперь это
490 стандартный маршрутизатор, поставляемый с фреймворком.
491 <classname>Zend_Controller_Front</classname> будет использовать его по
492 умолчанию, если не был установлен другой маршрутизатор.
498 Добавлен новый класс маршрута для использования с Rewrite
499 Router - <classname>Zend_Controller_Router_Route_Module</classname>.
500 Он включает в себя маршрут по умолчанию, используемый
501 MVC, и поддерживает <link
502 linkend="zend.controller.modular">модули
509 <classname>Zend_Controller_Router_StaticRoute</classname> переименован
510 в <classname>Zend_Controller_Router_Route_Static</classname>.
516 <classname>Zend_Controller_Dispatcher</classname> переименован в
517 <classname>Zend_Controller_Dispatcher_Standard</classname>.
524 <code>Zend_Controller_Action::_forward()</code> изменились.
525 Его сигнатура теперь:
528 <programlisting language="php"><![CDATA[
529 final protected function _forward($action,
532 array $params = null);
536 <varname>$action</varname> - обязательный аргумент. Если не был
537 определен контроллер, то предполагается, что вызывается
538 действие в текущем контроллере. <varname>$module</varname> всегда
539 игнорируется, если не определен контроллер. Все переданные в
540 аргументе <varname>$params</varname> параметры будут добавлены в
541 объект запроса. Если вы не запрашиваете контроллер или
542 модуль, но нужно передать параметры, то просто укажите null
543 на месте соответствующих аргументов.
549 <sect2 id="zend.controller.migration.fromzerotwo">
550 <title>Переход с 0.2.0 и более ранних версий на 0.6.0</title>
553 Базовое использование компонент системы MVC не изменилось,
554 следующий код будет корректно выполняться и в версии 0.6.0:
557 <programlisting language="php"><![CDATA[
558 Zend_Controller_Front::run('/path/to/controllers');
561 <programlisting language="php"><![CDATA[
562 /* -- создание маршрутизатора -- */
563 $router = new Zend_Controller_RewriteRouter();
564 $router->addRoute('user',
566 array('controller' => 'user', 'action' => 'info')
569 /* -- установка его во фронт-контроллере -- */
570 $ctrl = Zend_Controller_Front::getInstance();
571 $ctrl->setRouter($router);
573 /* -- установка директории контроллеров и запуск диспетчеризации -- */
574 $ctrl->setControllerDirectory('/path/to/controllers');
579 Рекомендуется использовать объект ответа для сбора содержимого и
580 заголовков. Это дает большую гибкость при переключении
581 между разными форматами вывода (например, JSON или XML вместо XHTML)
582 в приложениях. По умолчанию <code>dispatch()</code> будет возвращать
583 ответ, отправляя заголовки и выводя весь контент. Можно также
584 сделать так, чтобы фронт-контроллер возвращал ответ, используя метод
585 <code>returnResponse()</code>, и затем выводить ответ так, как нужно
586 вам. Будущая версия фронт-контроллер может принуждать к
587 использованию объекта ответа посредством буферизации вывода.
591 Также добавлено много новых функциональных возможностей,
592 расширяющих существующий API, они описаны в документации.
596 Основные изменения, о которых следует знать, касаются расширения
597 существующих компонент. Наиболее важные из них следующие:
603 <code>Zend_Controller_Front::dispatch()</code> по умолчанию
604 отлавливает все исключения в объекте ответа и не отображает
605 их для предотвращения раскрытия данных о системе. Вы
606 можете переопределить это поведение несколькими способами:
612 Установка <code>throwExceptions()</code> во
615 <programlisting language="php"><![CDATA[
616 $front->throwExceptions(true);
622 Установка <code>renderExceptions()</code> в объекте
625 <programlisting language="php"><![CDATA[
626 $response->renderExceptions(true);
627 $front->setResponse($response);
631 $front->returnResponse(true);
632 $response = $front->dispatch();
633 $response->renderExceptions(true);
641 <code>Zend_Controller_Dispatcher_Interface::dispatch()</code>
642 теперь принимает и возвращает объект запроса
643 <xref linkend="zend.controller.request" />
644 вместо метки <classname>Zend_Controller_Dispatcher_Token</classname>.
648 <code>Zend_Controller_Router_Interface::route()</code>
649 теперь принимает и возвращает объект ответа
650 <xref linkend="zend.controller.request" />
651 вместо метки <classname>Zend_Controller_Dispatcher_Token</classname>
656 Изменения <classname>Zend_Controller_Action</classname> включают в
662 Его конструктор теперь включает в себя три аргумента:
663 <code>Zend_Controller_Request_Abstract $request</code>,
664 <code>Zend_Controller_Response_Abstract $response</code>
665 и <code>array $params</code> (необязательный).
666 <code>Zend_Controller_Action::__construct()</code>
667 использует их для установки запроса, ответа и свойств
668 объекта (аргументов вызова); переопределяя конструктор,
669 вам следует реализовать те же операции.
670 Но лучше использовать метод <code>init()</code> для
671 выполнения любого конфигурирования экземпляра класса,
672 так как этот метод вызывается в конце конструктора.
676 Метод <code>run()</code> теперь не определен с ключевым
677 словом <code>final</code>, но он также и не используется
678 во фронт-контроллере; единственным его назначением
679 является использование класса как контроллера страниц.
680 Теперь он принимает два необязательных аргумента –
681 <code>Zend_Controller_Request_Abstract $request</code>
682 и <code>Zend_Controller_Response_Abstract $response</code>.
686 <code>indexAction()</code> уже не обязателен для
687 определения, но все же рекомендуется определять его в
688 качестве действия по умолчанию. Это позволяет
689 использовать RewriteRouter и контроллеры действий для
690 указания других используемых по умолчанию методов
695 <code>__call()</code> должен переопределяться для
696 автоматической обработки вызовов действий, не
697 определенных в классе контроллера.
701 Метод <code>_redirect()</code> теперь принимает второй
702 необязательный аргумент, HTTP-код, который должен
703 возвращаться при перенаправлении, и третий
704 необязательный аргумент, <varname>$prependBase</varname>,
705 который указывает, что базовый URL, зарегистрированный в
706 объекте запроса, должен предшествовать URL, переданному
712 Свойство <code>_action</code> больще не
713 устанавливается. Это свойство было объектом класса
714 <classname>Zend_Controller_Dispatcher_Token</classname>,
715 которй больше не существует в текущем воплощении.
716 Единственным назначением метки (token) было
717 предоставление информации о запрошенных контроллере,
718 действии и параметрах URL. Эта информация теперь
719 доступна в объекте запроса, и доступ к ней можно
720 получить следующим образом:
723 <programlisting language="php"><![CDATA[
724 // Извлечение имени запрошенного контроллера
725 // Ранее доступ был через $this->_action->getControllerName().
726 // Пример ниже использует getRequest(), хотя вы можете обращаться напрямую
727 // ко свойству $_request; рекомендуется использовать getRequest(), поскольку
728 // родительский класс может переопределить доступ к объекту запроса.
729 $controller = $this->getRequest()->getControllerName();
731 // Извлечение имени запрошенного действия
732 // Ранее доступ был через $this->_action->getActionName().
733 $action = $this->getRequest()->getActionName();
735 // Извлечение параметров запроса
736 // Оно не изменилось; _getParams() и _getParam() просто вызывают аналогичные
737 // методы объекта запроса
738 $params = $this->_getParams();
740 // запрашивается параметр 'foo', если параметр не найден,
741 // то используется значение по умолчанию 'default'
742 $foo = $this->_getParam('foo', 'default');
748 Удален метод <code>noRouteAction()</code>.
749 Подходящим способом обработки несуществующих методов
750 действий будет перенаправление к действию по
751 умолчанию через <code>__call()</code>:
754 <programlisting language="php"><![CDATA[
755 public function __call($method, $args)
757 // Если запрошен несуществующий метод действия, то вызывается метод
758 // действия по умолчанию:
759 if ('Action' == substr($method, -6)) {
760 return $this->defaultAction();
763 throw new Zend_Controller_Exception('Invalid method called');
772 <code>Zend_Controller_RewriteRouter::setRewriteBase()</code>.
773 Вместо него используйте
774 <code>Zend_Controller_Front::setBaseUrl()</code> (или
775 <code>Zend_Controller_Request_Http::setBaseUrl()</code>,
776 если используется класс запроса).
780 <classname>Zend_Controller_Plugin_Interface</classname> был заменен на
781 <classname>Zend_Controller_Plugin_Abstract</classname>. Все методы теперь
782 принимают и возвращают объект ответа
783 <xref linkend="zend.controller.request" /> вместо метки