Action Helpers allow developers to inject runtime and/or on-demand functionality into any Action Controllers that extend Zend_Controller_Action. Action Helpers aim to minimize the necessity to extend the abstract Action Controller in order to inject common Action Controller functionality.
There are a number of ways to use Action Helpers. Action Helpers
employ the use of a brokerage system, similar to the types of
brokerage you see in Zend_View_Helpers, and that
of Zend_Controller_Plugin.
Action Helpers (like Zend_View_Helpers
) may be
loaded and called on demand, or they may be instantiated at
request time (bootstrap) or action controller creation time
(init()). To understand this more fully, please see the usage
section below.
A helper can be initialized in several different ways, based on your needs as well as the functionality of that helper.
The helper broker is stored as the $_helper
member of
Zend_Controller_Action
; use the broker to retrieve or
call on helpers. Some methods for doing so include:
Explicitly using getHelper()
. Simply pass it a
name, and a helper object is returned:
<?php $flashMessenger = $this->_helper->getHelper('FlashMessenger'); $flashMessenger->addMessage('We did something in the last request');
Use the helper broker's __get()
functionality
and retrieve the helper as if it were a member property of
the broker:
<?php $flashMessenger = $this->_helper->FlashMessenger; $flashMessenger->addMessage('We did something in the last request');
Finally, most action helpers implement the method
direct()
which will call a specific, default
method in the helper. In the example of the
FlashMessenger
, it calls
addMessage()
:
<?php $this->_helper->FlashMessenger('We did something in the last request');
Notatka | |
---|---|
All of the above examples are functionally equivalent. |
You may also instantiate helpers explicitly. You may wish to do this if using the helper outside of an action controller, or if you wish to pass a helper to the helper broker for use by any action. Instantiation is as per any other PHP class.
Zend_Controller_Action_HelperBroker
handles the details
of registering helper objects and helper paths, as well as
retrieving helpers on-demand.
To register a helper with the broker, use addHelper
:
<?php Zend_Controller_Action_HelperBroker::addHelper($helper);
Of course, instantiating and passing helpers to the broker is a bit
time and resource intensive, so two methods exists to automate
things slightly: addPrefix()
and
addPath()
.
addPrefix()
takes a class prefix and uses it
to determine a path where helper classes have been defined.
It assumes the prefix follows Zend Framework class naming
conventions.
<?php // Add helpers prefixed with My_Action_Helpers in My/Action/Helpers/ Zend_Controller_Action_HelperBroker::addPrefix('My_Action_Helpers');
addPath()
takes a directory as its first
argument and a class prefix as the second argument
(defaulting to 'Zend_Controller_Action_Helper'). This allows
you to map your own class prefixes to specific directories.
<?php // Add helpers prefixed with Helper in Plugins/Helpers/ Zend_Controller_Action_HelperBroker::addPath('./Plugins/Helpers', 'Helper');
Since these methods are static, they may be called at any point in the controller chain in order to dynamically add helpers as needed.
To determine if a helper exists in the helper broker, use
hasHelper($name)
, where $name
is the short
name of the helper (minus the prefix):
<?php // Check if 'redirector' helper is registered with the broker: if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) { echo 'Redirector helper registered }
Finally, to delete a registered helper from the broker, use
removeHelper($name)
, where $name
is the
short name of the helper (minus the prefix):
<?php // Conditionally remove the 'redirector' helper from the broker: if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) { Zend_Controller_Action_HelperBroker::removeHelper('redirector') }
Zend Framework includes three action helpers by default: a FlashMessenger for handling session flash messages; a Redirector, to provide different implementations for redirecting to internal and external pages from your application; and a ViewRenderer to automate the process of setting up the view object in your controllers and rendering views.
The FlashMessenger
helper allows you to pass messages
that the user may need to see on the next request. To accomplish
this, FlashMessenger
uses
Zend_Session_Namespace
to store messages for future or
next request retrieval. It is generally a good idea that if you
plan on using Zend_Session
or
Zend_Session_Namespace
, that you initialize with
Zend_Session::start()
in your bootstrap file. (See
Zend Session
for more details on its usage.)
The usage example below shows the use of the flash messenger at its
most basic. When the action /some/my
is called, it adds
the flash message "Record Saved!" A subsequent request to the action
/some/my-next-request
will retrieve it (and thus delete
it as well).
<?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(); } }
The Redirector
helper allows you to use a redirector
object to fufill your application's needs for redirecting to a new
URL. It provides numerous benefits over the
_redirect()
method, such as being able to preconfigure
sitewide behavior into the redirector object or using the built in
goto($action, $controller, $module, $params)
interface
similar to that of Zend_Controller_Action::_forward()
.
The Redirector
has a number of methods that can be used
to affect the behaviour at redirect:
setCode()
can be used to set the HTTP response
code to use during the redirect.
setExit()
can be used to force an
exit()
following a redirect. By default this is
true.
setGoto()
can be used to set a default URL to
use if none is passed to goto()
. Uses the API
of Zend_Controller_Action::_forward()
:
setgoto($action, $controller = null, $module = null, array
$params = array());
setGotoRoute()
can be used to set a URL
based on a registered route. Pass in an array of key/value
pairs and a route name, and it will assemble the URL
according to the route type and definition.
setGotoUrl()
can be used to set a default URL to
use if none is passed to gotoUrl()
. Accepts a
single URL string.
setPrependBase()
can be used to prepend the
request object's base URL to a URL specified with
setGotoUrl()
, gotoUrl()
, or
gotoUrlAndExit()
.
Additionally, there are a variety of methods in the redirector for performing the actual redirects:
goto()
uses setGoto()
(_forward()-like API
) to build a URL and
perform a redirect.
gotoRoute()
uses setGotoRoute()
(route-assembly
) to build a URL and
perform a redirect.
gotoUrl()
uses setGotoUrl()
(URL string
) to build a URL and
perform a redirect.
Finally, you can determine the current redirect URL at any time
using getRedirectUrl()
.
Przykład 7.1. Setting Options
This example overrides several options, including setting the HTTP status code to use in the redirect ('303'), not defaulting to exit on redirect, and defining a default URL to use when redirecting.
<?php class SomeController extends Zend_Controller_Action { /** * Redirector - defined for code completion * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); // Set the default options for the redirector // Since the object is registered in the helper broker, these become // relevant for all actions from this point forward $this->_redirector->setCode('303') ->setExit(false) ->setGoto("this-action", "some-controller"); } public function myAction() { /* do some stuff */ // Redirect to a previously registered URL, and force an exit to occur // when done: $this->_redirector->redirectAndExit(); return; // never reached } } ?>
Przykład 7.2. Using Defaults
This example assumes that the defaults are used, which means
that any redirect will result in an immediate
exit()
.
<?php // ALTERNATIVE EXAMPLE class AlternativeController extends Zend_Controller_Action { /** * Redirector - defined for code completion * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); } public function myAction() { /* do some stuff */ $this->_redirector->gotoUrl('/my-controller/my-action/param1/test/param2/test2'); return; // never reached since default is to goto and exit } } ?>
Przykład 7.3. Using goto()'s _forward() API
goto()
's API mimics that of
Zend_Controller_Action::_forward()
. The primary
difference is that it builds a URL from the parameters passed,
and using the default :module/:controller/:action/*
format of the default router. It then redirects instead of
chaining the action.
<?php class ForwardController extends Zend_Controller_Action { /** * Redirector - defined for code completion * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); } public function myAction() { /* do some stuff */ // Redirect to 'my-action' of 'my-controller' in the current module, // using the params param1 => test and param2 => test2 $this->_redirector->goto('my-action', 'my-controller', null, array('param1' => 'test', 'param2' => 'test2')); } } ?>
Przykład 7.4. Using route assembly with gotoRout()
The following example uses the router's
assemble()
method to create a URL based on an
associative array of parameters passed. It assumes the following
route has been registered:
<?php $route = new Zend_Controller_Router_Route( 'blog/:year/:month/:day/:id', array('controller' => 'archive', 'module' => 'blog', 'action' => 'view') ); $router->addRoute('blogArchive', $route); ?>
Given an array with year set to 2006, month to 4, day to 24, and
id to 42, it would then build the URL
/blog/2006/4/24/42
.
<?php class BlogAdminController extends Zend_Controller_Action { /** * Redirector - defined for code completion * * @var Zend_Controller_Action_Helper_Redirector */ protected $_redirector = null; public function init() { $this->_redirector = $this->_helper->getHelper('Redirector'); } public function returnAction() { /* do some stuff */ // Redirect to blog archive. Builds the following URL: // /blog/2006/4/24/42 $this->_redirector->gotoRoute( array('year' => 2006, 'month' => 4, 'day' => 24, 'id' => 42), 'blogArchive' ); } } ?>
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.
Notatka | |
---|---|
If you perform a |
Notatka | |
---|---|
The
If you wish to modify settings of the
|
At its most basic usage, you simply instantiate the
ViewRenderer
and pass it to the action helper broker:
<?php Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer());
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:
<?php // A controller class, foo module: class Foo_BarController extends Zend_Controller_Action { // Render bar/index.phtml by default; no action required public function indexAction() { } // Render bar/populate.phtml with variable 'foo' set to 'bar'. // Since view object defined at preDispatch(), it's already available. public function populateAction() { $this->view->foo = 'bar'; } } ?> // in one of your view scripts: <?php $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.
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:
// Render 'foo' instead of current action script $this->_helper->viewRenderer('foo'); // render form.phtml to the 'html' response segment, without using a // controller view script subdirectory: $this->_helper->viewRenderer('form', 'html', true);
Notatka | |
---|---|
|
The constructor allows you to optionally pass the view object and
ViewRenderer
options; it accepts the same flags as
initView()
:
$view = new Zend_View(array('encoding' => '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()
.
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.
Notatka | |
---|---|
Once the view has been rendered to the response object, it
sets the |
Notatka | |
---|---|
By default,
|
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'.
Notatka | |
---|---|
By default,
|
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()
.
Notatka | |
---|---|
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. |
Notatka | |
---|---|
By default,
|
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()
.
Przykład 7.5. Basic Usage
At its most basic, you simply add the ViewRenderer
helper to the helper broker in your bootstrap, and then set
variables in your action methods.
<?php // In your bootstrap: Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer()); ?> <?php // A controller class, foo module: class Foo_BarController extends Zend_Controller_Action { // Render bar/index.phtml by default; no action required public function indexAction() { } // Render bar/populate.phtml with variable 'foo' set to 'bar'. // Since view object defined at preDispatch(), it's already available. public function populateAction() { $this->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'); } } ?>
Przykład 7.6. 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()
).
Notatka | |
---|---|
In most cases, it makes no sense to turn off autorendering
globally (ala |
<?php // Baz controller class, bar module: class Bar_BazController extends Zend_Controller_Action { public function fooAction() { // Don't auto render this action $this->_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(); } } ?>
Przykład 7.7. 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()
.
<?php // Bar controller class, foo module: class Foo_BarController extends Zend_Controller_Action { public function addAction() { // Render 'bar/form.phtml' instead of 'bar/add.phtml' $this->_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... } } ?>
Przykład 7.8. 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.
<?php // Bar controller class, foo module: class Foo_BarController extends Zend_Controller_Action { public function preDispatch() { // change view encoding $this->view->setEncoding('UTF-8'); } public function bazAction() { // Get view object and set escape callback to 'htmlspecialchars' $view = $this->_helper->viewRenderer->view; $view->setEscape('htmlspecialchars'); } } ?>
Przykład 7.9. Changing 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.
<?php /** * In your bootstrap: */ // Different view implementation $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_View_Controller_HelperBroker::addHelper($viewRenderer);
Przykład 7.10. 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()
:
<?php class SearchController extends Zend_Controller_Action { public function resultsAction() { // Assume $this->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 } }
Action helpers extend
Zend_Controller_Action_Helper_Abstract
, an abstract
class that provides the basic interface and functionality required
by the helper broker. These include the following methods:
setActionController()
is used to set the current
action controller.
init()
, triggered by the helper broker at
instantiation, can be used to trigger initialization in the
helper; this can be useful for resetting state when multiple
controllers use the same helper in chained actions.
preDispatch()
, is triggered prior to a
dispatched action.
postDispatch()
is triggered when a dispatched
action is done -- even if a preDispatch()
plugin has skipped the action. Mainly useful for cleanup.
getRequest()
retrieves the current request
object.
getResponse()
retrieves the current response
object.
getName()
retrieves the helper name. It
retrieves the portion of the class name following the last
underscore character, or the full class name otherwise. As
an example, if the class is named
Zend_Controller_Action_Helper_Redirector
, it
will return Redirector
; a class named
FooMessage
will simply return itself.
You may optionally include a direct()
method in your
helper class. If defined, it allows you to treat the helper as a
method of the helper broker, in order to allow easy, one-off usage
of the helper. As an example, the redirector
defines direct()
as an alias of goto()
,
allowing use of the helper like this:
<?php // Redirect to /blog/view/item/id/42 $this->_helper->redirector('item', 'view', 'blog', array('id' => 42)); ?>
Internally, the helper broker's __call()
method looks
for a helper named redirector
, then checks to see if
that helper has a defined direct
class, and calls it
with the arguments provided.
Once you have created your own helper class, you may provide access to it as described in the sections above.