ViewRendererIntroduction
The ViewRenderer helper is designed to satisfy the
following goals:
Eliminate the need to instantiate view objects within
controllers; view objects will be automatically registered
with the controller.
Automatically set view script, helper, and filter paths
based on the current module, and automatically associate
the current module name as a class prefix for helper and
filter classes.
Create a globally available view object for all dispatched
controllers and actions.
Allow the developer to set default view rendering options
for all controllers.
Add the ability to automatically render a view script with
no intervention.
Allow the developer to create her own specifications for
the view base path and for view script paths.
If you perform a _forward(),
redirect(), or
render() manually, autorendering will not occur, as
by performing any of these actions you are telling the
ViewRenderer that you are determining your own
output.
The ViewRenderer is enabled by default. You may
disable it via the front controller noViewRenderer
param ($front->setParam('noViewRenderer', true);) or
removing the helper from the helper broker stack
(Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer')).
If you wish to modify settings of the ViewRenderer
prior to dispatching the front controller, you may do so in one
of two ways:
Instantiate and register your own
ViewRenderer object and pass it to the
helper broker:
setView($view)
->setViewSuffix('php');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
]]>
Initialize and/or retrieve a ViewRenderer
object on demand via the helper broker:
setView($view)
->setViewSuffix('php');
]]>API
At its most basic usage, you simply instantiate the
ViewRenderer and pass it to the action helper broker.
The easiest way to instantiate it and register in one go is to use
the helper broker's getStaticHelper() method:
The first time an action controller is instantiated, it will trigger
the ViewRenderer to instantiate a view object. Each
time a controller is instantiated, the ViewRenderer's
init() method is called, which will cause it to set the
view property of the action controller, and call
addScriptPath() with a path relative to the current
module; this will be called with a class prefix named after the
current module, effectively namespacing all helper and filter
classes you define for the module.
Each time postDispatch() is called, it will call
render() for the current action.
As an example, consider the following class:
view->foo = 'bar';
}
}
...
// in one of your view scripts:
$this->foo(); // call Foo_View_Helper_Foo::foo()
]]>
The ViewRenderer also defines a number of accessors to
allow setting and retrieving view options:
setView($view) allows you to set the view
object for the ViewRenderer. It gets set as
the public class property $view.
setNeverRender($flag = true) can be used to
disable or enable autorendering globally, i.e., for all
controllers. If set to TRUE,
postDispatch()
will not automatically call render() in the
current controller. getNeverRender() retrieves
the current value.
setNoRender($flag = true) can be used to
disable or enable autorendering. If set to TRUE,
postDispatch() will not automatically call
render() in the current controller. This
setting is reset each time preDispatch() is
called (i.e., you need to set this flag for each controller
for which you don't want autorenderering to occur).
getNoRender() retrieves the current value.
setNoController($flag = true) can be used to
tell render() not to look for the action script
in a subdirectory named after the controller (which is the
default behaviour). getNoController() retrieves
the current value.
setNeverController($flag = true) is analogous
to setNoController(), but works on a global
level -- i.e., it will not be reset for each dispatched
action. getNeverController() retrieves
the current value.
setScriptAction($name) can be used to
specify the action script to render. $name
should be the name of the script minus the file suffix (and
without the controller subdirectory, unless
noController has been turned on). If not
specified, it looks for a view script named after the action
in the request object. getScriptAction()
retrieves the current value.
setResponseSegment($name) can be used to
specify which response object named segment to render into.
If not specified, it renders into the default segment.
getResponseSegment() retrieves the current
value.
initView($path, $prefix, $options) may be called
to specify the base view path, class prefix for helper and
filter scripts, and ViewRenderer options. You
may pass any of the following flags:
neverRender, noRender,
noController, scriptAction, and
responseSegment.
setRender($action = null, $name = null, $noController
= false) allows you to set any of
scriptAction, responseSegment, and
noController in one pass. direct()
is an alias to this method, allowing you to call this method
easily from your controller:
_helper->viewRenderer('foo');
// render form.phtml to the 'html' response segment, without using a
// controller view script subdirectory:
$this->_helper->viewRenderer('form', 'html', true);
]]>setRender() and direct()
don't actually render the view script, but instead set hints
that postDispatch() and
render() will use to render the view.
The constructor allows you to optionally pass the view object and
ViewRenderer options; it accepts the same flags as
initView():
'UTF-8'));
$options = array('noController' => true, 'neverRender' => true);
$viewRenderer =
new Zend_Controller_Action_Helper_ViewRenderer($view, $options);
]]>
There are several additional methods for customizing path
specifications used for determining the view base path to add to the
view object, and the view script path to use when autodetermining
the view script to render. These methods each take one or more of
the following placeholders:
:moduleDir refers to the current module's base
directory (by convention, the parent directory of the
module's controller directory).
:module refers to the current module name.
:controller refers to the current controller name.
:action refers to the current action name.
:suffix refers to the view script suffix (which
may be set via setViewSuffix()).
The methods for controlling path specifications are:
setViewBasePathSpec($spec) allows you to change
the path specification used to determine the base path to
add to the view object. The default specification is
:moduleDir/views. You may retrieve the current
specification at any time using
getViewBasePathSpec().
setViewScriptPathSpec($spec) allows you to
change the path specification used to determine the path to
an individual view script (minus the base view script path).
The default specification is
:controller/:action.:suffix. You may retrieve
the current specification at any time using
getViewScriptPathSpec().
setViewScriptPathNoControllerSpec($spec) allows
you to change the path specification used to determine the
path to an individual view script when
noController is in effect (minus the base view
script path). The default specification is
:action.:suffix. You may retrieve the current
specification at any time using
getViewScriptPathNoControllerSpec().
For fine-grained control over path specifications, you may use
Zend_Filter_Inflector.
Under the hood, the ViewRenderer uses an inflector to
perform path mappings already. To interact with the inflector --
either to set your own for use, or to modify the default inflector,
the following methods may be used:
getInflector() will retrieve the inflector. If
none exists yet in the ViewRenderer, it creates
one using the default rules.
By default, it uses static rule references for the suffix
and module directory, as well as a static target; this
allows various ViewRenderer properties the
ability to dynamically modify the inflector.
setInflector($inflector, $reference) allows you
to set a custom inflector for use with the
ViewRenderer. If $reference is
TRUE, it will set the suffix and module directory as static
references to ViewRenderer properties, as well
as the target.
Default Lookup Conventions
The ViewRenderer does some path normalization to
make view script lookups easier. The default rules are as
follows:
:module: MixedCase and camelCasedWords are separated by
dashes, and the entire string cast to lowercase. E.g.:
"FooBarBaz" becomes "foo-bar-baz".
Internally, the inflector uses the filters
Zend_Filter_Word_CamelCaseToDash and
Zend_Filter_StringToLower.
:controller: MixedCase and camelCasedWords are
separated by dashes; underscores are converted to directory
separators, and the entire string cast to lower case.
Examples: "FooBar" becomes "foo-bar";
"FooBar_Admin" becomes
"foo-bar/admin".
Internally, the inflector uses the filters
Zend_Filter_Word_CamelCaseToDash,
Zend_Filter_Word_UnderscoreToSeparator, and
Zend_Filter_StringToLower.
:action: MixedCase and camelCasedWords are separated
by dashes; non-alphanumeric characters are translated to
dashes, and the entire string cast to lower case.
Examples: "fooBar" becomes "foo-bar"; "foo-barBaz"
becomes "foo-bar-baz".
Internally, the inflector uses the filters
Zend_Filter_Word_CamelCaseToDash,
Zend_Filter_PregReplace, and
Zend_Filter_StringToLower.
The final items in the ViewRenderer API are the
methods for actually determining view script paths and rendering views.
These include:
renderScript($script, $name) allows you to
render a script with a path you specify, optionally to a
named path segment. When using this method, the
ViewRenderer does no autodetermination of the
script name, but instead directly passes the
$script argument directly to the view object's
render() method.
Once the view has been rendered to the response object, it
sets the noRender to prevent accidentally
rendering the same view script multiple times.
By default,
Zend_Controller_Action::renderScript()
proxies to the ViewRenderer's
renderScript() method.
getViewScript($action, $vars) creates the path
to a view script based on the action passed and/or any
variables passed in $vars. Keys for this array
may include any of the path specification keys ('moduleDir',
'module', 'controller', 'action', and 'suffix'). Any
variables passed will be used; otherwise, values based on
the current request will be utlized.
getViewScript() will use either the
viewScriptPathSpec or
viewScriptPathNoControllerSpec based on the
setting of the noController flag.
Word delimiters occurring in module, controller, or action names will be
replaced with dashes ('-'). Thus, if you have the controller name
'foo.bar' and the action 'baz:bat', using
the default path specification will result in a view script path of
'foo-bar/baz-bat.phtml'.
By default,
Zend_Controller_Action::getViewScript()
proxies to the ViewRenderer's
getViewScript() method.
render($action, $name, $noController) checks
first to see if either $name or
$noController have been passed, and if so, sets
the appropriate flags (responseSegment and noController,
respectively) in the ViewRenderer. It then passes the
$action argument, if any, on to
getViewScript(). Finally, it passes the
calculated view script path to renderScript().
Be aware of the side-effects of using render(): the
values you pass for the response segment name and for
the noController flag will persist in the object.
Additionally, noRender will be set after rendering is
completed.
By default,
Zend_Controller_Action::render() proxies to
the ViewRenderer's render()
method.
renderBySpec($action, $vars, $name) allows you
to pass path specification variables in order to determine
the view script path to create. It passes
$action and $vars to
getScriptPath(), and then passes the resulting
script path and $name on to
renderScript().
Basic Usage ExamplesBasic Usage
At its most basic, you simply initialize and register the
ViewRenderer helper with the helper broker in your
bootstrap, and then set variables in your action methods.
view->foo = 'bar';
}
// Renders nothing as it forwards to another action; the new action
// will perform any rendering
public function bazAction()
{
$this->_forward('index');
}
// Renders nothing as it redirects to another location
public function batAction()
{
$this->_redirect('/index');
}
}
]]>Naming Conventions: Word Delimiters in Controller and Action Names
If your controller or action name is composed of several
words, the dispatcher requires that these are separated on
the URL by specific path and word delimiter characters. The
ViewRenderer replaces any path delimiter found
in the controller name with an actual path delimiter ('/'),
and any word delimiter found with a dash ('-') when creating
paths. Thus, a call to the action
/foo.bar/baz.bat would dispatch to
FooBarController::bazBatAction() in
FooBarController.php, which would render
foo-bar/baz-bat.phtml; a call to the action
/bar_baz/baz-bat would dispatch to
Bar_BazController::bazBatAction() in
Bar/BazController.php (note the path
separation) and render bar/baz/baz-bat.phtml.
Note that the in the second example, the module is still the
default module, but that, because of the existence of a path
separator, the controller receives the name
Bar_BazController, in
Bar/BazController.php. The ViewRenderer mimics
the controller directory hierarchy.
Disabling Autorender
For some actions or controllers, you may want to turn off the
autorendering -- for instance, if you're wanting to emit a
different type of output (XML, JSON, etc),
or if you simply want
to emit nothing. You have two options: turn off all cases of
autorendering (setNeverRender()), or simply turn it
off for the current action (setNoRender()).
_helper->viewRenderer->setNoRender();
}
}
// Bat controller class, bar module:
class Bar_BatController extends Zend_Controller_Action
{
public function preDispatch()
{
// Never auto render this controller's actions
$this->_helper->viewRenderer->setNoRender();
}
}
]]>
In most cases, it makes no sense to turn off autorendering
globally (ala setNeverRender()), as the only thing
you then gain from ViewRenderer is the autosetup of
the view object.
Choosing a Different View Script
Some situations require that you render a different script than
one named after the action. For instance, if you have a
controller that has both add and edit actions, they may both
display the same 'form' view, albeit with different values set.
You can easily change the script name used with either
setScriptAction(), setRender(),
or calling the helper as a method, which will invoke
setRender().
_helper->viewRenderer('form');
}
public function editAction()
{
// Render 'bar/form.phtml' instead of 'bar/edit.phtml'
$this->_helper->viewRenderer->setScriptAction('form');
}
public function processAction()
{
// do some validation...
if (!$valid) {
// Render 'bar/form.phtml' instead of 'bar/process.phtml'
$this->_helper->viewRenderer->setRender('form');
return;
}
// otherwise continue processing...
}
}
]]>Modifying the Registered View
What if you need to modify the view object -- for instance,
change the helper paths, or the encoding? You can do so either
by modifying the view object set in your controller, or by
grabbing the view object out of the ViewRenderer;
both are references to the same object.
view->setEncoding('UTF-8');
}
public function bazAction()
{
// Get view object and set escape callback to 'htmlspecialchars'
$view = $this->_helper->viewRenderer->view;
$view->setEscape('htmlspecialchars');
}
}
]]>Advanced Usage ExamplesChanging the Path Specifications
In some circumstances, you may decide that the default path
specifications do not fit your site's needs. For instance, you
may want to have a single template tree to which you may then
give access to your designers (this is very typical when using
Smarty, for
instance). In such a case, you may want to hardcode the view
base path specification, and create an alternate specification
for the action view script paths themselves.
For purposes of this example, let's assume that the base path to
views should be '/opt/vendor/templates', and that you wish for
view scripts to be referenced by
':moduleDir/:controller/:action.:suffix'; if the
noController
flag has been set, you want to render out of the top level
instead of in a subdirectory (':action.:suffix'). Finally, you
want to use 'tpl' as the view script filename suffix.
setViewBasePathSpec('/opt/vendor/templates')
->setViewScriptPathSpec(':module/:controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
]]>Rendering Multiple View Scripts from a Single Action
At times, you may need to render multiple view scripts from a
single action. This is very straightforward -- simply make
multiple calls to render():
model is the current model
$this->view->results =
$this->model->find($this->_getParam('query', '');
// render() by default proxies to the ViewRenderer
// Render first the search form and then the results
$this->render('form');
$this->render('results');
}
public function formAction()
{
// do nothing; ViewRenderer autorenders the view script
}
}
]]>