[GENERIC] Zend_Translate:
[zend.git] / documentation / manual / en / module_specs / Zend_Controller-ActionController.xml
blobaa40660193bc8fac45ea5338df387d2ba92042a7
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.controller.action">
4     <title>Action Controllers</title>
6     <sect2 id="zend.controller.action.introduction">
7         <title>Introduction</title>
9         <para>
10             <classname>Zend_Controller_Action</classname> is an abstract class you may use
11             for implementing Action Controllers for use with the Front
12             Controller when building a website based on the
13             Model-View-Controller (<acronym>MVC</acronym>) pattern.
14         </para>
16         <para>
17             To use <classname>Zend_Controller_Action</classname>, you will need to
18             subclass it in your actual action controller classes (or subclass it
19             to create your own base class for action controllers). The most
20             basic operation is to subclass it, and create action methods that
21             correspond to the various actions you wish the controller to handle
22             for your site. <classname>Zend_Controller</classname>'s routing and dispatch handling
23             will autodiscover any methods ending in 'Action' in your class as
24             potential controller actions.
25         </para>
27         <para>
28             For example, let's say your class is defined as follows:
29         </para>
31         <programlisting language="php"><![CDATA[
32 class FooController extends Zend_Controller_Action
34     public function barAction()
35     {
36         // do something
37     }
39     public function bazAction()
40     {
41         // do something
42     }
44 ]]></programlisting>
46         <para>
47             The above <emphasis>FooController</emphasis> class (controller
48             <emphasis>foo</emphasis>) defines two actions, <emphasis>bar</emphasis> and
49             <emphasis>baz</emphasis>.
50         </para>
52         <para>
53             There's much more that can be accomplished than this, such as custom
54             initialization actions, default actions to call should no action (or
55             an invalid action) be specified, pre- and post-dispatch hooks, and a
56             variety of helper methods. This chapter serves as an overview of the
57             action controller functionality
58         </para>
60         <note>
61             <title>Default Behaviour</title>
63             <para>
64                 By default, the <link linkend="zend.controller.front">front
65                     controller</link> enables the <link
66                     linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
67                 action helper. This helper takes care of injecting the view
68                 object into the controller, as well as automatically rendering
69                 views. You may disable it within your action controller via one
70                 of the following methods:
71             </para>
73             <programlisting language="php"><![CDATA[
74 class FooController extends Zend_Controller_Action
76     public function init()
77     {
78         // Local to this controller only; affects all actions,
79         // as loaded in init:
80         $this->_helper->viewRenderer->setNoRender(true);
82         // Globally:
83         $this->_helper->removeHelper('viewRenderer');
85         // Also globally, but would need to be in conjunction with the
86         // local version in order to propagate for this controller:
87         Zend_Controller_Front::getInstance()
88             ->setParam('noViewRenderer', true);
89     }
91 ]]></programlisting>
93             <para>
94                 <methodname>initView()</methodname>, <methodname>getViewScript()</methodname>,
95                 <methodname>render()</methodname>, and <methodname>renderScript()</methodname> each
96                 proxy to the <emphasis>ViewRenderer</emphasis> unless the helper is not
97                 in the helper broker or the <emphasis>noViewRenderer</emphasis> flag has
98                 been set.
99             </para>
101             <para>
102                 You can also simply disable rendering for an individual view by
103                 setting the <emphasis>ViewRenderer</emphasis>'s <emphasis>noRender</emphasis>
104                 flag:
105             </para>
107             <programlisting language="php"><![CDATA[
108 class FooController extends Zend_Controller_Action
110     public function barAction()
111     {
112         // disable autorendering for this action only:
113         $this->_helper->viewRenderer->setNoRender();
114     }
116 ]]></programlisting>
118             <para>
119                 The primary reasons to disable the <emphasis>ViewRenderer</emphasis> are
120                 if you simply do not need a view object or if you are not
121                 rendering via view scripts (for instance, when using an action
122                 controller to serve web service protocols such as <acronym>SOAP</acronym>,
123                 <acronym>XML-RPC</acronym>, or <acronym>REST</acronym>). In most cases, you will
124                 never need to globally disable the <emphasis>ViewRenderer</emphasis>, only
125                 selectively within individual controllers or actions.
126             </para>
127         </note>
128     </sect2>
130     <sect2 id="zend.controller.action.initialization">
131         <title>Object Initialization</title>
133         <para>
134             While you can always override the action controller's constructor, we
135             do not recommend this. <methodname>Zend_Controller_Action::__construct()</methodname>
136             performs some important tasks, such as registering the request and
137             response objects, as well as any custom invocation arguments passed
138             in from the front controller. If you must override the constructor,
139             be sure to call <methodname>parent::__construct($request, $response,
140             $invokeArgs)</methodname>.
141         </para>
143         <para>
144             The more appropriate way to customize instantiation is to use the
145             <methodname>init()</methodname> method, which is called as the last task of
146             <methodname>__construct()</methodname>. For example, if you want to connect to
147             a database at instantiation:
148         </para>
150         <programlisting language="php"><![CDATA[
151 class FooController extends Zend_Controller_Action
153     public function init()
154     {
155         $this->db = Zend_Db::factory('Pdo_Mysql', array(
156             'host'     => 'myhost',
157             'username' => 'user',
158             'password' => 'XXXXXXX',
159             'dbname'   => 'website'
160         ));
161     }
163 ]]></programlisting>
164     </sect2>
166     <sect2 id="zend.controller.action.prepostdispatch">
167         <title>Pre- and Post-Dispatch Hooks</title>
169         <para>
170             <classname>Zend_Controller_Action</classname> specifies two methods that may
171             be called to bookend a requested action, <methodname>preDispatch()</methodname>
172             and <methodname>postDispatch()</methodname>. These can be useful in a variety of
173             ways: verifying authentication and <acronym>ACL</acronym>'s prior to running an action
174             (by calling <methodname>_forward()</methodname> in
175             <methodname>preDispatch()</methodname>, the action will be skipped), for instance, or
176             placing generated content in a sitewide template
177             (<methodname>postDispatch()</methodname>).
178         </para>
180         <note>
181             <title>Usage of init() vs. preDispatch()</title>
183             <para>
184                 In the <link linkend="zend.controller.action.initialization">previous
185                     section</link>, we introduced the <methodname>init()</methodname> method, and
186                 in this section, the <methodname>preDispatch()</methodname> method. What is the
187                 difference between them, and what actions would you take in each?
188             </para>
190             <para>
191                 The <methodname>init()</methodname> method is primarily intended for extending the
192                 constructor. Typically, your constructor should simply set object state, and not
193                 perform much logic. This might include initializing resources used in the controller
194                 (such as models, configuration objects, etc.), or assigning values retrieved from
195                 the front controller, bootstrap, or a registry.
196             </para>
198             <para>
199                 The <methodname>preDispatch()</methodname> method can also be used to set object
200                 or environmental (e.g., view, action helper, etc.) state, but its primary purpose
201                 is to make decisions about whether or not the requested action should be dispatched.
202                 If not, you should then <methodname>_forward()</methodname> to another action, or
203                 throw an exception.
204             </para>
206             <para>
207                 Note: <methodname>_forward()</methodname> actually will not work correctly when
208                 executed from <methodname>init()</methodname>, which is a formalization of the
209                 intentions of the two methods.
210             </para>
211         </note>
212     </sect2>
214     <sect2 id="zend.controller.action.accessors">
215         <title>Accessors</title>
217         <para>
218             A number of objects and variables are registered with the object,
219             and each has accessor methods.
220         </para>
222         <itemizedlist>
223             <listitem>
224                 <para>
225                     <emphasis>Request Object</emphasis>: <methodname>getRequest()</methodname>
226                     may be used to retrieve the request object used to call the action.
227                 </para>
228             </listitem>
230             <listitem>
231                 <para>
232                     <emphasis>Response Object</emphasis>:
233                     <methodname>getResponse()</methodname> may be used to retrieve the
234                     response object aggregating the final response. Some typical
235                     calls might look like:
236                 </para>
238                 <programlisting language="php"><![CDATA[
239 $this->getResponse()->setHeader('Content-Type', 'text/xml');
240 $this->getResponse()->appendBody($content);
241 ]]></programlisting>
242             </listitem>
244             <listitem>
245                 <para>
246                     <emphasis>Invocation Arguments</emphasis>: the front
247                     controller may push parameters into the router, dispatcher,
248                     and action controller. To retrieve these, use
249                     <methodname>getInvokeArg($key)</methodname>; alternatively, fetch the
250                     entire list using <methodname>getInvokeArgs()</methodname>.
251                 </para>
252             </listitem>
254             <listitem>
255                 <para>
256                     <emphasis>Request parameters</emphasis>: The request object
257                     aggregates request parameters, such as any <constant>_GET</constant> or
258                     <constant>_POST</constant> parameters, or user parameters specified in the
259                     <acronym>URL</acronym>'s path information. To retrieve these, use
260                     <methodname>_getParam($key)</methodname> or
261                     <methodname>_getAllParams()</methodname>. You may also set request
262                     parameters using <methodname>_setParam()</methodname>; this is useful
263                     when forwarding to additional actions.
264                 </para>
266                 <para>
267                     To test whether or not a parameter exists (useful for
268                     logical branching), use <methodname>_hasParam($key)</methodname>.
269                 </para>
271                 <note>
272                     <para>
273                         <methodname>_getParam()</methodname> may take an optional second
274                         argument containing a default value to use if the
275                         parameter is not set or is empty. Using it eliminates
276                         the need to call <methodname>_hasParam()</methodname> prior to
277                         retrieving a value:
278                     </para>
280                     <programlisting language="php"><![CDATA[
281 // Use default value of 1 if id is not set
282 $id = $this->_getParam('id', 1);
284 // Instead of:
285 if ($this->_hasParam('id') {
286     $id = $this->_getParam('id');
287 } else {
288     $id = 1;
290 ]]></programlisting>
291                 </note>
292             </listitem>
293         </itemizedlist>
294     </sect2>
296     <sect2 id="zend.controller.action.viewintegration">
297         <title>View Integration</title>
299         <note id="zend.controller.action.viewintegration.viewrenderer">
300             <title>Default View Integration is Via the ViewRenderer</title>
302             <para>
303                 The content in this section is only valid when you have explicitly disabled the
304                 <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
305                 Otherwise, you can safely skip over this section.
306             </para>
307         </note>
309         <para>
310             <classname>Zend_Controller_Action</classname> provides a rudimentary and
311             flexible mechanism for view integration. Two methods accomplish
312             this, <methodname>initView()</methodname> and <methodname>render()</methodname>; the
313             former method lazy-loads the <varname>$view</varname> public property, and the
314             latter renders a view based on the current requested action, using
315             the directory hierarchy to determine the script path.
316         </para>
318         <sect3 id="zend.controller.action.viewintegration.initview">
319             <title>View Initialization</title>
321             <para>
322                 <methodname>initView()</methodname> initializes the view object.
323                 <methodname>render()</methodname> calls <methodname>initView()</methodname> in
324                 order to retrieve the view object, but it may be initialized at any time;
325                 by default it populates the <varname>$view</varname> property with a
326                 <classname>Zend_View</classname> object, but any class implementing
327                 <classname>Zend_View_Interface</classname> may be used. If
328                 <varname>$view</varname> is already initialized, it simply returns
329                 that property.
330             </para>
332             <para>
333                 The default implementation makes the following assumption of
334                 the directory structure:
335             </para>
337             <programlisting language="php"><![CDATA[
338 applicationOrModule/
339     controllers/
340         IndexController.php
341     views/
342         scripts/
343             index/
344                 index.phtml
345         helpers/
346         filters/
347 ]]></programlisting>
349             <para>
350                 In other words, view scripts are assumed to be in the
351                 <filename>/views/scripts/</filename> subdirectory, and the
352                 <filename>/views/</filename> subdirectory is assumed to contain sibling
353                 functionality (helpers, filters). When determining the view
354                 script name and path, the <filename>/views/scripts/</filename> directory
355                 will be used as the base path, with directories named after the
356                 individual controllers providing a hierarchy of view scripts.
357             </para>
358         </sect3>
360         <sect3 id="zend.controller.action.viewintegration.render">
361             <title>Rendering Views</title>
363             <para>
364                 <methodname>render()</methodname> has the following signature:
365             </para>
367             <programlisting language="php"><![CDATA[
368 string render(string $action = null,
369               string $name = null,
370               bool $noController = false);
371 ]]></programlisting>
373             <para>
374                 <methodname>render()</methodname> renders a view script. If no arguments are
375                 passed, it assumes that the script requested is
376                 <filename>[controller]/[action].phtml</filename> (where
377                 <filename>.phtml</filename> is the value of the <varname>$viewSuffix</varname>
378                 property). Passing a value for <varname>$action</varname> will render
379                 that template in the <filename>/[controller]/</filename> subdirectory. To
380                 override using the <filename>/[controller]/</filename> subdirectory, pass
381                 a <constant>TRUE</constant> value for <varname>$noController</varname>. Finally,
382                 templates are rendered into the response object; if you wish to render to
383                 a specific <link
384                     linkend="zend.controller.response.namedsegments">named
385                     segment</link> in the response object, pass a value to
386                 <varname>$name</varname>.
387             </para>
389             <note>
390                 <para>
391                     Since controller and action names may contain word delimiter
392                     characters such as '_', '.', and '-', <methodname>render()</methodname>
393                     normalizes these to '-' when determining the script name. Internally,
394                     it uses the dispatcher's word and path delimiters to do this
395                     normalization. Thus, a request to
396                     <filename>/foo.bar/baz-bat</filename> will render the script
397                     <filename>foo-bar/baz-bat.phtml</filename>. If your action method
398                     contains camelCasing, please remember that this will result
399                     in '-' separated words when determining the view script
400                     file name.
401                 </para>
402             </note>
404             <para>
405                 Some examples:
406             </para>
408             <programlisting language="php"><![CDATA[
409 class MyController extends Zend_Controller_Action
411     public function fooAction()
412     {
413         // Renders my/foo.phtml
414         $this->render();
416         // Renders my/bar.phtml
417         $this->render('bar');
419         // Renders baz.phtml
420         $this->render('baz', null, true);
422         // Renders my/login.phtml to the 'form' segment of the
423         // response object
424         $this->render('login', 'form');
426         // Renders site.phtml to the 'page' segment of the response
427         // object; does not use the 'my/' subirectory
428         $this->render('site', 'page', true);
429     }
431     public function bazBatAction()
432     {
433         // Renders my/baz-bat.phtml
434         $this->render();
435     }
437 ]]></programlisting>
438         </sect3>
439     </sect2>
441     <sect2 id="zend.controller.action.utilmethods">
442         <title>Utility Methods</title>
444         <para>
445             Besides the accessors and view integration methods,
446             <classname>Zend_Controller_Action</classname> has several utility methods for
447             performing common tasks from within your action methods (or from
448             pre- and post-dispatch).
449         </para>
451         <itemizedlist>
452             <listitem>
453                 <para>
454                     <methodname>_forward($action, $controller = null, $module = null,
455                         array $params = null)</methodname>: perform another action. If
456                     called in <methodname>preDispatch()</methodname>, the currently
457                     requested action will be skipped in favor of the new one.
458                     Otherwise, after the current action is processed, the action
459                     requested in <methodname>_forward()</methodname> will be executed.
460                 </para>
461             </listitem>
463             <listitem>
464                 <para>
465                     <methodname>_redirect($url, array $options =
466                         array())</methodname>: redirect to another location. This
467                     method takes a <acronym>URL</acronym> and an optional set of options. By
468                     default, it performs an <acronym>HTTP</acronym> 302 redirect.
469                 </para>
471                 <para>
472                     The options may include one or more of the following:
473                 </para>
475                 <itemizedlist>
476                     <listitem>
477                         <para>
478                             <emphasis>exit:</emphasis> whether or not to exit
479                             immediately. If requested, it will cleanly close any
480                             open sessions and perform the redirect.
481                         </para>
483                         <para>
484                             You may set this option globally within the
485                             controller using the <methodname>setRedirectExit()</methodname>
486                             accessor.
487                         </para>
488                     </listitem>
490                     <listitem>
491                         <para>
492                             <emphasis>prependBase:</emphasis> whether or not to
493                             prepend the base <acronym>URL</acronym> registered with the request
494                             object to the <acronym>URL</acronym> provided.
495                         </para>
497                         <para>
498                             You may set this option globally within the
499                             controller using the
500                             <methodname>setRedirectPrependBase()</methodname> accessor.
501                         </para>
502                     </listitem>
504                     <listitem>
505                         <para>
506                             <emphasis>code:</emphasis> what <acronym>HTTP</acronym> code to utilize
507                             in the redirect. By default, an <acronym>HTTP</acronym> 302 is
508                             utilized; any code between 301 and 306 may be used.
509                         </para>
511                         <para>
512                             You may set this option globally within the
513                             controller using the
514                             <methodname>setRedirectCode()</methodname> accessor.
515                         </para>
516                     </listitem>
517                 </itemizedlist>
518             </listitem>
519         </itemizedlist>
520     </sect2>
522     <sect2 id="zend.controller.action.subclassing">
523         <title>Subclassing the Action Controller</title>
525         <para>
526             By design, <classname>Zend_Controller_Action</classname> must be subclassed
527             in order to create an action controller. At the minimum, you will
528             need to define action methods that the controller may call.
529         </para>
531         <para>
532             Besides creating useful functionality for your web applications, you
533             may also find that you're repeating much of the same setup or
534             utility methods in your various controllers; if so, creating a
535             common base controller class that extends
536             <classname>Zend_Controller_Action</classname> could solve such redundancy.
537         </para>
539         <example id="zend.controller.action.subclassing.example-call">
540             <title>Handling Non-Existent Actions</title>
542             <para>
543                 If a request to a controller is made that includes an undefined
544                 action method, <methodname>Zend_Controller_Action::__call()</methodname>
545                 will be invoked. <methodname>__call()</methodname> is, of course,
546                 <acronym>PHP</acronym>'s magic method for method overloading.
547             </para>
549             <para>
550                 By default, this method throws a
551                 <classname>Zend_Controller_Action_Exception</classname> indicating the
552                 requested method was not found in the controller. If the method
553                 requested ends in 'Action', the assumption is that an action was
554                 requested and does not exist; such errors result in an exception
555                 with a code of 404. All other methods result in an exception
556                 with a code of 500. This allows you to easily differentiate
557                 between page not found and application errors in your error
558                 handler.
559             </para>
561             <para>
562                 You should override this functionality if you wish to perform
563                 other operations. For instance, if you wish to display an error
564                 message, you might write something like this:
565             </para>
567             <programlisting language="php"><![CDATA[
568 class MyController extends Zend_Controller_Action
570     public function __call($method, $args)
571     {
572         if ('Action' == substr($method, -6)) {
573             // If the action method was not found, render the error
574             // template
575             return $this->render('error');
576         }
578         // all other methods throw an exception
579         throw new Exception('Invalid method "'
580                             . $method
581                             . '" called',
582                             500);
583     }
585 ]]></programlisting>
587             <para>
588                 Another possibility is that you may want to forward on to a
589                 default controller page:
590             </para>
592             <programlisting language="php"><![CDATA[
593 class MyController extends Zend_Controller_Action
595     public function indexAction()
596     {
597         $this->render();
598     }
600     public function __call($method, $args)
601     {
602         if ('Action' == substr($method, -6)) {
603             // If the action method was not found, forward to the
604             // index action
605             return $this->_forward('index');
606         }
608         // all other methods throw an exception
609         throw new Exception('Invalid method "'
610                             . $method
611                             . '" called',
612                             500);
613     }
615 ]]></programlisting>
616         </example>
618         <para>
619             Besides overriding <methodname>__call()</methodname>, each of the
620             initialization, utility, accessor, view, and dispatch hook methods
621             mentioned previously in this chapter may be overridden in order to
622             customize your controllers. As an example, if you are storing your
623             view object in a registry, you may want to modify your
624             <methodname>initView()</methodname> method with code resembling the following:
625         </para>
627         <programlisting language="php"><![CDATA[
628 abstract class My_Base_Controller extends Zend_Controller_Action
630     public function initView()
631     {
632         if (null === $this->view) {
633             if (Zend_Registry::isRegistered('view')) {
634                 $this->view = Zend_Registry::get('view');
635             } else {
636                 $this->view = new Zend_View();
637                 $this->view->setBasePath(dirname(__FILE__) . '/../views');
638             }
639         }
641         return $this->view;
642     }
644 ]]></programlisting>
646         <para>
647             Hopefully, from the information in this chapter, you can see the
648             flexibility of this particular component and how you can shape it to
649             your application's or site's needs.
650         </para>
651     </sect2>
652 </sect1>
653 <!--
654 vim:se ts=4 sw=4 et: