Programmer's Reference Guide

Исключения

Переход с предыдущих версий

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; вы можете изменить правила инфлектора так, чтобы он более не разделял слова в имени действия знаком тире:

    1. $viewRenderer =
    2.     Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    3. $inflector = $viewRenderer->getInflector();
    4. $inflector->setFilterRule(':action', array(
    5.     new Zend_Filter_PregReplace(
    6.         '#[^a-z0-9' . preg_quote(DIRECTORY_SEPARATOR, '#') . ']+#i',
    7.         ''
    8.     ),
    9.     'StringToLower'
    10. ));

    Приведенный выше код изменит инфлектор таким образом, чтобы он более не разделял слова в имени действия знаком тире; вы можете также убрать фильтр 'StringToLower', если хотите, чтобы реальные имена скриптов вида тоже были в формате camelCase.

    Если переименование скриптов вида слишком утомительно или требует много времени, то этот вариант будет наилучшим решением на тот период, пока вы не найдете время на переименование.

  • Менее желательное решение: Вы можете заставить диспетчер принимать имена действий в формате camelCase, установив новый флаг фронт-контроллера 'useCaseSensitiveActions':

    1. $front->setParam('useCaseSensitiveActions', true);

    Это позволит вам использовать camelCase в URL-ах и они будут приводить к запуску тех действий, что и при использовании разделителей слов. Тем не менее, это будет означать, что исходная проблема может повлечь за собой другие; возможно, вам потребуется также использовать описанный выше второй вариант, чтобы все работало наверняка.

    Также заметьте, что использование этого флага приведет к появлению предупреждения (notice) о том, что его использование не рекомендуется.

Переход с 0.9.3 на 1.0.0RC1 и более поздние версии

Основные изменения, появившиеся в 1.0.0RC1 - это добавление включенного по умолчанию плагина ErrorHandler и помощника действий ViewRenderer. Пожалуйста, прочитайте внимательно документацию к ним, чтобы понять, как они работают, и как они могут повлиять на работу ваших приложений.

Плагин ErrorHandler производит в методе postDispatch() проверку на предмет исключений и переход (forwarding) к определенному контроллеру-обработчику исключений. Вы можете отключить его путем установки параметра noErrorHandler во фронт-контроллере:

  1. $front->setParam('noErrorHandler', true);

Помощник действий ViewRenderer автоматизирует добавление вида в контроллеры действий и производит авторендеринг скрипта вида, выбранного по текущему действию. Первая проблема, с которой вы можете встретиться - у вас есть действия, которые не производят рендеринг скриптов вида и не производят переход или перенаправление, поскольку ViewRenderer будет пытаться запустить скрипт вида, выбранного по имени действия.

Есть несколько стратегий, используя которые, вы можете обновить свой код. В краткострочной перспективе решением может быть глобальное отключение ViewRenderer во фронт-контроллере до начала процесса диспетчеризации:

  1. // $front является экземпляром Zend_Controller_Front
  2. $front->setParam('noViewRenderer', true);

Но в долгосрочной перспективе это не лучшее решение, поскольку оно означает, что вам в будущем придется писать больше кода.

Когда вы будете готовы начать использование функционала ViewRenderer, то необходимо проверить некоторые места в коде контроллеров. Первое, просмотрите методы действий (методы, заканчивающиеся на 'Action') и определите, что делает каждый метод. Если не происходит ничего из следующего, то нужно произвести изменения:

  • Вызов $this->render()

  • Вызов $this->_forward()

  • Вызов $this->_redirect()

  • Вызов помощника действий Redirector

Наиболее легким способом будет отключение авторендеринга в данном методе:

  1. $this->_helper->viewRenderer->setNoRender();

Если вы обнаружили, что ни один из методов действий не производит рендеринг, переход или перенаправление, то, скорее всего, нужно поместить эту строку в методы preDispatch() или init():

  1. public function preDispatch()
  2. {
  3.     // отключение авторендеринга скриптов вида
  4.     $this->_helper->viewRenderer->setNoRender()
  5.     // ... еще код ..
  6. }

Если вы вызываете render() и используете определенную соглашением модульную структуру директорий, то нужно изменить свой код так, чтобы использовался авторендеринг:

  • Если производится рендеринг нескольких скриптов вида в одном действии, то не нужно ничего изменять.

  • Если производится простой вызов метода render() без аргументов, то можете удалить соответствующие строки.

  • Если вызывается render() с аргументами и не производится впоследствии каких-либо действий или рендеринга нескольких скриптов вида, то можно заменить эти вызовы на чтение $this->_helper->viewRenderer().

На тот случай, если вы не используете определенную соглашением модульную структуру директорий, есть набор методов для установки базового пути к видам и спецификаций пути ко скрипту, поэтому вы сможете и в этом случае использовать ViewRenderer. Информацию об этих методах вы найдете в документации по ViewRenderer

Если вы используете объект вида из реестра, создали свой объект вида, либо используете другие реализации встроенного, то может потребоваться добавить этот объект в ViewRenderer. Это легко можно сделать в любой момент времени.

  • До начала диспетчеризации экземпляра фронт-контроллера:

    1. // Предполагается, что $view уже определен
    2. $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
    3. Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
  • В любой точке процесса загрузки (bootstrap process):

    1. $viewRenderer =
    2.     Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    3. $viewRenderer->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 не изменилось:

  1. Zend_Controller_Front::run('/path/to/controllers');

