Переход с предыдущих версий API компонент системы MVC претерпевал изменения со временем. Если вы начали использование Zend Framework с его ранних версий, то следуйте приведенным ниже рекомендациям по переносу вашего кода на новую архитектуру. Переход с 1.7.x на 1.8.0 и более поздние версии Изменения в стандартном маршруте Поскольку в новый стандартный маршрут были добавлены переводимые сегменты, символ @ стал специальным символом в начале сегмента маршрута. Для того, чтобы можно было использовать его в статических сегментах, вы должны экранировать его путем добавления второго символа @. То же самое правило теперь применяется и к символу :. Переход с 1.6.x на 1.7.0 и более поздние версии Изменения в интерфейсе диспетчера Пользователи обратили наше внимание на тот факт, что Zend_Controller_Action_Helper_ViewRenderer использует не присутствующий в интерфейсе метод из абстрактного класса диспетчера. Мы добавили этот метод в интерфейс диспетчера для того, чтобы гарантировать работу созданного вами диспетчера с классами, входящими в поставку Zend Framework: formatModuleName(): должен принимать необработанное имя контроллера (в том виде, в котором оно хранится в объекте запроса) и преобразовывать его в имя класса контроллера, наследующего от Zend_Controller_Action. Переход с 1.5.x на 1.6.0 и более поздние версии Изменения в интерфейсе диспетчера Пользователи обратили наше внимание на тот факт, что Zend_Controller_Front и Zend_Controller_Router_Route_Module используют методы диспетчера, которые не определены в его интерфейсе. Мы добавили следующие три метода в его интерфейс для того, чтобы гарантировать работу созданного вами диспетчера с классами, входящими в поставку Zend Framework: getDefaultModule(): должен возвращать имя используемого по умолчанию модуля. getDefaultControllerName(): должен возвращать имя используемого по умолчанию контроллера. getDefaultAction(): должен возвращать имя используемого по умолчанию действия. Переход с 1.0.x на 1.5.0 и более поздние версии Хотя основной набор функциональных возможностей остался тем же, и все документированные возможности не претерпели изменений, есть одна недокументированная "возможность", которая была изменена. При написании URL-ов, документированным способом написания имен действий в формате camelCase является использование разделителей слов. По умолчанию это '.' или '-', но они могут быть заменены на другие символы путем настройки диспетчера. Диспетчер внутри себя приводит имена действий к нижнему регистру и использует эти разделители слов для "пересборки" имен действий с использованием формата camelCase. Но из-за того, что функции PHP не чувствительны к регистру, вы могли по-прежнему писать URL-ы в формате camelCasе, и результатом был запуск тех же методов действий. Например, 'camel-cased' должен был преобразовываться диспетчером в 'camelCasedAction', а 'camelCased' - в 'camelcasedAction', но из-за нечувствительности PHP к регистру имен функций в обоих случаях будет произведен вызов одного и того же метода. Это вызывало проблемы с ViewRenderer при определении имени скрипта вида. Документированный способ состоит в том, что все разделители слов преобразуются в тире, и слова приводятся к нижнему регистру. Это создает семантическую связь между действиями и скриптами видов, а нормализация гарантирует, что скрипты могут быть найдены. Тем не менее, если вызывается действие с именем 'camelCased' и благополучно обработано, то разделитель слов более не присутствует в имени, и ViewRenderer пытается вызвать другой скрипт вида - 'camelcased.phtml' вместо 'camel-cased.phtml'. Некоторые разработчики полагались на эту незапланированную "возможность". Тем не менее, некоторые изменения в дереве 1.5.0, привели к тому, что ViewRenderer более не ищет такие пути; семантическая связь теперь усилена. Главное, диспетчер теперь чувствителен к регистру в именах действий. Это значит, что ссылка на действие через URL с использованием формата camelCase не будет приводить к вызову того же метода, что и с использованием разделителей слов (т.е. 'camel-casing'). Если получилось, что вы используете эту "возможность", то в имеете несколько вариантов решения: Наилучший вариант: переименуйте ваши скрипты вида. Плюсы: будущая совместимость. Минусы: если вы имеете много скриптов вида, которые полагаются на старое, незапланированное поведение, то вам придется сделать много переименований. Второй лучший вариант: ViewRenderer теперь делегирует определение скриптов вида инфлектору Zend_Filter_Inflector; вы можете изменить правила инфлектора так, чтобы он более не разделял слова в имени действия знаком тире: getInflector(); $inflector->setFilterRule(':action', array( new Zend_Filter_PregReplace( '#[^a-z0-9' . preg_quote(DIRECTORY_SEPARATOR, '#') . ']+#i', '' ), 'StringToLower' )); ]]> Приведенный выше код изменит инфлектор таким образом, чтобы он более не разделял слова в имени действия знаком тире; вы можете также убрать фильтр 'StringToLower', если хотите, чтобы реальные имена скриптов вида тоже были в формате camelCase. Если переименование скриптов вида слишком утомительно или требует много времени, то этот вариант будет наилучшим решением на тот период, пока вы не найдете время на переименование. Менее желательное решение: Вы можете заставить диспетчер принимать имена действий в формате camelCase, установив новый флаг фронт-контроллера 'useCaseSensitiveActions': setParam('useCaseSensitiveActions', true); ]]> Это позволит вам использовать camelCase в URL-ах и они будут приводить к запуску тех действий, что и при использовании разделителей слов. Тем не менее, это будет означать, что исходная проблема может повлечь за собой другие; возможно, вам потребуется также использовать описанный выше второй вариант, чтобы все работало наверняка. Также заметьте, что использование этого флага приведет к появлению предупреждения (notice) о том, что его использование не рекомендуется. Переход с 0.9.3 на 1.0.0RC1 и более поздние версии Основные изменения, появившиеся в 1.0.0RC1 - это добавление включенного по умолчанию плагина ErrorHandler и помощника действий ViewRenderer. Пожалуйста, прочитайте внимательно документацию к ним, чтобы понять, как они работают, и как они могут повлиять на работу ваших приложений. Плагин ErrorHandler производит в методе postDispatch() проверку на предмет исключений и переход (forwarding) к определенному контроллеру-обработчику исключений. Вы можете отключить его путем установки параметра noErrorHandler во фронт-контроллере: setParam('noErrorHandler', true); ]]> Помощник действий ViewRenderer автоматизирует добавление вида в контроллеры действий и производит авторендеринг скрипта вида, выбранного по текущему действию. Первая проблема, с которой вы можете встретиться - у вас есть действия, которые не производят рендеринг скриптов вида и не производят переход или перенаправление, поскольку ViewRenderer будет пытаться запустить скрипт вида, выбранного по имени действия. Есть несколько стратегий, используя которые, вы можете обновить свой код. В краткострочной перспективе решением может быть глобальное отключение ViewRenderer во фронт-контроллере до начала процесса диспетчеризации: setParam('noViewRenderer', true); ]]> Но в долгосрочной перспективе это не лучшее решение, поскольку оно означает, что вам в будущем придется писать больше кода. Когда вы будете готовы начать использование функционала ViewRenderer, то необходимо проверить некоторые места в коде контроллеров. Первое, просмотрите методы действий (методы, заканчивающиеся на 'Action') и определите, что делает каждый метод. Если не происходит ничего из следующего, то нужно произвести изменения: Вызов $this->render() Вызов $this->_forward() Вызов $this->_redirect() Вызов помощника действий Redirector Наиболее легким способом будет отключение авторендеринга в данном методе: _helper->viewRenderer->setNoRender(); ]]> Если вы обнаружили, что ни один из методов действий не производит рендеринг, переход или перенаправление, то, скорее всего, нужно поместить эту строку в методы preDispatch() или init(): _helper->viewRenderer->setNoRender() // ... еще код .. } ]]> Если вы вызываете render() и используете определенную соглашением модульную структуру директорий, то нужно изменить свой код так, чтобы использовался авторендеринг: Если производится рендеринг нескольких скриптов вида в одном действии, то не нужно ничего изменять. Если производится простой вызов метода render() без аргументов, то можете удалить соответствующие строки. Если вызывается render() с аргументами и не производится впоследствии каких-либо действий или рендеринга нескольких скриптов вида, то можно заменить эти вызовы на чтение $this->_helper->viewRenderer(). На тот случай, если вы не используете определенную соглашением модульную структуру директорий, есть набор методов для установки базового пути к видам и спецификаций пути ко скрипту, поэтому вы сможете и в этом случае использовать ViewRenderer. Информацию об этих методах вы найдете в документации по ViewRenderer Если вы используете объект вида из реестра, создали свой объект вида, либо используете другие реализации встроенного, то может потребоваться добавить этот объект в ViewRenderer. Это легко можно сделать в любой момент времени. До начала диспетчеризации экземпляра фронт-контроллера: В любой точке процесса загрузки (bootstrap process): setView($view); ]]> Есть много способов модификации ViewRenderer, включая установку других скриптов вида для рендеринга, определение замещений для всех замещаемых элементов пути ко скрипту вида (включая суффикс), выбор именованного сегмента ответа в качестве используемого и др. Если вы не используете определенную соглашением модульную структуру директорий, то можете ассоциировать с ViewRenderer другие спецификации путей. Рекомендуется адаптировать свой код для использования ErrorHandler и ViewRenderer, так как сейчас это лежащий в основе фреймворка функционал. Переход с 0.9.2 на 0.9.3 и более поздние версии В версии 0.9.3 были добавлены помощники действий (action helpers). Это изменение включает в себя удаление перечисленных ниже методов из-за того, что сейчас они инкапсулированы в помощнике перенаправлений (redirector action helper): setRedirectCode(); используйте Zend_Controller_Action_Helper_Redirector::setCode(). setRedirectPrependBase(); используйте Zend_Controller_Action_Helper_Redirector::setPrependBase(). setRedirectExit(); используйте Zend_Controller_Action_Helper_Redirector::setExit(). Более подробную информацию о том, как извлекать и работать с объектами действий, читайте в документации по помощникам действий. Об установке опций перенаправления и альтернативных методах перенаправления читайте в документации по помощнику перенаправлений. Переход с 0.6.0 на 0.8.0 и более поздние версии Базовое использование компонент MVC не изменилось: Тем не менее, структура директорий была подвергнута пересмотру, некоторые компоненты были удалены, другие добавлены или переименованы. Изменения включают в себя следующее: Zend_Controller_Router удален в пользу использования Rewrite Router. Zend_Controller_RewriteRouter переименован в Zend_Controller_Router_Rewrite, теперь это стандартный маршрутизатор, поставляемый с фреймворком. Zend_Controller_Front будет использовать его по умолчанию, если не был установлен другой маршрутизатор. Добавлен новый класс маршрута для использования с Rewrite Router - Zend_Controller_Router_Route_Module. Он включает в себя маршрут по умолчанию, используемый MVC, и поддерживает модули контроллеров. Zend_Controller_Router_StaticRoute переименован в Zend_Controller_Router_Route_Static. Zend_Controller_Dispatcher переименован в Zend_Controller_Dispatcher_Standard. Аргументы метода Zend_Controller_Action::_forward() изменились. Его сигнатура теперь: $action - обязательный аргумент. Если не был определен контроллер, то предполагается, что вызывается действие в текущем контроллере. $module всегда игнорируется, если не определен контроллер. Все переданные в аргументе $params параметры будут добавлены в объект запроса. Если вы не запрашиваете контроллер или модуль, но нужно передать параметры, то просто укажите null на месте соответствующих аргументов. Переход с 0.2.0 и более ранних версий на 0.6.0 Базовое использование компонент системы MVC не изменилось, следующий код будет корректно выполняться и в версии 0.6.0: addRoute('user', 'user/:username', array('controller' => 'user', 'action' => 'info') ); /* -- установка его во фронт-контроллере -- */ $ctrl = Zend_Controller_Front::getInstance(); $ctrl->setRouter($router); /* -- установка директории контроллеров и запуск диспетчеризации -- */ $ctrl->setControllerDirectory('/path/to/controllers'); $ctrl->dispatch(); ]]> Рекомендуется использовать объект ответа для сбора содержимого и заголовков. Это дает большую гибкость при переключении между разными форматами вывода (например, JSON или XML вместо XHTML) в приложениях. По умолчанию dispatch() будет возвращать ответ, отправляя заголовки и выводя весь контент. Можно также сделать так, чтобы фронт-контроллер возвращал ответ, используя метод returnResponse(), и затем выводить ответ так, как нужно вам. Будущая версия фронт-контроллер может принуждать к использованию объекта ответа посредством буферизации вывода. Также добавлено много новых функциональных возможностей, расширяющих существующий API, они описаны в документации. Основные изменения, о которых следует знать, касаются расширения существующих компонент. Наиболее важные из них следующие: Zend_Controller_Front::dispatch() по умолчанию отлавливает все исключения в объекте ответа и не отображает их для предотвращения раскрытия данных о системе. Вы можете переопределить это поведение несколькими способами: Установка throwExceptions() во фронт-контроллере: throwExceptions(true); ]]> Установка renderExceptions() в объекте ответа: renderExceptions(true); $front->setResponse($response); $front->dispatch(); // или: $front->returnResponse(true); $response = $front->dispatch(); $response->renderExceptions(true); echo $response; ]]> Zend_Controller_Dispatcher_Interface::dispatch() теперь принимает и возвращает объект запроса вместо метки Zend_Controller_Dispatcher_Token. Zend_Controller_Router_Interface::route() теперь принимает и возвращает объект ответа вместо метки Zend_Controller_Dispatcher_Token Изменения Zend_Controller_Action включают в себя следующее: Его конструктор теперь включает в себя три аргумента: Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response и array $params (необязательный). Zend_Controller_Action::__construct() использует их для установки запроса, ответа и свойств объекта (аргументов вызова); переопределяя конструктор, вам следует реализовать те же операции. Но лучше использовать метод init() для выполнения любого конфигурирования экземпляра класса, так как этот метод вызывается в конце конструктора. Метод run() теперь не определен с ключевым словом final, но он также и не используется во фронт-контроллере; единственным его назначением является использование класса как контроллера страниц. Теперь он принимает два необязательных аргумента – Zend_Controller_Request_Abstract $request и Zend_Controller_Response_Abstract $response. indexAction() уже не обязателен для определения, но все же рекомендуется определять его в качестве действия по умолчанию. Это позволяет использовать RewriteRouter и контроллеры действий для указания других используемых по умолчанию методов действий. __call() должен переопределяться для автоматической обработки вызовов действий, не определенных в классе контроллера. Метод _redirect() теперь принимает второй необязательный аргумент, HTTP-код, который должен возвращаться при перенаправлении, и третий необязательный аргумент, $prependBase, который указывает, что базовый URL, зарегистрированный в объекте запроса, должен предшествовать URL, переданному в первом аргументе. Свойство _action больще не устанавливается. Это свойство было объектом класса Zend_Controller_Dispatcher_Token, которй больше не существует в текущем воплощении. Единственным назначением метки (token) было предоставление информации о запрошенных контроллере, действии и параметрах URL. Эта информация теперь доступна в объекте запроса, и доступ к ней можно получить следующим образом: _action->getControllerName(). // Пример ниже использует getRequest(), хотя вы можете обращаться напрямую // ко свойству $_request; рекомендуется использовать getRequest(), поскольку // родительский класс может переопределить доступ к объекту запроса. $controller = $this->getRequest()->getControllerName(); // Извлечение имени запрошенного действия // Ранее доступ был через $this->_action->getActionName(). $action = $this->getRequest()->getActionName(); // Извлечение параметров запроса // Оно не изменилось; _getParams() и _getParam() просто вызывают аналогичные // методы объекта запроса $params = $this->_getParams(); // запрашивается параметр 'foo', если параметр не найден, // то используется значение по умолчанию 'default' $foo = $this->_getParam('foo', 'default'); ]]> Удален метод noRouteAction(). Подходящим способом обработки несуществующих методов действий будет перенаправление к действию по умолчанию через __call(): defaultAction(); } throw new Zend_Controller_Exception('Invalid method called'); } ]]> Удален метод Zend_Controller_RewriteRouter::setRewriteBase(). Вместо него используйте Zend_Controller_Front::setBaseUrl() (или Zend_Controller_Request_Http::setBaseUrl(), если используется класс запроса). Zend_Controller_Plugin_Interface был заменен на Zend_Controller_Plugin_Abstract. Все методы теперь принимают и возвращают объект ответа вместо метки диспетчеризации.