Помощники действий (action helpers) дают разработчикам возможность добавлять функционал во время выполнения или по требованию в любые контроллеры действий, которые наследуют от Zend_Controller_Action. Помощники действий помогают снизить необходимость в наследовании от абстрактного контроллера действий при добавлении общего функционала в контроллер действий.
Есть несколько вариантов использования помощников действий.
Помощники действий используют брокерскую систему (brokerage system),
подобную той, которая используется в
Zend_View_Helper и
Zend_Controller_Plugin.
Помощники действий (как и Zend_View_Helper
) могут быть
загружены и вызваны по требованию, либо инстанцироваться во время
запроса (начальной загрузки) или создания контроллера действий
(init()). Для того, чтобы лучше разобраться с этим, см. ниже раздел
по использованию.
Помощник может быть инициализирован несколькими различными способами, выбор способа зависит от ваших нужд и от функционала, предоставляемого этим помощником.
Брокер помощников хранится как член $_helper
класса
Zend_Controller_Action
; используйте брокер для
получения или вызова помощников. Методы для этого включают в себя:
-
Явное использование метода
getHelper()
. Просто передайте ему имя, и будет возвращен объект помощника:<?php $flashMessenger = $this->_helper->getHelper('FlashMessenger'); $flashMessenger->addMessage('We did something in the last request');
-
Используйте функционал "волшебного" метода
__get()
брокера помощников - извлекайте помощника так же, как если бы он был свойством этого брокера:<?php $flashMessenger = $this->_helper->FlashMessenger; $flashMessenger->addMessage('We did something in the last request');
-
И наконец, большинство помощников действий реализует метод
direct()
, который будет вызывать особый, используемый по умолчанию метод в помощнике. Например, в случаеFlashMessenger
будет вызван методaddMessage()
:<?php $this->_helper->FlashMessenger('We did something in the last request');
Замечание | |
---|---|
Все примеры выше функционально эквивалентны. |
Вы можете также явно инстанцировать помощников. Вы можете захотеть сделать это, если используете помощника вне контроллера действий, или если хотите передавать помощника брокеру для использования в любых действиях. Инстанцирование производится так же, как и для любого другого класса PHP.
Zend_Controller_Action_HelperBroker
управляет
регистрацией объектов помощников и путей к помощникам, а также
извлечением помощников по требованию.
Для того, чтобы зарегистрировать помощника через брокер, используйте
addHelper
:
<?php Zend_Controller_Action_HelperBroker::addHelper($helper);
Само собой, инстанцирование и передача помощников брокеру отнимают
некоторое время и ресурсы, поэтому существуют два метода для
некоторой автоматизации: addPrefix()
и
addPath()
.
-
addPrefix()
принимает префикс класса и использует его для определения пути, по которому определен класс помощника. Подразумевается, что префикс следует соглашениям по именованию классов Zend Framework-а.<?php // Добавление помощников, начинающихся с My_Action_Helpers в My/Action/Helpers/ Zend_Controller_Action_HelperBroker::addPrefix('My_Action_Helpers');
-
addPath()
принимает директорию в качестве первого аргумента и префикс класса в качестве второго (по умолчанию это 'Zend_Controller_Action_Helper'). Это позволяет поставить в соответствие определенным директориям собственные префиксы классов.<?php // Добавление помощников, начинающихся с Helper в Plugins/Helpers/ Zend_Controller_Action_HelperBroker::addPath('./Plugins/Helpers', 'Helper');
Поскольку эти методы статические, то они могут вызываться из любого места в цепочке контроллеров для динамического добавления помощников при необходимости.
Для определения того, есть ли помощник в брокере, используйте
hasHelper($name)
, где $name
- короткое имя помощника (без префикса):
<?php // Check if 'redirector' helper is registered with the broker: if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) { echo 'Redirector helper registered'; }
Есть также два статических метода для извлечения помощников из
брокера помощников: getExistingHelper()
и
getStaticHelper()
. getExistingHelper()
будет извлекать помощника только если он был ранее вызван или явно
зарегистрирован через брокер помощников, иначе бросается исключение.
getStaticHelper()
делает то же самое, что и
getExistingHelper()
, за тем исключением, что будет
пытаться инстанцировать помощника, если он еще не был
зарегистрирован в стеке помощников. getStaticHelper()
является хорошим выбором, если нужно извлечь помощника для конфигурирования.
Оба метода принимают единственный аргумент, $name
,
который является коротким именем помощника (без префикса).
<?php // Проверка того, что помощник 'redirector' зарегистрирован в брокере, и его извлечение: if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) { $redirector = Zend_Controller_Action_HelperBroker::getExistingHelper('redirector'); } // Или просто извлеките его, не заботясь о том, был ли он ранее зарегистрирован: $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector'); }
Наконец, для удаления зарегистрированного помощника из брокера
используйте removeHelper($name)
, где $name
- короткое имя помощника (без префикса):
<?php // Удаление помощника 'redirector' из брокера, помещенное в условную конструкцию if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) { Zend_Controller_Action_HelperBroker::removeHelper('redirector') }
Zend Framework уже содержит в себе набор помощников действий:
AutoComplete
автоматизирует ответы для автозавершения
ввода с использованием AJAX; ContextSwitch
и
AjaxContext
для обслуживания альтернативных форматов
ответов для ваших действий; FlashMessenger
для
управления сессионными сообщениями; Json
для
кодирования и отправки ответов JSON; Redirector
,
предоставляющий различные реализации перенаправления из вашего
приложения на внутренние и внешние страницы; и
ViewRenderer
, автоматизирующий процесс настройки
объекта вида в контроллерах и рендеринга видов.
Помощник ActionStack
позволяет помещать в стек запросы к
плагину
ActionStack
фронт-контроллера, помогая эффективно создавать очереди действий,
выполняемых в течение запроса. Этот помощник позволяет добавлять
действия посредством установки новых объектов запросов или наборов
действие/контроллер/модуль.
Вызов помощника ActionStack инициализирует плагин ActionStack | |
---|---|
При вызове помощника |
Пример 7.2. Добавление задачи с использованием имен действия, контроллера и модуля
Зачастую наиболее простым способом будет указание действия,
контроллера и модуля (и необязательных параметров запроса), почти
так же, как если бы вы вызывали
Zend_Controller_Action::_forward()
:
<?php class FooController extends Zend_Controller_Action { public function barAction() { // Добавление двух действий в стек // Добавление вызова к /foo/baz/bar/baz // (FooController::bazAction() с переменной запроса bar == baz) $this->_helper->actionStack('baz', 'foo', 'default', array('bar' => 'baz')); // Добавление вызова к /bar/bat // (BarController::batAction()) $this->_helper->actionStack('bat', 'bar'); } } ?>
Пример 7.3. Добавление задачи с использованием объекта запроса
Иногда имеет смысл использовать объект запроса, что более
соответствует духу ООП. Объект запроса тоже можно передавать
помощнику ActionStack
.
<?php class FooController extends Zend_Controller_Action { public function barAction() { // Добавление двух действий в стек // Добавление вызова к /foo/baz/bar/baz // (FooController::bazAction() с переменной запроса bar == baz) $request = clone $this->getRequest(); $request->setActionName('baz') // не устанавливайте контроллер и ->setParams(array('bar' => 'baz')); // модуль; используются текущие значения $this->_helper->actionStack($request); // Add call to /bar/bat // (BarController::batAction()) $request = clone $this->getRequest(); $request->setActionName('bat') // не устанавливайте модуль; ->setControllerName('bar'); // используется текущее значение $this->_helper->actionStack($request); } } ?>
Многие JavaScript-библиотеки для AJAX предоставляют функционал для
автодополнения, с его помощью отображается список
возможных соответствий в то время, пока пользователь набирает текст.
Помощник AutoComplete
предназначен для облегчения возврата
допустимых ответов для функционала такого рода.
Поскольку не все JavaScript-библиотеки реализуют автодополнение
одинаково, то помощник AutoComplete
предоставляет в
абстрактном классе некоторый базовый функционал, необходимый для
большинства библиотек, и конкретные реализации для отдельных библиотек.
Возвращаемые данные в
основном - JSON-массивы строк, JSON-массивы массивов (в которых каждый
массив-член является ассоциативным массивом метаданных, используемых при
создании списка), либо HTML.
Базовое использование одинаково для всех реализаций:
<?php class FooController extends Zend_Controller_Action { public function barAction() { // Выполнение некоторой логики... // Кодирование и отправка ответа: $this->_helper->autoCompleteDojo($data); // То же самое явным образом: $response = $this->_helper->autoCompleteDojo->sendAutoCompletion($data); // Или просто подготовьте ответ для автодополнения: $response = $this->_helper->autoCompleteDojo->prepareAutoCompletion($data); } } ?>
По умолчанию этот помощник делает следующее:
Отключает макеты и ViewRenderer.
Устанавливает необходимые заголовки ответа.
Устанавливает тело ответа с закодированными данными в нужном формате для автодополнения.
Отправляет ответ.
Доступные методы помощника включают в себя:
disableLayouts()
может использоваться для отключения макетов и ViewRenderer. Обычно он вызывается вprepareAutoCompletion()
.encodeJson($data, $keepLayouts = false)
будет кодировать данные в формат JSON, при этом можно опционально включать или отключать макеты. Обычно этот метод вызывается вprepareAutoCompletion()
.prepareAutoCompletion($data, $keepLayouts = false)
используется для подготовки ответа в формате, необходимом для конкретной реализации, при этом можно опционально включать или отключать макеты. Возвращаемое значение может варьироваться в зависимости от используемой реализации.sendAutoCompletion($data, $keepLayouts = false)
используется для отправки данных в формате, необходимом для конкретной реализации. Он вызываетprepareAutoCompletion()
и затем отправляет ответ.direct($data, $sendNow = true, $keepLayouts = false)
используется, когда помощник вызывается как метод брокера помощников. Флаг$sendNow
используется для определения того, какой метод вызывать -sendAutoCompletion()
илиprepareAutoCompletion()
. По умолчанию ответ отправляется сразу.
В настоящее время AutoComplete
поддерживает AJAX-библиотеки
Dojo и Scriptaculous.
В Dojo нет собственно виджета для автодополнения, но он имеет два виджета, которые могут производить автодополнение: ComboBox и FilteringSelect. В обоих случаях они требуют использования хранилища данных, который реализует QueryReadStore, читайте документацию по dojo.data для получения более подробной информации по этой теме.
В Zend Framework вы можете передавать простой индексный массив для помощника AutoCompleteDojo, и он будет возвращен в формате, пригодном для использования с хранилищем в Dojo:
<?php // within a controller action: $this->_helper->autoCompleteDojo($data);
Пример 7.4. Автодополнение с Dojo и Zend MVC
Автодополнение с Dojo через Zend MVC требует реализации нескольких вещей: генерация объекта формы для того ComboBox, для которого нужно реализовать автодополнение, действие контроллера для обслуживания автодополнения, создание своего QueryReadStore для связи с этим действием и генерация javascript-кода для инициализации автодополнения.
Для начала рассмотрим, что нужно сделать по части javascript. Dojo представляет собой полный фреймворк для создания объектно-ориентированного кода на языке JavaScript, почти так же, как Zend Framework на языке PHP. Он позволяет создавать псевдопространства имен, используя для этого иерархию директорий. Создадим директорию 'custom' на том же уровне, что и директория Dojo. В этой директории создадим файл TestNameReadStore.js со следующим содержимым:
dojo.provide("custom.TestNameReadStore"); dojo.declare("custom.TestNameReadStore", dojox.data.QueryReadStore, { fetch:function (request) { request.serverQuery = { test:request.query.name }; return this.inherited("fetch", arguments); } });
Этот класс просто наследует от класса QueryReadStore фреймворка Dojo, который сам по себе является абстрактным. Мы просто определяем метод, по которому производится запрос, и присваиваем его элементу 'test'.
Далее создадим элемент формы, для которого хотим реализовать автодополнение:
<?php class TestController extends Zend_Controller_Action { protected $_form; public function getForm() { if (null === $this->_form) { require_once 'Zend/Form.php'; $this->_form = new Zend_Form(); $this->_form->setMethod('get') ->setAction($this->getRequest()->getBaseUrl() . '/test/process') ->addElements(array( 'test' => array('type' => 'text', 'options' => array( 'filters' => array('StringTrim'), 'dojoType' => array('dijit.form.ComboBox'), 'store' => 'testStore', 'autoComplete' => 'false', 'hasDownArrow' => 'true', 'label' => 'Your input:', )), 'go' => array('type' => 'submit', 'options' => array('label' => 'Go!')) )); } return $this->_form; } }
Здесь мы просто создаем форму с методами 'test' и 'go'. Метод 'test' добавляет несколько специальных, специфических для Dojo атрибутов: dojoType, store, autoComplete и hasDownArrow. Через 'dojoType' мы указываем, что создается ComboBox, он связан с хранилищем данных (ключ 'store') 'testStore'. Устанавливая 'autoComplete' в false, мы говорим Dojo, чтобы он не выбирал автоматически первое соответствие, а вместо этого показывал список соответсвий. Наконец, 'hasDownArrow' создает стрелку наподобие той, что присутствует в выпадающем списке, чтобы можно было выводить и убирать список соответствий.
Добавим метод для отображения формы и действие для обработки автодополнения:
<?php class TestController extends Zend_Controller_Action { // ... /** * Страница с формой */ public function indexAction() { $this->view->form = $this->getForm(); } public function autocompleteAction() { if ('ajax' != $this->_getParam('format', false)) { return $this->_helper->redirector('index'); } if ($this->getRequest()->isPost()) { return $this->_helper->redirector('index'); } $match = trim($this->getRequest()->getQuery('test', '')); $matches = array(); foreach ($this->getData() as $datum) { if (0 === strpos($datum, $match)) { $matches[] = $datum; } } $this->_helper->autoCompleteDojo($matches); } }
В методе autocompleteAction()
мы делаем несколько
вещей. Сначала мы проверяем, был ли произведен POST-запрос и
имеет ли параметр 'format' значение 'ajax', это помогает
отсечь большинство ложных запросов. Далее мы получаем
параметр 'test' и сравниваем его с нашими данными (здесь я
намеренно опустил реализацию метода getData()
,
источники данных могут быть любыми). В конце выполнения
передаем найденные соответствия помощнику AutoCompletion.
Теперь на очереди написание скрипта вида для страницы с формой. В нем нужно установить хранилище данных, вывести форму и подключить все необходимые библиотеки Dojo, включая наше хранилище данных. Ниже приведен скрипт вида с комментариями:
<? // установка хранилища данных: ?> <div dojoType="custom.TestNameReadStore" jsId="testStore" url="<?= $this->baseUrl() ?>/unit-test/autocomplete/format/ajax" requestMethod="get"></div> <? // рендеринг формы: ?> <?= $this->form ?> <? // подключение css для Dojo в HTML-заголовке: ?> <? $this->headStyle()->captureStart() ?> @import "<?= $this->baseUrl() ?>/javascript/dijit/themes/tundra/tundra.css"; @import "<?= $this->baseUrl() ?>/javascript/dojo/resources/dojo.css"; <? $this->headStyle()->captureEnd() ?> <? // подключение javascript в HTML-заголовке, включая библиотеки для Dojo: ?> <? $this->headScript() ->setAllowArbitraryAttributes(true) ->appendFile($this->baseUrl() . '/javascript/dojo/dojo.js', 'text/javascript', array('djConfig' => 'parseOnLoad: true')) ->captureStart() ?> djConfig.usePlainJson=true; dojo.registerModulePath("custom","../custom"); dojo.require("dojo.parser"); dojo.require("dojox.data.QueryReadStore"); dojo.require("dijit.form.ComboBox"); dojo.require("custom.TestNameReadStore"); <? $this->headScript()->captureEnd() ?>
Обратите внимание на вызовы помощников видов, таких, как headStyle м headScript, - это метки заполнения, которые могут затем рендериться в HTML-заголовке скрипта макета.
Теперь у нас есть всё для того, чтобы автодополнение с Dojo заработало.
Scriptaculous ожидает HTML-ответ в определенном формате.
С этой библиотекой используется помощник 'AutoCompleteScriptaculous'. Просто передавайте ему массив данных, и он создает ответ HTML, совместимый с Ajax.Autocompleter.
The ContextSwitch
action helper is intended for
facilitating returning different response formats on request.
The AjaxContext
helper is a specialized version of
ContextSwitch
that facilitates returning responses
to XmlHttpRequests.
To enable either one, you must provide hinting in your controller as to what actions can respond to which contexts. If an incoming request indicates a valid context for the given action, the helper will then:
Disable layouts, if enabled.
Set an alternate view suffix, effectively requiring a separate view script for the context.
Send approprite response headers for the context desired.
Optionally, call specified callbacks to setup the context and/or perform post-processing.
As an example, let's consider the following controller:
<?php class NewsController extends Zend_Controller_Action { /** * Landing page; forwards to listAction() */ public function indexAction() { $this->_forward('list'); } /** * List news items */ public function listAction() { } /** * View a news item */ public function viewAction() { } } ?>
Let's say that we want the listAction()
to also be
available in an XML format. Instead of creating a different action, we
can hint that it can return an XML response:
<?php class NewsController extends Zend_Controller_Action { public function init() { $contextSwitch = $this->_helper->getHelper('contextSwitch'); $contextSwitch->addActionContext('list', 'xml') ->initContext(); } // ... } ?>
What this will do is:
Set the 'Content-Type' response header to 'text/xml'.
Change the view suffix to 'xml.phtml' (or, if you use an alternate view suffix, 'xml.[your suffix]').
Now, you'll need to create a new view script, 'news/list.xml.phtml', which will create and render the XML.
To determine if a request should initiate a context switch, the helper checks for a token in the request object. By default, it looks for the 'format' parameter, though this may be configured. This means that, in most cases, to trigger a context switch, you can add a 'format' parameter to your request:
Via URL parameter:
/news/list/format/xml
(recall, the default routing schema allows for arbitrary key/value pairs following the action)Via GET parameter:
/news/list?format=xml
ContextSwitch
allows you to specify arbitrary contexts,
including what suffix change will occur (if any), any response headers
that should be sent, and arbitrary callbacks for initialization and post
processing.
By default, two contexts are available to the
ContextSwitch
helper: json and xml.
-
JSON. The JSON context sets the 'Content-Type' response header to 'application/json', and the view script suffix to 'json.phtml'.
By default, however, no view script is required. It will simply serialize all view variables, and emit the JSON response immediately.
This behaviour can be disabled by turning off auto-JSON serialization:
<?php $this->_helper->contextSwitch()->setAutoJsonSerialization(false); ?>
XML. The XML context sets the 'Content-Type' response header to 'text/xml', and the view script suffix to 'xml.phtml'. You will need to create a new view script for the context.
Sometimes, the default contexts are not enough. For instance, you
may wish to return YAML, or serialized PHP, an RSS or ATOM feed,
etc. ContextSwitch
allows you to do so.
The easiest way to add a new context is via the
addContext()
method. This method takes two arguments,
the name of the context, and an array specification. The
specification should include one or more of the following:
suffix: the suffix to prepend to the default view suffix as registered in the ViewRenderer.
headers: an array of header/value pairs you wish sent as part of the response.
-
callbacks: an array containing one or more of the keys 'init' or 'post', pointing to valid PHP callbacks that can be used for context initialization and post processing.
Initialization callbacks occur when the context is detected by
ContextSwitch
. You can use it to perform arbitrary logic that should occur. As an example, the JSON context uses a callback to disable the ViewRenderer when auto-JSON serialization is on.Post processing occurs during the action's
postDispatch()
routine, and can be used to perform arbitrary logic. As an example, the JSON context uses a callback to determine if auto-JSON serialization is on; if so, it serializes the view variables to JSON and sends the response, but if not, it re-enables the ViewRenderer.
There are a variety of methods for interacting with contexts:
addContext($context, array $spec)
: add a new context. Throws an exception if the context already exists.setContext($context, array $spec)
: add a new context or overwrite an existing context. Uses the same specification asaddContext()
.addContexts(array $contexts)
: add many contexts at once. The$contexts
array should be an array of context/specification pairs. If any of the contexts already exists, it will throw an exception.setContexts(array $contexts)
: add new contexts and overwrite existing ones. Uses the same specification asaddContexts()
.hasContext($context)
: returns true if the context exists, false otherwise.getContext($context)
: retrieve a single context by name. Returns an array following the specification used inaddContext()
.getContexts()
: retrieve all contexts. Returns an array of context/specification pairs.removeContext($context)
: remove a single context by name. Returns true if successful, false if the context was not found.clearContexts()
: remove all contexts.
There are two mechanisms for setting available contexts. You can
either manually create arrays in your controller, or use several
methods in ContextSwitch
to assemble them.
The principle method for adding action/context relations is
addActionContext()
. It expects two arguments, the
action to which the context is being added, and either the name of a
context or an array of contexts. As an example, consider the
following controller class:
<?php class FooController extends Zend_Controller_Action { public function listAction() { } public function viewAction() { } public function commentsAction() { } public function updateAction() { } } ?>
Let's say we wanted to add an XML context to the 'list' action, and
XML and JSON contexts to the 'comments' action. We could do so in
the init()
method:
<?php class FooController extends Zend_Controller_Action { public function init() { $this->_helper->contextSwitch() ->addActionContext('list', 'xml') ->addActionContext('comments', array('xml', 'json')) ->initContext(); } } ?>
Alternately, you could simply define the array property
$contexts
:
<?php class FooController extends Zend_Controller_Action { public $contexts = array( 'list' => array('xml'), 'comments' => array('xml', 'json') ); public function init() { $this->_helper->contextSwitch()->initContext(); } } ?>
The above is less overhead, but also prone to potential errors.
The following methods can be used to build the context mappings:
-
addActionContext($action, $context)
: marks one or more contexts as available to an action. If mappings already exists, simply appends to those mappings.$context
may be a single context, or an array of contexts.A value of
true
for the context will mark all available contexts as available for the action.An empty value for $context will disable all contexts for the given action.
setActionContext($action, $context)
: marks one or more contexts as available to an action. If mappings already exists, it replaces them with those specified.$context
may be a single context, or an array of contexts.addActionContexts(array $contexts)
: add several action/context pairings at once.$contexts
should be an associative array of action/context pairs. It proxies toaddActionContext()
, meaning that if pairings already exist, it appends to them.setActionContexts(array $contexts)
: acts likeaddActionContexts()
, but overwrites existing action/context pairs.hasActionContext($action, $context)
: determine if a particular action has a give context.getActionContexts($action = null)
: returns either all contexts for a given action, or all action/context pairs.removeActionContext($action, $context)
: remove one or more contexts from a given action.$context
may be a single context or an array of contexts.clearActionContexts($action = null)
: remove all contexts from a given action, or from all actions with contexts.
To initialize context switching, you need to call
initContext()
in your action controller:
<?php class NewsController extends Zend_Controller_Action { public function init() { $this->_helper->contextSwitch()->initContext(); } } ?>
In some cases, you may want to force the context used; for instance,
you may only want to allow the XML context if context switching is
activated. You can do so by passing the context to
initContext()
:
<?php $contextSwitch->initContext('xml'); ?>
A variety of methods can be used to alter the behaviour of the
ContextSwitch
helper. These include:
-
setAutoJsonSerialization($flag)
: By default, JSON contexts will serialize any view variables to JSON notation and return this as a response. If you wish to create your own response, you should turn this off; this needs to be done prior to the call toinitContext()
.<?php $contextSwitch->setAutoJsonSerialization(false); $contextSwitch->initContext(); ?>
You can retrieve the value of the flag with
getAutoJsonSerialization()
. -
setSuffix($context, $suffix, $prependViewRendererSuffix)
: With this method, you can specify a different suffix to use for a given context. The third argument is used to indicate whether or not to prepend the current ViewRenderer suffix with the new suffix; this flag is enabled by default.Passing an empty value to the suffix will cause only the ViewRenderer suffix to be used.
-
addHeader($context, $header, $content)
: Add a response header for a given context.$header
is the header name, and$content
is the value to pass for that header.Each context can have multiple headers;
addHeader()
adds additional headers to the context's header stack.If the
$header
specified already exists for the context, an exception will be thrown. setHeader($context, $header, $content)
:setHeader()
acts just likeaddHeader()
, except it allows you to overwrite existing context headers.addHeaders($context, array $headers)
: Add multiple headers at once to a given context. Proxies toaddHeader()
, so if the header already exists, an exception will be thrown.$headers
is an array of header/context pairs.setHeaders($context, array $headers.)
: likeaddHeaders()
, except it proxies tosetHeader()
, allowing you to overwrite existing headers.getHeader($context, $header)
: retrieve the value of a header for a given context. Returns null if not found.removeHeader($context, $header)
: remove a single header for a given context.clearHeaders($context, $header)
: remove all headers for a given context.setCallback($context, $trigger, $callback)
: set a callback at a given trigger for a given context. Triggers may be either 'init' or 'post' (indicating callback will be called at either context initialization or postDispatch).$callback
should be a valid PHP callback.setCallbacks($context, array $callbacks)
: set multiple callbacks for a given context.$callbacks
should be trigger/callback pairs. In actuality, the most callbacks that can be registered are two, one for initialization and one for post processing.getCallback($context, $trigger)
: retrieve a callback for a given trigger in a given context.getCallbacks($context)
: retrieve all callbacks for a given context. Returns an array of trigger/callback pairs.removeCallback($context, $trigger)
: remove a callback for a given trigger and context.clearCallbacks($context)
: remove all callbacks for a given context.-
setContextParam($name)
: set the request parameter to check when determining if a context switch has been requested. The value defaults to 'format', but this accessor can be used to set an alternate value.getContextParam()
can be used to retrieve the current value. -
setAutoDisableLayout($flag)
: By default, layouts are disabled when a context switch occurs; this is because typically layouts will only be used for returning normal responses, and have no meaning in alternate contexts. However, if you wish to use layouts (perhaps you may have a layout for the new context), you can change this behaviour by passing a true value tosetAutoDisableLayout()
. You should do this before callinginitContext()
.To get the value of this flag, use the accessor
getAutoDisableLayout()
. getCurrentContext()
can be used to determine what context was detected, if any. This returns null if no context switch occurred, or if called beforeinitContext()
has been invoked.
The AjaxContext
helper extends
ContextSwitch
, so all of the functionality listed for
ContextSwitch
is available to it. There are a few key
differences, however.
First, it uses a different action controller property for
determining contexts, $ajaxable
. This is so you can
have different contexts used for AJAX versus normal HTTP requests.
The various *ActionContext*()
methods of
AjaxContext
will write to this property.
Second, it will only trigger if an XmlHttpRequest has occurred, as
determined by the request object's isXmlHttpRequest()
method. Thus, if the context parameter ('format') is passed in the
request, but the request was not made as an XmlHttpRequest, no
context switch will trigger.
Third, AjaxContext
adds an additional context, HTML. In
this context, it sets the suffix to 'ajax.phtml' in order to
differentiate the context from a normal request. No additional
headers are returned.
Пример 7.5. Allowing Actions to Respond To Ajax Requests
In this following example, we're allowing requests to the actions 'view', 'form', and 'process' to respond to AJAX requests. In the first two cases, 'view' and 'form', we'll return HTML snippets with which to update the page; in the latter, we'll return JSON.
<?php class CommentController extends Zend_Controller_Action { public function init() { $ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext->addActionContext('view', 'html') ->addActionContext('form', 'html') ->addActionContext('process', 'json') ->initContext(); } public function viewAction() { // Pull a single comment to view. // When AjaxContext detected, uses the comment/view.ajax.phtml // view script. } public function formAction() { // Render the "add new comment" form. // When AjaxContext detected, uses the comment/form.ajax.phtml // view script. } public function processAction() { // Process a new comment // Return the results as JSON; simply assign the results as view // variables, and JSON will be returned. } } ?>
On the client end, your AJAX library will simply request the endpoints '/comment/view', '/comment/form', and '/comment/process', and pass the 'format' parameter: '/comment/view/format/html', '/comment/form/format/html', '/comment/process/format/json'. (Or you can pass the parameter via GET: e.g., "?format=json".)
Assuming your library passes the 'X-Requested-With: XmlHttpRequest' header, these actions will then return the appropriate response format.
Помощник FlashMessenger
позволяет передавать сообщения,
которые нужно отобразить пользователю при следующем запросе.
Для хранения сообщений до следующего запроса
FlashMessenger
использует
Zend_Session_Namespace
. Как правило, лучше всего
использовать тот Zend_Session
или
Zend_Session_Namespace
, который вы инициализировали с
помощью Zend_Session::start()
в своем файле загрузки.
(За более подробной информацией об использовании см.
Zend Session).
Пример использования ниже демонстрирует простейший случай
использования мессенджера. Когда вызывается действие
/some/my
, оно добавляет мгновенное сообщение "Record
Saved!". Последующий запрос к действию
/some/my-next-request
получит это сообщение
(и удалит его).
<?php class SomeController extends Zend_Controller_Action { /** * FlashMessenger * * @var Zend_Controller_Action_Helper_FlashMessenger */ protected $_flashMessenger = null; public function init() { $this->_flashMessenger = $this->_helper->getHelper('FlashMessenger'); $this->initView(); } public function myAction() { /** * default method of getting Zend_Controller_Action_Helper_FlashMessenger * instance on-demand */ $this->_flashMessenger->addMessage('Record Saved!'); } public function myNextRequestAction() { $this->view->messages = $this->_flashMessenger->getMessages(); $this->render(); } }
JSON быстро становится предпочтительным форматом для использования с AJAX-запросами, которые подразумевают ответы с данными. Синтаксический разбор JSON может производиться сразу на стороне клиента, что приводит к большей производительности.
Помощник действий JSON выполняет несколько функций:
Отключает макеты, если они включены.
Отключает ViewRenderer, если он включен.
Устанавливает заголовок ответа 'Content-Type' со значением 'application/json'.
По умолчанию сразу возвращает ответ, не дожидаясь завершения выполнения действия.
Использование помощника довольно простое - вызывайте его как метод
брокера помощников или вызывайте один из его методов
encodeJson()
или
sendJson()
:
<?php class FooController extends Zend_Controller_Action { public function barAction() { // произведение некоторых действий... // Отправка ответа JSON: $this->_helper->json($data); // или... $this->_helper->json->sendJson($data); // либо получение данных в формате json: $json = $this->_helper->json->encodeJson($data); } } ?>
Использование с макетами | |
---|---|
Для того, чтобы использовать отдельные макеты для JSON-ответов
(например, для того, чтобы помещать JSON-ответы в некоторый
контекст), все методы в помощнике JSON принимают второй опциональный
параметр - флаг для включения и отключения макетов. Передача
значения <?php class FooController extends Zend_Controller_Action { public function barAction() { // Получение данных в формате json, макеты остаются включенными $json = $this->_helper->json->encodeJson($data, true); } } ?> |
Помощник Redirector
позволяет использовать объект
Redirector для удовлетворения нужд в перенаправлении на
новые URL. Он имеет многие преимущества по сравнению с методом
_redirect()
, такие, как возможность предварительной
конфигурации поведения на стороне сайта в объекте Redirector или
использование встроенного интерфейса
goto($action, $controller, $module, $params)
, подобного
интерфейсу Zend_Controller_Action::_forward()
.
Redirector
имеет набор методов, которые могут
использоваться для управления поведением при перенаправлении:
setCode()
может использоваться для установки кода ответа HTTP, используемого при перенаправлении.setExit()
может использоваться для установки принудительного вызоваexit()
после перенаправления. По умолчанию он установлен в true.setGoto()
может использоваться для установки URL, используемого по умолчанию, если методуgoto()
не был передан URL. Использует интерфейсZend_Controller_Action::_forward()
: setgoto($action, $controller = null, $module = null, array $params = array());setGotoRoute()
может использоваться для установки URL, основываясь на зарегистрированном маршруте. Ему должен передаваться массив пар ключ/значение и имя маршрута, из них будет собран URL в соответствии с типом и определением маршрута.setGotoUrl()
может использоваться для установки URL, используемого по умолчанию, если методуgotoUrl()
не был передан URL. Принимает единственную строку URL в качестве аргумента.setPrependBase()
может использоваться для добавления базового URL объекта запроса в начало URL, заданного через методыsetGotoUrl()
,gotoUrl()
, илиgotoUrlAndExit()
.setUseAbsoluteUri()
может использоваться для принужденияRedirector
-а применять абсолютные URI при произведении перенаправления. Когда эта опция установлена, то используются значения$_SERVER['HTTP_HOST']
,$_SERVER['SERVER_PORT']
и$_SERVER['HTTPS']
для формирования полного URI из URL, определенного одним из методов перенаправления. Эта опция по умолчанию отключена, но может быть включена по умолчанию в последующих релизах.
Кроме этого, в Redirector есть различные методы, выполняющие текущие перенаправления:
goto()
используетsetGoto()
(интерфейс, подобный_forward()
) для построения URL и перенаправления на него.gotoRoute()
используетsetGotoRoute()
(сборка маршрута) для построения URL и перенаправления на него.gotoUrl()
используетsetGotoUrl()
(строка URL) для построения URL и перенаправления на него.
Наконец, можно в любое время получить текущий URL для
перенаправления, используя getRedirectUrl()
.
Пример 7.6. Опции настройки
В этом примере переопределяются несколько опций, включая код статуса HTTP, используемого при перенаправлении ('303'), и определение URL, используемое по умолчанию при перенаправлении.
<?php class SomeController extends Zend_Controller_Action { /** * Редиректор - определен для полноты кода * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); // Установка опций по умолчанию для редиректора // Поскольку объект зарегистрирован в брокере помощников, то эти опции // будут действительными для всех последующих действий $this->_redirector->setCode('303') ->setExit(false) ->setGoto("this-action", "some-controller"); } public function myAction() { /* делаем что-то */ // Перенаправление на ранее зарегистрированный URL и // принудительное завершение исполнения скрипта: $this->_redirector->redirectAndExit(); return; // никогда не будет достигнуто } } }
Пример 7.7. Использование по умолчанию
Этот пример предполагает, что используются значения по
умолчанию, это означает, что после любых перенаправлений будет
производиться выход exit()
.
<?php // АЛЬТЕРНАТИВНЫЙ ПРИМЕР class AlternativeController extends Zend_Controller_Action { /** * Редиректор - определен для полноты кода * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); } public function myAction() { /* делаем что-то */ $this->_redirector->gotoUrl('/my-controller/my-action/param1/test/param2/test2'); // это место никогда не будет достигнуто, // т.к. по умолчанию производится переход и завершение выполнения return; } }
Пример 7.8. Использование интерфейса _forward() для goto()
Метод goto()
копирует интерфейс метода
Zend_Controller_Action::_forward()
. Основное
отличие состоит в том, что он строит URL из переданных
параметров и использует формат
:module/:controller/:action/*
маршрутизатора по
умолчанию. Затем он производит перенаправление вместо добавления
действия в цепочку.
<?php class ForwardController extends Zend_Controller_Action { /** * Редиректор - определен для полноты кода * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); } public function myAction() { /* Делаем что-то */ // Перенаправление на действие 'my-action' контроллера 'my-controller' // в текущем модуле с использованием параметров param1 => test и // param2 => test2 $this->_redirector->goto('my-action', 'my-controller', null, array('param1' => 'test', 'param2' => 'test2')); } }
Пример 7.9. Использование маршрута с gotoRoute()
Следующий пример использует метод assemble()
маршрута для
создания URL, основанного на переданном ассоциативном массиве
параметров. Этот пример предполагает, что был зарегистрирован
следующий маршрут:
<?php $route = new Zend_Controller_Router_Route( 'blog/:year/:month/:day/:id', array('controller' => 'archive', 'module' => 'blog', 'action' => 'view') ); $router->addRoute('blogArchive', $route);
При заданном массиве, в котором year (год), month (месяц), и day
(день) установлены в 2006, 4 и 24 соответственно, будет построен
URL /blog/2006/4/24/42
.
<?php class BlogAdminController extends Zend_Controller_Action { /** * Редиректор - определен для полноты кода * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); } public function returnAction() { /* делаем что-то */ // Перенаправление в архив блога. Строит URL // /blog/2006/4/24/42 $this->_redirector->gotoRoute( array('year' => 2006, 'month' => 4, 'day' => 24, 'id' => 42), 'blogArchive' ); } }
Помощник ViewRenderer
предназначен для решения
следующих задач:
Устранение необходимости инстанцирования объектов вида внутри контроллеров; объекты вида будут автоматически регистрироваться вместе с контроллером.
Автоматическая установка путей к скриптам вида, помощникам и фильтрам, основанная на текущем модуле, и автоматическое присоединение имени текущего модуля в качестве префикса имен классов помощников и фильтров.
Создание глобально доступного объекта вида для всех запускаемых контроллеров и действий.
Возможность устанавливать используемые по умолчанию опции рендеринга для всех контроллеров.
Возможность автоматического рендеринга скрипта вида, не требующего от разработчика каких-либо действий.
Возможность создавать собственные спецификации базового пути вида и путей к скриптам видов.
Замечание | |
---|---|
Если вы вручную производите |
Замечание | |
---|---|
Если вы хотите изменить настройки
|
В простейшем варианте использования вы просто инстанцируете
ViewRenderer
и передаете его брокеру помощников.
Наиболее легким способом его инстанцирования и регистрации является
использование метода getStaticHelper()
брокера
помощников:
<?php Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
Во время инстанцирования контроллера действий производится вызов
ViewRenderer
для инстанцирования объекта вида. Каждый
раз, когда инстанцируется контроллер, вызывается метод
init()
помощника ViewRenderer
, что
приводит к установке свойства $view
данного контроллера
действий и вызову метода addScriptPath()
с путем
относительно текущего модуля; он будет вызван с префиксом класса,
соответствующим имени текущего модуля, что эффективно
разделяет пространства имен всех классов помощников и фильтров,
определенных для этого модуля.
Каждый раз, когда вызывается postDispatch()
, он будет
вызывать render()
для текущего действия.
В качестве примера рассмотрим следующий класс:
<?php // Класс контроллера, модуль foo: class Foo_BarController extends Zend_Controller_Action { // Рендеринг bar/index.phtml по умолчанию; // не требуется производить какие-либо операции public function indexAction() { } // Рендеринг bar/populate.phtml с переменной 'foo', установленной в 'bar'. // Поскольку объект вида определен в preDispatch(), то он всегда доступен. public function populateAction() { $this->view->foo = 'bar'; } } ... // в одном из ваших скриптов вида: <?php $this->foo(); // call Foo_View_Helper_Foo::foo()
ViewRenderer
также определяет несколько аксессоров для
того, чтобы можно было устанавливать и извлекать опции видов:
setView($view)
позволяет установить объект вида дляViewRenderer
. Объект сохраняется в открытом свойстве$view
класса.setNeverRender($flag = true)
может использоваться для отключения или включения авторендеринга глобально, т.е. для всех контроллеров. Если установлен вtrue
, тоpostDispatch()
не будет автоматически вызыватьrender()
в текущем контроллере.getNeverRender()
возвращает текущее значение.setNoRender($flag = true)
может использоваться для отключения или включения авторендеринга. Если установлен вtrue
, тоpostDispatch()
не будет автоматически вызыватьrender()
в текущем контроллере. Эта установка сбрасывается каждый раз во время вызоваpreDispatch()
(т.е. нужно устанавливать этот флаг для каждого контроллера, для которого вы не хотите производить авторендеринг).getNoRender()
возвращает текущее значение.setNoController($flag = true)
может использоваться для того, чтобы указать методуrender()
, чтобы он не искал скрипт вида в поддиректории с именем контроллера (что является поведением по умолчанию).getNoController()
возвращает текущее значение.setNeverController($flag = true)
является аналогомsetNoController()
, но работает на глобальном уровне - т.е. он не будет сбрасываться с каждым обработанным действием.getNeverController()
возвращает текущее значение.setScriptAction($name)
может использоваться для того, чтобы указать скрипт действия для рендеринга.$name
должен быть именем скрипта без суффикса (и без поддиректории контроллера, за исключением того случая, когда включенnoController
). Если не задан, то ищется скрипт вида с именем, аналогичным имени действия в объекте запроса.getScriptAction()
возвращает текущее значение.setResponseSegment($name)
может использоваться для указания того, в какой именованный сегмент объекта ответа следует сохранить результат рендеринга. Если не указан, то выходные данные сохраняются в сегменте, используемом по умолчанию.getResponseSegment()
возвращает текущее значение.initView($path, $prefix, $options
может вызываться для указания базового пути вида, префикса классов помощников и фильтров, опций помощникаViewRenderer
. Вы можете передавать любые из следующих флагов:neverRender
,noRender
,noController
,scriptAction
иresponseSegment
.-
setRender($action = null, $name = null, $noController = false)
позволяет установитьscriptAction
,responseSegment
, илиnoController
за один проход.direct()
является псевдонимом для этого метода, что дает возможность легко вызывать этот метод из вашего контроллера.// Рендеринг 'foo' вместо текущего скрипта вида $this->_helper->viewRenderer('foo'); // Рендеринг form.phtml в сегмент ответа 'html' в обход // поддиректории: $this->_helper->viewRenderer('form', 'html', true);
Замечание setRender()
иdirect()
в действительности не производят рендеринг скрипта вида, а устанавливают закрытые свойства помощника, которыеpostDispatch()
иrender()
будут использовать при рендеринге скрипта вида.
Конструктор позволяет опционально передать объект вида и опции
ViewRenderer
. Он использует те же флаги, что и
initView()
:
$view = new Zend_View(array('encoding' => 'UTF-8')); $options = array('noController' => true, 'neverRender' => true); $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view, $options);
ViewRenderer
имеет несколько дополнительных методов для
создания пользовательских спецификаций пути, используемых для
определения базового пути вида, добавляемого в объект вида, и пути к
определенному скрипту вида, используемого при автоматическом
определении скрипта вида для рендеринга. Все эти методы принимают
одну или более меток заполнения:
:moduleDir
ссылается на текущую базовую директорию модуля (по соглашению это директория, родительская по отношению к директории контроллеров модуля).:module
ссылается на имя текущего модуля.:controller
ссылается на имя текущего контроллера.:action
ссылается на имя текущего действия.:suffix
ссылается на суффикс скрипта вида (который может быть установлен черезsetViewSuffix()
).
Методы для управления спецификациями пути:
setViewBasePathSpec($spec)
позволяет изменить спецификацию пути, используемую для определения базового пути, добавляемого в объект вида. По умолчанию используется спецификация:moduleDir/views
. Вы можете в любое время получить текущую спецификацицию, используя методgetViewBasePathSpec()
.setViewScriptPathSpec($spec)
позволяет изменить спецификацию пути, используемую для определения пути к отдельному скрипту вида (без базового пути скрипта вида). По умолчанию используется спецификация:controller/:action.:suffix
. Вы можете в любое время получить текущую спецификацию, используя методgetViewScriptPathSpec()
.setViewScriptPathNoControllerSpec($spec)
позволяет изменить спецификацию пути, используемую для определения пути к отдельному скрипту вида, когда действуетnoController
(без базового пути скрипта вида). По умолчанию используется спецификация:action.:suffix
. Вы можете в любое время получить текущую спецификацию, используя методgetViewScriptPathNoControllerSpec()
.
Для более детального управления спецификациями путей вы можете
использовать
Zend_Filter_Inflector.
Внутри себя ViewRenderer
уже использует инфлектор для
поиска соответствий. Для взаимодействия с инфлектором - установки
своего собственного инфлектора или изменения используемого по
умолчанию - могут использоваться следующие методы:
-
getInflector()
возвращает инфлектор. Если вViewRenderer
его нет, то метод создает его, используя правила по умолчанию.По умолчанию он использует ссылки на статические правила для суффикса и директории модуля, так же, как и статическую цель. Это дает различным свойствам
ViewRenderer
возможность динамически изменять инфлектор. setInflector($inflector, $reference)
позволяет устанавливать свой инфлектор для использования сViewRenderer
. Если$reference
равен true, то суффикс и директория модуля будут установлены как статические ссылки на свойстваViewRenderer
, так же, как и цель.
Используемые по умолчанию соглашения по поиску | |
---|---|
|
Последними рассматриваемыми элементами в API ViewRenderer
-а являются
методы для собственно определения путей к скриптам вида и
рендеринга видов. Эти методы включают в себя:
-
renderScript($script, $name)
позволяет производить рендеринг скрипта по указанному пути, в опционально заданный именованный сегмент. Если используется этот метод, тоViewRenderer
не производит автоматическое определение имени скрипта, вместо этого он напрямую передает аргумент$script
методуrender()
объекта вида.Замечание После того, как был произведен рендеринг вида в объект ответа, устанавливается
noRender
для предотвращения случайного повторного рендеринга того же скрипта вида.Замечание По умолчанию
Zend_Controller_Action::renderScript()
вызывает методrenderScript()
помощникаViewRenderer
. -
getViewScript($action, $vars)
создает путь к скрипту вида, основываясь на переданном действии $action и/или переменных, переданных в $vars. Этот массив может включать в себя ключи спецификаций пути ('moduleDir', 'module', 'controller', 'action' и 'suffix'). Если была передана переменная, то она будет использована, иначе будут использоваться значения из текущего запроса.getViewScript()
будет использоватьviewScriptPathSpec
, либоviewScriptPathNoControllerSpec
, в зависимости от значения флагаnoController
.Разделители слов в именах модуля, контроллера или действия будут заменены на тире ('-'). Таким образом, если вы имеете контроллер с именем 'foo.bar' и действие 'baz:bat', то при использовании спецификации по умолчанию результатом будет путь 'foo-bar/baz-bat.phtml' к скрипту вида.
Замечание По умолчанию
Zend_Controller_Action::getViewScript()
вызывает методgetViewScript()
ViewRenderer
-а. -
render($action, $name, $noController)
сначала проверяет, были ли переданы параметры$name
или$noController
, и если были переданы, то устанавливает соответствующие флаги (responseSegment и noController соответственно) в ViewRenderer. Затем он передает параметр$action
(если есть) методуgetViewScript()
. Наконец, он передает полученный путь к скрипту вида методуrenderScript()
.Замечание Следует помнить о побочных эффектах использования render(): значения, передаваемые для имени сегмента ответа и флага noController, сохраняются в объекте. Кроме этого, по окончании рендеринга будет установлен noRender.
Замечание По умолчанию
Zend_Controller_Action::render()
вызывает методrender()
помощникаViewRenderer
. renderBySpec($action, $vars, $name)
позволяет передавать переменные спецификации пути для определения создаваемого пути к скрипту вида. Он передает$action
и$vars
методуgetScriptPath()
, затем передает полученный путь и$name
методуrenderScript()
.
Пример 7.10. Базовое использование
В простейшем случае вы просто инициализируете и
регистрируете помощник ViewRenderer
через брокер
помощников в своем файле загрузки и затем устанавливаете
переменные в своих методах действий.
<?php // В вашем файле загрузки: Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); ... <?php // Модуль 'foo', контроллер 'bar': class Foo_BarController extends Zend_Controller_Action { // По умолчанию производится рендеринг bar/index.phtml; // дополнительные действия не требуются public function indexAction() { } // Рендеринг bar/populate.phtml с переменной 'foo', установленной в 'bar'. // Поскольку объект вида был определен в preDispatch(), то он уже // доступен для использования. public function populateAction() { $this->view->foo = 'bar'; } // Ничего не рендерится, т.к. производится переход на другое действие; // это другое действие может производить рендеринг public function bazAction() { $this->_forward('index'); } // Ничего не рендерится, т.к. производится перенаправление по другому адресу public function batAction() { $this->_redirect('/index'); } }
Соглашения по именованию: Разделители слов в именах контроллера и действия | |
---|---|
Если имена вашего контроллера и действия состоят из
нескольких слов, то диспетчер требует, чтобы в URL они были
разделены определенными символами-разделителями слов и
путей.
Во втором примере обратите внимание на то, что по-прежнему
используется модуль по умолчанию, но из-за наличия
разделителя путей получается имя контроллера
|
Пример 7.11. Отключение авторендеринга
Может потребоваться отключить авторендеринг для некоторых
действий или контроллеров - например, если вы хотите производить
вывод другого типа (XML, JSON и т.д.), или просто не хотите
ничего выводить. Есть два варианта - либо полностью
отключить авторендеринг (setNeverRender()
), либо
отключить его для текущего действия
(setNoRender()
).
<?php // Класс контроллера baz, модуль bar: class Bar_BazController extends Zend_Controller_Action { public function fooAction() { // Не производить авторендеринг в этом действии $this->_helper->viewRenderer->setNoRender(); } } // Класс контроллера bat, модуль bar: class Bar_BatController extends Zend_Controller_Action { public function preDispatch() { // Не производить авторендеринг во всех действиях этого контроллера $this->_helper->viewRenderer->setNoRender(); } }
Замечание | |
---|---|
В большинстве случаев не имеет смысла глобально отключать
авторендеринг (через |
Пример 7.12. Выбор другого скрипта вида
В некоторых случаях требуется, чтобы производился рендеринг
скрипта с именем, отличным от имени действия. Например, если у
вас есть контроллер, который имеет методы действий для
добавления и редактирования, они оба могут отображать один и тот
же вид 'форма', хоть и с разным набором значений. Вы легко
можете изменить имя скрипта, используя методы
setScriptAction()
и setRender()
, или
вызывая помощника как метод брокера - этим будет произведен
вызов метода setRender()
.
<?php // Класс контроллера bar, модуль foo: class Foo_BarController extends Zend_Controller_Action { public function addAction() { // Рендерить 'bar/form.phtml' вместо 'bar/add.phtml' $this->_helper->viewRenderer('form'); } public function editAction() { // Рендерить 'bar/form.phtml' вместо 'bar/edit.phtml' $this->_helper->viewRenderer->setScriptAction('form'); } public function processAction() { // произведение валидации... if (!$valid) { // Рендерить 'bar/form.phtml' вместо 'bar/process.phtml' $this->_helper->viewRenderer->setRender('form'); return; } // иначе продолжение обработки... } }
Пример 7.13. Изменение зарегистрированного объекта вида
А что, если нужно модифицировать объект вида - например,
изменить пути к помощникам или кодировку? Вы можете делать это
как через модификацию объекта вида, установленного в вашем
контроллере, так и через извлечение объекта вида из
ViewRenderer
, оба они являются ссылками на один и
тот же объект.
<?php // Класс контроллера bar, модуль foo: class Foo_BarController extends Zend_Controller_Action { public function preDispatch() { // Изменение кодировки вида $this->view->setEncoding('UTF-8'); } public function bazAction() { // Получение объекта вида и указание 'htmlspecialchars' // в качестве функции для экранирования $view = $this->_helper->viewRenderer->view; $view->setEscape('htmlspecialchars'); } }
Пример 7.14. Изменение спецификаций пути
В некоторых случаях вы можете решить, что спецификации пути, используемые по умолчанию, не соответствуют требованиям вашего сайта. Например, вы можете захотеть иметь одно дерево шаблонов, к которому можно давать доступ дизайнерам (что, например, довольно типично в случае использованя Smarty). В таком случае вы можете захотеть задать жесткую спецификацию базового пути вида и создать альтернативную спецификацию для собственно путей к скриптам вида.
В рамках данного примера предположим, что базовый путь к скриптам вида - '/opt/vendor/templates', и вы хотите, чтобы обращение к скриптам вида производилось по схеме ':moduleDir/:controller/:action.:suffix'. Также предположим, что если флаг noController установлен, то нужно, чтобы использовался верхний уровень вместо поддиректории (':action.:suffix'). И наконец, вы хотите использовать 'tpl' в качестве суффикса имени скрипта вида.
<?php /** * В вашем файле загрузки: */ // Другая реализация вида $view = new ZF_Smarty(); $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view); $viewRenderer->setViewBasePathSpec('/opt/vendor/templates') ->setViewScriptPathSpec(':module/:controller/:action.:suffix') ->setViewScriptPathNoControllerSpec(':action.:suffix') ->setViewSuffix('tpl'); Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
Пример 7.15. Рендеринг нескольких скриптов вида из одного действия
Иногда бывает нужно произвести рендеринг нескольких скриптов
вида из одного действия. Решение довольно очевидное - просто
сделайте несколько вызовов метода render()
:
<?php class SearchController extends Zend_Controller_Action { public function resultsAction() { // Предполагается, что $this->model - текущая модель $this->view->results = $this->model->find($this->_getParam('query', ''); // render() по умолчанию использует ViewRenderer // Рендеринг формы поиска и затем результатов поиска $this->render('form'); $this->render('results'); } public function formAction() { // Ничего не делается. ViewRenderer автоматически производит // рендеринг скрипта вида } }
Помощники действий расширяют
Zend_Controller_Action_Helper_Abstract
, абстрактный
класс, дающий базовый интерфейс и функционал, который требуется для
использования с брокером помощников. Он включает в себя следующие
методы:
setActionController()
используется для установки текущего контроллера действий.init()
, запускаемый брокером при инстанцировании, может использоваться для запуска инициализации в помощнике. Это может быть полезным для переустановки состояния, когда несколько контроллеров используют один и тот же помощник в цепочке действий.preDispatch()
запускается до того, как будет запущено действие.postDispatch()
запускается, когда выполнение действия завершилось - даже если плагинpreDispatch()
пропустил это действие. Полезно в основном для очистки.getRequest()
возвращает текущий объект запроса.getResponse()
возвращает текущий объект ответа.getName()
возвращает имя помощника. Он извлекает ту часть имени класса, которая следует после последнего символа подчеркивания, иначе возвращается полное имя класса. Например, если класс называетсяZend_Controller_Action_Helper_Redirector
, то он вернетRedirector
, а если класс называетсяFooMessage
то он просто вернет свое полное имя.
Вы можете опционально добавить метод direct()
в свой
класс помощника. Если он определен, то это позволит вам обращаться к
помощнику как к методу брокера помощников, этим обеспечивается
легкое единовременное использование помощника. Например,
redirector
определяет direct()
как псевдоним метода
goto()
, что позволяет использовать помощника следующим
образом:
<?php // Перенаправление на /blog/view/item/id/42 $this->_helper->redirector('item', 'view', 'blog', array('id' => 42));
Метод брокера помощников __call()
ищет помощника с
именем redirector
, затем смотрит, имеет ли помощник
определенный метод direct
, и, если есть, вызывает его с
переданными аргументами.
Создав собственный класс помощника, вы можете предоставить доступ к нему, как описано в разделах выше.