| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.front">
- <title>The Front Controller</title>
- <sect2 id="zend.controller.front.overview">
- <title>Overview</title>
- <para>
- <classname>Zend_Controller_Front</classname> implements a <ulink
- url="http://www.martinfowler.com/eaaCatalog/frontController.html">Front
- Controller pattern</ulink> used in <ulink
- url="http://en.wikipedia.org/wiki/Model-view-controller">Model-View-Controller
- (MVC)</ulink> applications. Its purpose is to initialize the
- request environment, route the incoming request, and then dispatch
- any discovered actions; it aggregates any responses and returns them
- when the process is complete.
- </para>
- <para>
- <classname>Zend_Controller_Front</classname> also implements the <ulink
- url="http://en.wikipedia.org/wiki/Singleton_pattern">Singleton
- pattern</ulink>, meaning only a single instance of it may be available at
- any given time. This allows it to also act as a registry on which
- the other objects in the dispatch process may draw.
- </para>
- <para>
- <classname>Zend_Controller_Front</classname> registers a <link
- linkend="zend.controller.plugins">plugin broker</link> with
- itself, allowing various events it triggers to be observed by
- plugins. In most cases, this gives the developer the opportunity to
- tailor the dispatch process to the site without the need to extend
- the front controller to add functionality.
- </para>
- <para>
- At a bare minimum, the front controller needs one or more paths to
- directories containing <link linkend="zend.controller.action">action
- controllers</link> in order to do its work. A variety of methods
- may also be invoked to further tailor the front controller
- environment and that of its helper classes.
- </para>
- <note>
- <title>Default Behaviour</title>
- <para>
- By default, the front controller loads the <link
- linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler</link>
- plugin, as well as the <link
- linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
- action helper plugin. These are to simplify error handling and
- view renderering in your controllers, respectively.
- </para>
- <para>
- To disable the <emphasis>ErrorHandler</emphasis>, perform the following
- at any point prior to calling <methodname>dispatch()</methodname>:
- </para>
- <programlisting language="php"><![CDATA[
- // Disable the ErrorHandler plugin:
- $front->setParam('noErrorHandler', true);
- ]]></programlisting>
- <para>
- To disable the <emphasis>ViewRenderer</emphasis>, do the following prior
- to calling <methodname>dispatch()</methodname>:
- </para>
- <programlisting language="php"><![CDATA[
- // Disable the ViewRenderer helper:
- $front->setParam('noViewRenderer', true);
- ]]></programlisting>
- </note>
- </sect2>
- <sect2 id="zend.controller.front.methods.primary">
- <title>Primary Methods</title>
- <para>
- The front controller has several accessors for setting up its
- environment. However, there are three primary methods key to the
- front controller's functionality:
- </para>
- <sect3 id="zend.controller.front.methods.primary.getinstance">
- <title>getInstance()</title>
- <para>
- <methodname>getInstance()</methodname> is used to retrieve a front
- controller instance. As the front controller implements a
- Singleton pattern, this is also the only means possible for
- instantiating a front controller object.
- </para>
- <programlisting language="php"><![CDATA[
- $front = Zend_Controller_Front::getInstance();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.setcontrollerdirectory">
- <title>setControllerDirectory() and addControllerDirectory</title>
- <para>
- <methodname>setControllerDirectory()</methodname> is used to tell <link
- linkend="zend.controller.dispatcher">the dispatcher</link>
- where to look for <link
- linkend="zend.controller.action">action controller</link>
- class files. It accepts either a single path or an associative
- array of module and path pairs.
- </para>
- <para>
- As some examples:
- </para>
- <programlisting language="php"><![CDATA[
- // Set the default controller directory:
- $front->setControllerDirectory('../application/controllers');
- // Set several module directories at once:
- $front->setControllerDirectory(array(
- 'default' => '../application/controllers',
- 'blog' => '../modules/blog/controllers',
- 'news' => '../modules/news/controllers',
- ));
- // Add a 'foo' module directory:
- $front->addControllerDirectory('../modules/foo/controllers', 'foo');
- ]]></programlisting>
- <note>
- <para>
- If you use <methodname>addControllerDirectory()</methodname> without a
- module name, it will set the directory for the
- <emphasis>default</emphasis> module -- overwriting it if it already
- exists.
- </para>
- </note>
- <para>
- You can get the current settings for the controller directory
- using <methodname>getControllerDirectory()</methodname>; this will return an
- array of module and directory pairs.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.addmoduledirectory">
- <title>addModuleDirectory() and getModuleDirectory()</title>
- <para>
- One aspect of the front controller is that you may <link
- linkend="zend.controller.modular">define a modular directory
- structure</link> for creating standalone components; these are
- called "modules".
- </para>
- <para>
- Each module should be in its own directory and mirror the
- directory structure of the default module -- i.e., it should
- have a <filename>/controllers/</filename> subdirectory at the minimum, and typically
- a <filename>/views/</filename> subdirectory and other application subdirectories.
- </para>
- <para>
- <methodname>addModuleDirectory()</methodname> allows you to pass the name of
- a directory containing one or more module directories. It then
- scans it and adds them as controller directories to the front
- controller.
- </para>
- <para>
- Later, if you want to determine the path to a particular module
- or the current module, you can call
- <methodname>getModuleDirectory()</methodname>, optionally passing a module
- name to get that specific module directory.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.dispatch">
- <title>dispatch()</title>
- <para>
- <methodname>dispatch(Zend_Controller_Request_Abstract $request = null,
- Zend_Controller_Response_Abstract $response = null)</methodname>
- does the heavy work of the front controller. It may optionally
- take a <link linkend="zend.controller.request">request
- object</link> and/or a <link
- linkend="zend.controller.response">response object</link>,
- allowing the developer to pass in custom objects for each.
- </para>
- <para>
- If no request or response object are passed in,
- <methodname>dispatch()</methodname> will check for previously registered
- objects and use those or instantiate default versions to use in
- its process (in both cases, the <acronym>HTTP</acronym> flavor will be used as the
- default).
- </para>
- <para>
- Similarly, <methodname>dispatch()</methodname> checks for registered <link
- linkend="zend.controller.router">router</link> and <link
- linkend="zend.controller.dispatcher">dispatcher</link>
- objects, instantiating the default versions of each if none is
- found.
- </para>
- <para>
- The dispatch process has three distinct events:
- </para>
- <itemizedlist>
- <listitem><para>Routing</para></listitem>
- <listitem><para>Dispatching</para></listitem>
- <listitem><para>Response</para></listitem>
- </itemizedlist>
- <para>
- Routing takes place exactly once, using the values in the
- request object when <methodname>dispatch()</methodname> is called.
- Dispatching takes place in a loop; a request may either indicate
- multiple actions to dispatch, or the controller or a plugin may
- reset the request object to force additional actions to
- dispatch. When all is done, the front controller returns a
- response.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.run">
- <title>run()</title>
- <para>
- <methodname>Zend_Controller_Front::run($path)</methodname> is a static
- method taking simply a path to a directory containing
- controllers. It fetches a front controller instance (via
- <link
- linkend="zend.controller.front.methods.primary.getinstance">getInstance()</link>),
- registers the path provided via <link
- linkend="zend.controller.front.methods.primary.setcontrollerdirectory">setControllerDirectory()</link>,
- and finally <link
- linkend="zend.controller.front.methods.primary.dispatch">dispatches</link>.
- </para>
- <para>
- Basically, <methodname>run()</methodname> is a convenience method that can
- be used for site setups that do not require customization of the
- front controller environment.
- </para>
- <programlisting language="php"><![CDATA[
- // Instantiate front controller, set controller directory, and dispatch in one
- // easy step:
- Zend_Controller_Front::run('../application/controllers');
- ]]></programlisting>
- </sect3>
- </sect2>
- <sect2 id="zend.controller.front.methods.environment">
- <title>Environmental Accessor Methods</title>
- <para>
- In addition to the methods listed above, there are a number of
- accessor methods that can be used to affect the front controller
- environment -- and thus the environment of the classes to which the
- front controller delegates.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>resetInstance()</methodname> can be used to clear all
- current settings. Its primary purpose is for testing, but it
- can also be used for instances where you wish to chain
- together multiple front controllers.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setDefaultControllerName()</methodname> and
- <methodname>getDefaultControllerName()</methodname> let you
- specify a different name to use for the default controller
- ('index' is used otherwise) and retrieve the current value.
- They proxy to <link linkend="zend.controller.dispatcher">the dispatcher</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setDefaultAction()</methodname> and
- <methodname>getDefaultAction()</methodname> let you specify a
- different name to use for the default action ('index' is
- used otherwise) and retrieve the current value. They proxy
- to <link linkend="zend.controller.dispatcher">the dispatcher</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setRequest()</methodname> and
- <methodname>getRequest()</methodname> let you specify <link
- linkend="zend.controller.request">the request</link>
- class or object to use during the dispatch process and to
- retrieve the current object. When setting the request
- object, you may pass in a request class name, in which case
- the method will load the class file and instantiate it.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setRouter()</methodname>
- <methodname>getRouter()</methodname> let you specify <link
- linkend="zend.controller.router">the router</link>
- class or object to use during the dispatch process and to
- retrieve the current object. When setting the router
- object, you may pass in a router class name, in which case
- the method will load the class file and instantiate it.
- </para>
- <para>
- When retrieving the router object, it first checks to see if
- one is present, and if not, instantiates the default router
- (rewrite router).
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setBaseUrl()</methodname> and
- <methodname>getBaseUrl()</methodname> let you specify <link
- linkend="zend.controller.request.http.baseurl">the base
- <acronym>URL</acronym></link> to strip when routing requests and to
- retrieve the current value. The value is provided to the
- request object just prior to routing.
- </para>
- <note>
- <title>Fully-Qualified URL is not supported</title>
- <para>
- Passing a fully-qualified URL (ie: http://example.com/) to the
- <methodname>setBaseUrl</methodname> method is not supported, and
- will cause issues when using the URL view helper. See ticket
- <ulink url="http://framework.zend.com/issues/browse/ZF-10923">
- ZF-10923
- </ulink> for more details.
- </para>
- </note>
- </listitem>
- <listitem>
- <para>
- <methodname>setDispatcher()</methodname> and
- <methodname>getDispatcher()</methodname> let you specify <link
- linkend="zend.controller.dispatcher">the
- dispatcher</link> class or object to use during the
- dispatch process and retrieve the current object. When
- setting the dispatcher object, you may pass in a dispatcher
- class name, in which case the method will load the class
- file and instantiate it.
- </para>
- <para>
- When retrieving the dispatcher object, it first checks to see if
- one is present, and if not, instantiates the default
- dispatcher.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setResponse()</methodname> and
- <methodname>getResponse()</methodname> let you specify <link
- linkend="zend.controller.response">the response</link>
- class or object to use during the dispatch process and to
- retrieve the current object. When setting the response
- object, you may pass in a response class name, in which case
- the method will load the class file and instantiate it.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>registerPlugin(Zend_Controller_Plugin_Abstract $plugin,
- $stackIndex = null)</methodname> allows you to register <link
- linkend="zend.controller.plugins">plugin objects</link>.
- By setting the optional <varname>$stackIndex</varname>, you can
- control the order in which plugins will execute.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>unregisterPlugin($plugin)</methodname> let you
- unregister <link
- linkend="zend.controller.plugins">plugin objects</link>.
- <varname>$plugin</varname> may be either a plugin object or a
- string denoting the class of plugin to unregister.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>throwExceptions($flag)</methodname> is used to turn on/off
- the ability to throw exceptions during the dispatch process.
- By default, exceptions are caught and placed in the <link
- linkend="zend.controller.response">response
- object</link>; turning on <methodname>throwExceptions()</methodname>
- will override this behaviour.
- </para>
- <para>
- For more information, read <link linkend="zend.controller.exceptions">MVC
- Exceptions</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>returnResponse($flag)</methodname> is used to tell the front
- controller whether to return the response
- (<constant>TRUE</constant>) from <methodname>dispatch()</methodname>, or if the
- response should be automatically emitted
- (<constant>FALSE</constant>). By default, the response is
- automatically emitted (by calling
- <methodname>Zend_Controller_Response_Abstract::sendResponse()</methodname>);
- turning on <methodname>returnResponse()</methodname> will override this
- behaviour.
- </para>
- <para>
- Reasons to return the response include a desire to check for
- exceptions prior to emitting the response, needing to log
- various aspects of the response (such as headers), etc.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.front.methods.params">
- <title>Front Controller Parameters</title>
- <para>
- In the introduction, we indicated that the front controller also
- acts as a registry for the various controller components. It does so
- through a family of "param" methods. These methods allow you to
- register arbitrary data -- objects and variables -- with the front
- controller to be retrieved at any time in the dispatch chain. These
- values are passed on to the router, dispatcher, and action
- controllers. The methods include:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>setParam($name, $value)</methodname> allows you to set a
- single parameter of <varname>$name</varname> with value
- <varname>$value</varname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setParams(array $params)</methodname> allows you to set
- multiple parameters at once using an associative array.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getParam($name)</methodname> allows you to retrieve a single
- parameter at a time, using <varname>$name</varname> as the
- identifier.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getParams()</methodname> allows you to retrieve the entire
- list of parameters at once.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearParams()</methodname> allows you to clear a single
- parameter (by passing a string identifier), multiple named
- parameters (by passing an array of string identifiers), or the
- entire parameter stack (by passing nothing).
- </para>
- </listitem>
- </itemizedlist>
- <para>
- There are several pre-defined parameters that may be set that have
- specific uses in the dispatch chain:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>useDefaultControllerAlways</emphasis> is used to hint to
- <link linkend="zend.controller.dispatcher">the
- dispatcher</link> to use the default controller in the
- default module for any request that is not dispatchable
- (i.e., the module, controller, and/or action do not exist).
- By default, this is off.
- </para>
- <para>
- See <link linkend="zend.controller.exceptions.internal">MVC Exceptions
- You May Encounter</link>
- for more detailed information on using this setting.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>disableOutputBuffering</emphasis> is used to hint to <link
- linkend="zend.controller.dispatcher">the
- dispatcher</link> that it should not use output
- buffering to capture output generated by action controllers.
- By default, the dispatcher captures any output and appends
- it to the response object body content.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>noViewRenderer</emphasis> is used to disable the <link
- linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
- Set this parameter to <constant>TRUE</constant> to disable it.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>noErrorHandler</emphasis> is used to disable the <link
- linkend="zend.controller.plugins.standard.errorhandler">Error
- Handler plugin</link>. Set this parameter to <constant>TRUE</constant> to
- disable it.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.front.subclassing">
- <title>Extending the Front Controller</title>
- <para>
- To extend the Front Controller, at the very minimum you will need
- to override the <methodname>getInstance()</methodname> method:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Controller_Front extends Zend_Controller_Front
- {
- public static function getInstance()
- {
- if (null === self::$_instance) {
- self::$_instance = new self();
- }
- return self::$_instance;
- }
- }
- ]]></programlisting>
- <para>
- Overriding the <methodname>getInstance()</methodname> method ensures that
- subsequent calls to
- <methodname>Zend_Controller_Front::getInstance()</methodname> will return an
- instance of your new subclass instead of a
- <classname>Zend_Controller_Front</classname> instance -- this is particularly
- useful for some of the alternate routers and view helpers.
- </para>
- <para>
- Typically, you will not need to subclass the front controller unless
- you need to add new functionality (for instance, a plugin
- autoloader, or a way to specify action helper paths). Some points
- where you may want to alter behaviour may include modifying how
- controller directories are stored, or what default router or
- dispatcher are used.
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|