Zend_Controller_Action - абстрактный класс,
который можно использовать для реализации контроллеров действий
для последующего их использования с фронт-контроллером при
разработке сайта, основанного на паттерне Model-View-Controller
(MVC).
Для того, чтобы использовать Zend_Controller_Action,
нужно создать его подкласс в своей действующей директории
контроллеров (или расширить его для создания своего базового класса
контроллеров действий). Работа с ним в основном сводится к
созданию его подкласса и написании методов действий, соответствующих
различным действиям, которые должен обрабатывать этот контроллер.
Маршрутизатор и диспетчер компоненты Zend_Controller
будут считать за методы действий все методы в классе
контроллера с именем, заканчивающимся на 'Action'.
Для примера предположим, что ваш класс определен следующим образом:
class FooController extends Zend_Controller_Action
{
publicfunction barAction()
{
// делает что-нибудь
}
publicfunction bazAction()
{
// делает что-нибудь
}
}
Приведенный выше класс FooController (контроллер
foo) определяет два действия - bar и
baz.
Класс может быть дополнен инициализирующим методом, методом
действия по умолчанию (если не был вызван метод, либо
вызван несуществующий метод), перехватчиками pre- и post-dispatch и
различными вспомогательными методами. Этот раздел служит обзором
функционала контроллера действий.
Note: Поведение по умолчанию
По умолчанию фронт-контроллер
активирует помощника действий ViewRenderer.
Этот помощник обеспечивает добавление объекта вида в контроллер
и автоматический рендеринг видов. Вы можете отключить его в
своем контроллере действия, используя один из следующих методов:
class FooController extends Zend_Controller_Action
{
publicfunction 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
{
publicfunction 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
Zend_Controller_Action определяет два метода, которые
вызываются до и после требуемого действия,
preDispatch() и postDispatch(). Они
могут быть полезны в различных случаях - например, проверка
аутентификации и списка управления доступом до запуска действия
(при вызове метода _forward() в
preDispatch() текущее действие будет пропущено) или
размещение сгенерированного содержимого в шаблоне боковой части
сайта (метод postDispatch()).
Аксессоры
С объектом контроллера регистрируется несколько объектов
и переменных, они имеют свои методы-аксессоры.
Объект запроса: через метод
getRequest() извлекается объект запроса, который
использовался для вызова данного действия.
Объект ответа:
через метод getResponse() извлекается объект
ответа, объединяющий в себе заголовки и содержимое ответа.
Некоторые типичные вызовы могут выглядеть следующим образом:
Аргументы вызова: фронт-контроллер
может добавлять параметры в маршрутизатор, диспетчер и
контроллер действий. Для их получения используйте
getInvokeArg($key), можно также извлечь весь список
аргументов, используя метод getInvokeArgs().
Параметры запроса: Объект запроса
заключает в себе параметры запроса, такие, как значения
_GET, _POST, или пользовательские параметры, определенные в
пути URL. Для их получения используйте
_getParam($key) или
_getAllParams(). Вы можете также установить
параметры запроса, используя метод _setParam(),
это полезно при перенаправлении на другие действия через
метод _forward().
Для определения того, существует ли параметр или нет
(полезно для логического ветвления), используйте
_hasParam($key).
Note:
_getParam() может принимать опциональный
второй аргумент, содержащий значение по умолчанию,
которое используется, если параметр не установлен или
пустой. Его использование устраняет необходимость
вызова _hasParam() до получения значения:
// Используется значение по умолчанию 1, если id не установлен
$id = $this->_getParam('id', 1);
// Вместо:
if($this->_hasParam('id'){
$id = $this->_getParam('id');
}else{
$id = 1;
}
Интеграция вида
Note: По умолчанию интеграция вида производится через 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.
Note:
Поскольку имена контроллера и действия могут содержать
символы-ограничители слов, такие, как '_', '.', и '-', то
render() нормализует их к '-', когда
определяет имя скрипта.
Внутри себя для такой нормализации он использует
ограничители слов и путей для диспетчера. Таким образом,
запрос к /foo.bar/baz-bat приведет к рендерингу
скрипта foo-bar/baz-bat.phtml. Если ваш метод
действия содержит camelCase, то следует иметь в виду, что
при определении имени скрипта вида результатом будут
разделенные '-' слова.
Некоторые примеры:
class MyController extends Zend_Controller_Action
{
publicfunction 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);
}
publicfunction 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, может решить проблему
избыточности.
Example #1 Обрабаботка обращений к несуществующим действиям
Если сделан запрос к контроллеру, который содержит в себе
не определенный в контроллере метод действия, то вызывается метод
Zend_Controller_Action::__call().
__call() является магическим методом для перегрузки
методов в PHP.
По умолчанию этот метод бросает исключение
Zend_Controller_Action_Exception, означающее, что
требуемый метод не найден в контроллере. Если требуемый метод
заканчивается строкой 'Action', то предполагается, что было
запрошено действие и оно не существует; такая ошибка приводит к
исключению с кодом 404. В остальных случаях бросается исключение
с кодом 500. Это позволяет легко дифференцировать в обработчике
ошибок случаи, когда страница не найдена, и когда произошла
ошибка приложения.
Например, если вы хотите выводить сообщение об ошибке, то можете
написать нечто подобное:
// Если метод действия не был найден, то производится
// переход к действию index
return$this->_forward('index');
}
// все другие методы бросают исключение
throw new Exception('Invalid method "'
. $method
. '" called',
500);
}
}
Как и метод __call(), любые аксессоры,
сервисные методы, методы инициализации, вида и перехвата, упомянутые
ранее в этом разделе, могут быть переопределены для того, чтобы
приспособить свои контроллеры под конкретные нужды. Например, если
вы храните свои объекты вида в реестре, то можете модифицировать
свой метод initView():
abstract class My_Base_Controller extends Zend_Controller_Action
Надеемся, из написанного в этом разделе вы смогли увидеть, насколько
гибка эта компонента, и как можно заточить ее под нужды своего
приложения или сайта.