Тем не менее, структура директорий была подвергнута пересмотру, некоторые компоненты были удалены, другие добавлены или переименованы. Изменения включают в себя следующее:

  • 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() изменились. Его сигнатура теперь:

    1. final protected function _forward($action,
    2.                                   $controller = null,
    3.                                   $module = null,
    4.                                   array $params = null);

    $action - обязательный аргумент. Если не был определен контроллер, то предполагается, что вызывается действие в текущем контроллере. $module всегда игнорируется, если не определен контроллер. Все переданные в аргументе $params параметры будут добавлены в объект запроса. Если вы не запрашиваете контроллер или модуль, но нужно передать параметры, то просто укажите null на месте соответствующих аргументов.

Переход с 0.2.0 и более ранних версий на 0.6.0

Базовое использование компонент системы MVC не изменилось, следующий код будет корректно выполняться и в версии 0.6.0:

  1. Zend_Controller_Front::run('/path/to/controllers');
  1. /* -- создание маршрутизатора -- */
  2. $router = new Zend_Controller_RewriteRouter();
  3. $router->addRoute('user',
  4.                   'user/:username',
  5.                   array('controller' => 'user', 'action' => 'info')
  6. );
  7.  
  8. /* -- установка его во фронт-контроллере -- */
  9. $ctrl = Zend_Controller_Front::getInstance();
  10. $ctrl->setRouter($router);
  11.  
  12. /* -- установка директории контроллеров и запуск диспетчеризации -- */
  13. $ctrl->setControllerDirectory('/path/to/controllers');
  14. $ctrl->dispatch();

Рекомендуется использовать объект ответа для сбора содержимого и заголовков. Это дает большую гибкость при переключении между разными форматами вывода (например, JSON или XML вместо XHTML) в приложениях. По умолчанию dispatch() будет возвращать ответ, отправляя заголовки и выводя весь контент. Можно также сделать так, чтобы фронт-контроллер возвращал ответ, используя метод returnResponse(), и затем выводить ответ так, как нужно вам. Будущая версия фронт-контроллер может принуждать к использованию объекта ответа посредством буферизации вывода.

Также добавлено много новых функциональных возможностей, расширяющих существующий API, они описаны в документации.

Основные изменения, о которых следует знать, касаются расширения существующих компонент. Наиболее важные из них следующие:

  • Zend_Controller_Front::dispatch() по умолчанию отлавливает все исключения в объекте ответа и не отображает их для предотвращения раскрытия данных о системе. Вы можете переопределить это поведение несколькими способами:

    • Установка throwExceptions() во фронт-контроллере:

      1. $front->throwExceptions(true);
    • Установка renderExceptions() в объекте ответа:

      1. $response->renderExceptions(true);
      2. $front->setResponse($response);
      3. $front->dispatch();
      4.  
      5. // или:
      6. $front->returnResponse(true);
      7. $response = $front->dispatch();
      8. $response->renderExceptions(true);
      9. 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. Эта информация теперь доступна в объекте запроса, и доступ к ней можно получить следующим образом:

      1. // Извлечение имени запрошенного контроллера
      2. // Ранее доступ был через $this->_action->getControllerName().
      3. // Пример ниже использует getRequest(), хотя вы можете обращаться напрямую
      4. // ко свойству $_request; рекомендуется использовать getRequest(), поскольку
      5. // родительский класс может переопределить доступ к объекту запроса.
      6. $controller = $this->getRequest()->getControllerName();
      7.  
      8. // Извлечение имени запрошенного действия
      9. // Ранее доступ был через $this->_action->getActionName().
      10. $action = $this->getRequest()->getActionName();
      11.  
      12. // Извлечение параметров запроса
      13. // Оно не изменилось; _getParams() и _getParam() просто вызывают аналогичные
      14. // методы объекта запроса
      15. $params = $this->_getParams();
      16.  
      17. // запрашивается параметр 'foo', если параметр не найден,
      18. // то используется значение по умолчанию 'default'
      19. $foo = $this->_getParam('foo', 'default');
    • Удален метод noRouteAction(). Подходящим способом обработки несуществующих методов действий будет перенаправление к действию по умолчанию через __call():

      1. public function __call($method, $args)
      2. {
      3.     // Если запрошен несуществующий метод действия, то вызывается метод
      4.     // действия по умолчанию:
      5.     if ('Action' == substr($method, -6)) {
      6.         return $this->defaultAction();
      7.     }
      8.  
      9.     throw new Zend_Controller_Exception('Invalid method called');
      10. }
  • Удален метод Zend_Controller_RewriteRouter::setRewriteBase(). Вместо него используйте Zend_Controller_Front::setBaseUrl() (или Zend_Controller_Request_Http::setBaseUrl(), если используется класс запроса).

  • Zend_Controller_Plugin_Interface был заменен на Zend_Controller_Plugin_Abstract. Все методы теперь принимают и возвращают объект ответа Объект запроса вместо метки диспетчеризации.


Исключения
blog comments powered by Disqus

Select a Version

Languages Available

Components

Search the Manual