ViewRendererВведение
Помощник ViewRenderer предназначен для решения
следующих задач:
Устранение необходимости инстанцирования объектов вида
внутри контроллеров; объекты вида будут автоматически
регистрироваться вместе с контроллером.
Автоматическая установка путей к скриптам вида, помощникам
и фильтрам, основанная на текущем модуле, и автоматическое
присоединение имени текущего модуля в качестве префикса имен
классов помощников и фильтров.
Создание глобально доступного объекта вида для всех
запускаемых контроллеров и действий.
Возможность устанавливать используемые по
умолчанию опции рендеринга для всех контроллеров.
Возможность автоматического рендеринга скрипта
вида, не требующего от разработчика каких-либо действий.
Возможность создавать собственные спецификации базового пути
вида и путей к скриптам видов.
Если вы вручную производите _forward(),
перенаправление или render, то авторендеринг не
будет произведен, поскольку выполнение любых этих операций
говорит помощнику ViewRenderer, что вы определили
свой собственный вывод.
ViewRenderer включен по умолчанию. Вы можете
отключить его через параметр фронт-контроллера
noViewRenderer
($front->setParam('noViewRenderer', true)) или
посредством удаления помощника из стека брокера помощников
(Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer')).
Если вы хотите изменить настройки ViewRenderer до
начала диспетчеризации, то можете сделать это одним из двух
способов:
Инстанцировать и зарегистрировать свой объект
ViewRenderer, а затем передать его брокеру
помощников:
setView($view)
->setViewSuffix('php');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
]]>
Инициализировать и/или извлечь по запросу объект
ViewRenderer через брокер помощников:
setView($view)
->setViewSuffix('php');
]]>API
В простейшем варианте использования вы просто инстанцируете
ViewRenderer и передаете его брокеру помощников.
Наиболее легким способом его инстанцирования и регистрации является
использование метода getStaticHelper() брокера
помощников:
Во время инстанцирования контроллера действий производится вызов
ViewRenderer для инстанцирования объекта вида. Каждый
раз, когда инстанцируется контроллер, вызывается метод
init() помощника ViewRenderer, что
приводит к установке свойства $view данного контроллера
действий и вызову метода addScriptPath() с путем
относительно текущего модуля; он будет вызван с префиксом класса,
соответствующим имени текущего модуля, что эффективно
разделяет пространства имен всех классов помощников и фильтров,
определенных для этого модуля.
Каждый раз, когда вызывается postDispatch(), он будет
вызывать render() для текущего действия.
В качестве примера рассмотрим следующий класс:
view->foo = 'bar';
}
}
...
// в одном из ваших скриптов вида:
$this->foo(); // вызывает 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() является псевдонимом для этого метода,
что дает возможность легко вызывать этот метод из вашего
контроллера.
_helper->viewRenderer('foo');
// Рендеринг form.phtml в сегмент ответа 'html' в обход
// поддиректории:
$this->_helper->viewRenderer('form', 'html', true);
]]>setRender() и direct() в
действительности не производят рендеринг скрипта вида, а
устанавливают закрытые свойства помощника, которые
postDispatch() и render()
будут использовать при рендеринге скрипта вида.
Конструктор позволяет опционально передать объект вида и опции
ViewRenderer. Он использует те же флаги, что и
initView():
'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, так же, как и цель.
Используемые по умолчанию соглашения по поискуViewRenderer производит некоторую нормализацию пути
для облегчения поиска скрипта вида. Используемые по умолчанию
правила:
:module: СловаРазделенныеРегистром
(CamelCase) разделяются тире и вся строка приводится к
нижнему регистру. Например: "FooBarBaz" преобразуется в
"foo-bar-baz".
Внутри себя инфлектор использует фильтры
Zend_Filter_Word_CamelCaseToDash и
Zend_Filter_StringToLower.
:controller:
СловаРазделенныеРегистром (CamelCase) разделяются
тире, знаки подчеркивания преобразуются в разделители
директорий и вся строка приводится к нижнему регистру.
Например: "FooBar" преобразуется в "foo-bar";
"FooBar_Admin" преобразуется в "foo-bar/admin".
Внутри себя инфлектор использует фильтры
Zend_Filter_Word_CamelCaseToDash,
Zend_Filter_Word_UnderscoreToSeparator и
Zend_Filter_StringToLower.
:action:
СловаРазделенныеРегистром (CamelCase) разделяются
тире, символы, не являющиеся буквенно-цифровыми,
переводятся в тире и
вся строка приводится к нижнему регистру.
Например: "fooBar" преобразуется в "foo-bar";
"foo-barBaz" преобразуется в "foo-bar-baz".
Внутри себя инфлектор использует фильтры
Zend_Filter_Word_CamelCaseToDash,
Zend_Filter_PregReplace и
Zend_Filter_StringToLower.
Последними рассматриваемыми элементами в 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().
Примеры базового использованияБазовое использование
В простейшем случае вы просто инициализируете и
регистрируете помощник ViewRenderer через брокер
помощников в своем файле загрузки и затем устанавливаете
переменные в своих методах действий.
view->foo = 'bar';
}
// Ничего не рендерится, т.к. производится переход на другое действие;
// это другое действие может производить рендеринг
public function bazAction()
{
$this->_forward('index');
}
// Ничего не рендерится, т.к. производится перенаправление по другому адресу
public function batAction()
{
$this->_redirect('/index');
}
}
]]>Соглашения по именованию: Разделители слов в именах контроллера и действия
Если имена вашего контроллера и действия состоят из
нескольких слов, то диспетчер требует, чтобы в URL они были
разделены определенными символами-разделителями слов и
путей. ViewRenderer при создании путей заменяет все
найденные в имени контроллера разделители путей действующим
разделителем путей ('/') и все разделители слов - чертой
('-'). Таким образом, вызов действия
/foo.bar/baz.bat должен быть преобразован в
вызов метода FooBarController::bazBatAction() в
FooBarController.php, который в свою очередь
произведет рендеринг скрипта вида foo-bar/baz-bat.phtml.
Вызов действия /bar_baz/baz-bat должен быть
преобразован в вызов
Bar_BazController::bazBatAction() в
Bar/BazController.php (обратите внимание на
разделение путей), при этом производится рендеринг
bar/baz/baz-bat.phtml.
Во втором примере обратите внимание на то, что по-прежнему
используется модуль по умолчанию, но из-за наличия
разделителя путей получается имя контроллера
Bar_BazController в файле
Bar/BazController.php. ViewRenderer
имитирует иерархию директорий контроллеров.
Отключение авторендеринга
Может потребоваться отключить авторендеринг для некоторых
действий или контроллеров - например, если вы хотите производить
вывод другого типа (XML, JSON и т.д.), или просто не хотите
ничего выводить. Есть два варианта - либо полностью
отключить авторендеринг (setNeverRender()), либо
отключить его для текущего действия
(setNoRender()).
_helper->viewRenderer->setNoRender();
}
}
// Класс контроллера bat, модуль bar:
class Bar_BatController extends Zend_Controller_Action
{
public function preDispatch()
{
// Не производить авторендеринг во всех действиях этого контроллера
$this->_helper->viewRenderer->setNoRender();
}
}
]]>
В большинстве случаев не имеет смысла глобально отключать
авторендеринг (через setNeverRender()), поскольку
единственная выгода, которую вы получаете в этом случае от
использования ViewRenderer - автоматическая
установка объекта вида.
Выбор другого скрипта вида
В некоторых случаях требуется, чтобы производился рендеринг
скрипта с именем, отличным от имени действия. Например, если у
вас есть контроллер, который имеет методы действий для
добавления и редактирования, они оба могут отображать один и тот
же вид 'форма', хоть и с разным набором значений. Вы легко
можете изменить имя скрипта, используя методы
setScriptAction() и setRender(), или
вызывая помощника как метод брокера - этим будет произведен
вызов метода setRender().
_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;
}
// иначе продолжение обработки...
}
}
]]>Изменение зарегистрированного объекта вида
А что, если нужно модифицировать объект вида - например,
изменить пути к помощникам или кодировку? Вы можете делать это
как через модификацию объекта вида, установленного в вашем
контроллере, так и через извлечение объекта вида из
ViewRenderer, оба они являются ссылками на один и
тот же объект.
view->setEncoding('UTF-8');
}
public function bazAction()
{
// Получение объекта вида и указание 'htmlspecialchars'
// в качестве функции для экранирования
$view = $this->_helper->viewRenderer->view;
$view->setEscape('htmlspecialchars');
}
}
]]>Примеры продвинутого использованияИзменение спецификаций пути
В некоторых случаях вы можете решить, что спецификации пути,
используемые по умолчанию, не соответствуют требованиям вашего
сайта. Например, вы можете захотеть иметь одно дерево шаблонов,
к которому можно давать доступ дизайнерам (что, например,
довольно типично в случае использованя
Smarty).
В таком случае вы можете захотеть задать жесткую
спецификацию базового пути вида и создать альтернативную
спецификацию для собственно путей к скриптам вида.
В рамках данного примера предположим, что базовый путь к
скриптам вида - '/opt/vendor/templates', и вы хотите, чтобы
обращение к скриптам вида производилось по схеме
':moduleDir/:controller/:action.:suffix'. Также предположим, что
если флаг noController установлен, то нужно, чтобы использовался
верхний уровень вместо поддиректории (':action.:suffix'). И
наконец, вы хотите использовать 'tpl' в качестве суффикса имени
скрипта вида.
setViewBasePathSpec('/opt/vendor/templates')
->setViewScriptPathSpec(':module/:controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
]]>Рендеринг нескольких скриптов вида из одного действия
Иногда бывает нужно произвести рендеринг нескольких скриптов
вида из одного действия. Решение довольно очевидное - просто
сделайте несколько вызовов метода render():
model - текущая модель
$this->view->results =
$this->model->find($this->_getParam('query', '');
// render() по умолчанию использует ViewRenderer
// Рендеринг формы поиска и затем результатов поиска
$this->render('form');
$this->render('results');
}
public function formAction()
{
// Ничего не делается. ViewRenderer автоматически производит
// рендеринг скрипта вида
}
}
]]>