Programmer's Reference Guide
| Диспетчер |
Контроллеры действий
Введение
Zend_Controller_Action - абстрактный класс, который можно использовать для реализации контроллеров действий для последующего их использования с фронт-контроллером при разработке сайта, основанного на паттерне Model-View-Controller (MVC).
Для того, чтобы использовать Zend_Controller_Action, нужно создать его подкласс в своей действующей директории контроллеров (или расширить его для создания своего базового класса контроллеров действий). Работа с ним в основном сводится к созданию его подкласса и написании методов действий, соответствующих различным действиям, которые должен обрабатывать этот контроллер. Маршрутизатор и диспетчер компоненты Zend_Controller будут считать за методы действий все методы в классе контроллера с именем, заканчивающимся на 'Action'.
Для примера предположим, что ваш класс определен следующим образом:
- class FooController extends Zend_Controller_Action
- {
- public function barAction()
- {
- // делает что-нибудь
- }
- public function bazAction()
- {
- // делает что-нибудь
- }
- }
Приведенный выше класс FooController (контроллер
foo) определяет два действия - bar и
baz.
Класс может быть дополнен инициализирующим методом, методом действия по умолчанию (если не был вызван метод, либо вызван несуществующий метод), перехватчиками pre- и post-dispatch и различными вспомогательными методами. Этот раздел служит обзором функционала контроллера действий.
Замечание: Поведение по умолчанию
По умолчанию фронт-контроллер активирует помощника действий ViewRenderer. Этот помощник обеспечивает добавление объекта вида в контроллер и автоматический рендеринг видов. Вы можете отключить его в своем контроллере действия, используя один из следующих методов:
class FooController extends Zend_Controller_Action { public function init() { // Локально, только для данного контроллера: $this->_invokeArgs['noViewRenderer'] = true; // Глобально: $this->_helper->removeHelper('viewRenderer'); // Тоже глобально, но должен использоваться вместе // с локальной версией для того, чтобы распространить // действие на данный контроллер: Zend_Controller_Front::getInstance() ->setParam('noViewRenderer', true); } }initView(),getViewScript(),render()иrenderScript()служат посредниками дляViewRenderer, пока этот помощник находится в брокере помощников и не установлен флагnoViewRenderer.
Вы можете также отключить рендеринг для отдельного вида посредством установки флагаnoRenderвViewRenderer:
Основные причины для отключения
class FooController extends Zend_Controller_Action { public function barAction() { // отключение авторендеринга для этого действия: $this->_helper->viewRenderer->setNoRender(); } }ViewRenderer- вам просто не нужен объект вида или если вы не производите рендеринг через скрипты вида (например, когда используется контроллер действий для обслуживания протоколов веб-сервисов, таких, как SOAP, XML-RPC, или REST). В большинстве случаев не нужно будет глобально отключатьViewRenderer, только избирательно в отдельных контроллерах или действиях.
Инициализация объекта
Несмотря на то, что вы всегда можете переопределить конструктор
контроллера действий, мы не рекомендуем делать это.
Zend_Controller_Action::__construct()
выполняет некоторые важные
задачи, такие, как регистрация объектов запроса и ответа, аргументов
вызова, переданных из фронт-контроллера. Если необходимо
переопределить контроллер, то всегда вызывайте конструктор
родительского класса parent::__construct($request, $response,
$invokeArgs) в конструкторе подкласса.
Более подходящим способом настройки инстанцирования
является использование метода init(), который
вызывается в конце выполнения __construct(). Например,
если вы хотите устанавливать соединение с БД при инстанцировании:
- class FooController extends Zend_Controller_Action
- {
- public function init()
- {
- 'host' => 'myhost',
- 'username' => 'user',
- 'password' => 'XXXXXXX',
- 'dbname' => 'website'
- ));
- }
- }
Перехватчики Pre- и Post-Dispatch
Zend_Controller_Action определяет два метода, которые
вызываются до и после требуемого действия,
preDispatch() и postDispatch(). Они
могут быть полезны в различных случаях - например, проверка
аутентификации и списка управления доступом до запуска действия
(при вызове метода _forward() в
preDispatch() текущее действие будет пропущено) или
размещение сгенерированного содержимого в шаблоне боковой части
сайта (метод postDispatch()).
Аксессоры
С объектом контроллера регистрируется несколько объектов и переменных, они имеют свои методы-аксессоры.
Объект запроса: через метод
getRequest()извлекается объект запроса, который использовался для вызова данного действия.-
Объект ответа: через метод
getResponse()извлекается объект ответа, объединяющий в себе заголовки и содержимое ответа. Некоторые типичные вызовы могут выглядеть следующим образом:- $this->getResponse()->setHeader('Content-Type', 'text/xml');
- $this->getResponse()->appendBody($content);
-
Аргументы вызова: фронт-контроллер может добавлять параметры в маршрутизатор, диспетчер и контроллер действий. Для их получения используйте
getInvokeArg($key), можно также извлечь весь список аргументов, используя методgetInvokeArgs(). -
Параметры запроса: Объект запроса заключает в себе параметры запроса, такие, как значения _GET, _POST, или пользовательские параметры, определенные в пути URL. Для их получения используйте
_getParam($key)или_getAllParams(). Вы можете также установить параметры запроса, используя метод_setParam(), это полезно при перенаправлении на другие действия через метод_forward().Для определения того, существует ли параметр или нет (полезно для логического ветвления), используйте
_hasParam($key).Замечание:
_getParam()может принимать опциональный второй аргумент, содержащий значение по умолчанию, которое используется, если параметр не установлен или пустой. Его использование устраняет необходимость вызова_hasParam()до получения значения:
- // Используется значение по умолчанию 1, если id не установлен
- $id = $this->_getParam('id', 1);
- // Вместо:
- if ($this->_hasParam('id') {
- $id = $this->_getParam('id');
- } else {
- $id = 1;
- }
Интеграция вида
Замечание: По умолчанию интеграция вида производится через ViewRenderer
Изложенное в этом разделе действительно только в том случае, если вы явным образом отключили ViewRenderer. Иначе вы можете спокойно пропустить этот раздел.
Zend_Controller_Action предоставляет простейший и
гибкий механизм интеграции видов. Два метода осуществляют это:
initView() и render(). Первый метод
выполняет отложенную загрузку открытого свойства $view,
второй выполняет рендеринг вида, основываясь на запрошенном в данный
момент действии, используя иерархию директорий для определения пути
к скрипту.
Инициализация вида
initView() инициализирует объект вида.
render() вызывает initView() для
извлечения объекта вида, но этот объект может быть
инициализирован в любое время. По умолчанию
initView() заполняет свойство $view
объектом Zend_View, но может также использоваться
любой класс, реализующий интерфейс
Zend_View_Interface. Если $view уже
инициализирован, то просто возвращается это свойство.
Реализация, используемая по умолчанию, делает следующие предположения по структуре директорий:
- applicationOrModule/
- controllers/
- IndexController.php
- views/
- scripts/
- index/
- index.phtml
- helpers/
- filters/
Другими словами, предполагается, что скрипты вида находятся в
поддиректории views/scripts/ и поддиректория
views должна содержать родственный функционал того
же уровня (это могут быть помощники, фильтры). Когда
определяется имя и путь к скрипту вида, то в качестве базового
пути используется директория views/scripts/
с директориями, именованными в соответствии с отдельными
контроллерами, что дает иерархию скриптов вида.
Рендеринг видов
render() имеет следующую сигнатуру:
- string render(string $action = null,
- string $name = null,
- bool $noController = false);
render() рендерит скрипт вида. Если не были
переданы аргументы, то предполагается, что запрашивается скрипт
[controller]/[action].phtml (где
.phtml - значение свойства
$viewSuffix). Передача значения для
$action вызовет генерацию этого шаблона в
поддиректории [controller]. Для того, чтобы
отменить использование поддиректории [controller],
передавайте значение true для $noController.
Шаблоны рендерятся в объект ответа, если же вы хотите сохранить
результат в
именованный
сегмент объекта ответа, то передавайте значение для
$name.
Замечание: Поскольку имена контроллера и действия могут содержать символы-ограничители слов, такие, как '_', '.', и '-', то
render()нормализует их к '-', когда определяет имя скрипта. Внутри себя для такой нормализации он использует ограничители слов и путей для диспетчера. Таким образом, запрос к/foo.bar/baz-batприведет к рендерингу скриптаfoo-bar/baz-bat.phtml. Если ваш метод действия содержит camelCase, то следует иметь в виду, что при определении имени скрипта вида результатом будут разделенные '-' слова.
Некоторые примеры:
- class MyController extends Zend_Controller_Action
- {
- public function fooAction()
- {
- // Рендеринг my/foo.phtml
- $this->render();
- // Рендеринг my/bar.phtml
- $this->render('bar');
- // Рендеринг baz.phtml
- $this->render('baz', null, true);
- // Рендеринг my/login.phtml в сегмент 'form' объекта ответа
- $this->render('login', 'form');
- // Рендеринг site.phtml в сегмент 'page' объекта ответа,
- // при этом не используется поддиректория 'my/'
- $this->render('site', 'page', true);
- }
- public function bazBatAction()
- {
- // Рендеринг my/baz-bat.phtml
- $this->render();
- }
- }
Сервисные методы
Кроме аксессоров и методов интеграции видов, Zend_Controller_Action имеет несколько сервисных методов для выполнения распространенных зачач в методах действий (или в методах pre- и post-dispatch).
-
_forward($action, $controller = null, $module = null, array $params = null): выполяет другое действие. Если был вызван вpreDispatch(), то запрошенноое в данный момент действие будет пропущено в пользу нового. Иначе действие, запрошенное в _forward(), будет выполнено после того, как было выполнено текущее действие. -
_redirect($url, array $options = array()): производит перенаправление по другому адресу. Этот метод принимает URL и опционально набор опций. По умолчанию он производит перенаправление HTTP 302.Опции могут включать в себя одну или более из следующих:
-
exit: производить или нет выход после этого. Если установлена, то будет произведены надлежащее закрытие всех открытых сессий и перенаправление.
Вы можете установить эту опцию глобально в контроллере, используя аксессор
setRedirectExit(). -
prependBase: добавлять или нет базовый URL из объекта запроса в начало данного URL.
Вы можете установить эту опцию глобально в контроллере, используя аксессор
setRedirectPrependBase(). -
code: какой код HTTP использовать при перенаправлении. По умолчанию используется HTTP 302. Могут использоваться любые коды от 301 до 306.
Вы можете установить эту опцию глобально в контроллере, используя аксессор
setRedirectCode().
-
Создание подклассов контроллера действий
Задумано, что в порядке создания контроллеров действий должны создаваться подклассы от Zend_Controller_Action. Как минимум, вам нужно будет определить методы действий, которые может вызывать контроллер.
Помимо создания полезного функционала для своих веб-приложений, вы можете также обнаружить, что большинство установок или сервисных методов повторяются в ваших различных контроллерах. В этом случае создание общего базового контроллера, расширяющего Zend_Controller_Action, может решить проблему избыточности.
Пример #1 Обрабаботка обращений к несуществующим действиям
Если сделан запрос к контроллеру, который содержит в себе
не определенный в контроллере метод действия, то вызывается метод
Zend_Controller_Action::__call().
__call() является магическим методом для перегрузки
методов в PHP.
По умолчанию этот метод бросает исключение Zend_Controller_Action_Exception, означающее, что требуемый метод не найден в контроллере. Если требуемый метод заканчивается строкой 'Action', то предполагается, что было запрошено действие и оно не существует; такая ошибка приводит к исключению с кодом 404. В остальных случаях бросается исключение с кодом 500. Это позволяет легко дифференцировать в обработчике ошибок случаи, когда страница не найдена, и когда произошла ошибка приложения.
Например, если вы хотите выводить сообщение об ошибке, то можете написать нечто подобное:
- class MyController extends Zend_Controller_Action
- {
- public function __call($method, $args)
- {
- // Если метод действия не найден, то рендерится шаблон ошибки
- return $this->render('error');
- }
- // все другие методы бросают исключение
- throw new Exception('Invalid method "'
- . $method
- . '" called',
- 500);
- }
- }
Другая возможность состоит в том, что вы можете производить переход на страницу контроллера по умолчанию:
- class MyController extends Zend_Controller_Action
- {
- public function indexAction()
- {
- $this->render();
- }
- public function __call($method, $args)
- {
- // Если метод действия не был найден, то производится
- // переход к действию index
- return $this->_forward('index');
- }
- // все другие методы бросают исключение
- throw new Exception('Invalid method "'
- . $method
- . '" called',
- 500);
- }
- }
Как и метод __call(), любые аксессоры,
сервисные методы, методы инициализации, вида и перехвата, упомянутые
ранее в этом разделе, могут быть переопределены для того, чтобы
приспособить свои контроллеры под конкретные нужды. Например, если
вы храните свои объекты вида в реестре, то можете модифицировать
свой метод initView():
- abstract class My_Base_Controller extends Zend_Controller_Action
- {
- public function initView()
- {
- if (null === $this->view) {
- if (Zend_Registry::isRegistered('view')) {
- $this->view = Zend_Registry::get('view');
- } else {
- $this->view = new Zend_View();
- }
- }
- return $this->view;
- }
- }
Надеемся, из написанного в этом разделе вы смогли увидеть, насколько гибка эта компонента, и как можно заточить ее под нужды своего приложения или сайта.
| Диспетчер |
Select a Version
Languages Available
Components
Search the Manual
Navigation
- Руководство разработчика
- Руководство разработчика
- Zend_Controller
- Zend_Controller - Быстрый старт
- Основы Zend_Controller
- Фронт-контроллер
- Объект запроса
- Стандартный маршрутизатор
- Диспетчер
- Контроллеры действий
- Помощники действий
- Объект ответа
- Плагины
- Использование модульной структуры директорий
- Исключения
- Переход с предыдущих версий
