<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.controller.dispatcher">
    <title>The Dispatcher</title>

    <sect2 id="zend.controller.dispatcher.overview">
        <title>Overview</title>

        <para>
            Dispatching is the process of taking the request object,
            <classname>Zend_Controller_Request_Abstract</classname>, extracting the module
            name, controller name, action name, and optional parameters
            contained in it, and then instantiating a controller and calling an
            action of that controller. If any of the module, controller, or
            action are not found, it will use default values for them.
            <classname>Zend_Controller_Dispatcher_Standard</classname> specifies
            <code>index</code> for each of the controller and action defaults
            and <code>default</code> for the module default value, but allows
            the developer to change the default values for each using the
            <code>setDefaultController()</code>,
            <code>setDefaultAction()</code>, and <code>setDefaultModule()</code>
            methods, respectively.
        </para>

        <note>
            <title>Default Module</title>

            <para>
                When creating modular applications, you may find that you want
                your default module namespaced as well (the default
                configuration is that the default module is
                <emphasis>not</emphasis> namespaced). As of 1.5.0, you can now
                do so by specifying the <code>prefixDefaultModule</code> as true
                in either the front controller or your dispatcher:
            </para>

            <programlisting role="php"><![CDATA[
// In your front controller:
$front->setParam('prefixDefaultModule', true);

// In your dispatcher:
$dispatcher->setParam('prefixDefaultModule', true);
]]></programlisting>

            <para>
                This allows you to re-purpose an existing module to be the
                default module for an application.
            </para>
        </note>

        <para>
            Dispatching happens in a loop in the front controller. Before
            dispatching occurs, the front controller routes the request to find
            user specified values for the module, controller, action, and optional
            parameters. It then enters a dispatch loop, dispatching the request.
        </para>

        <para>
            At the beginning of each iteration, it sets a flag in the request
            object indicating that the action has been dispatched. If an action
            or pre/postDispatch plugin resets that flag, the dispatch loop will
            continue and attempt to dispatch the new request. By changing the
            controller and/or action in the request and resetting the dispatched
            flag, the developer may define a chain of requests to perform.
        </para>

        <para>
            The action controller method that controls such dispatching is
            <code>_forward()</code>; call this method from any of the
            pre/postDispatch() or action methods, providing an action, controller,
            module, and optionally any additional parameters you may wish to
            send to the new action:
        </para>

        <programlisting role="php"><![CDATA[
public function fooAction()
{
    // forward to another action in the current controller and module:
    $this->_forward('bar', null, null, array('baz' => 'bogus'));
}

public function barAction()
{
    // forward to an action in another controller:
    // FooController::bazAction(),
    // in the current module:
    $this->_forward('baz', 'foo', null, array('baz' => 'bogus'));
}

public function bazAction()
{
    // forward to an action in another controller in another module,
    // Foo_BarController::bazAction():
    $this->_forward('baz', 'bar', 'foo', array('baz' => 'bogus'));
}
]]></programlisting>
    </sect2>

    <sect2 id="zend.controller.dispatcher.subclassing">
        <title>Subclassing the Dispatcher</title>

        <para>
            <classname>Zend_Controller_Front</classname> will first call the router to
            determine the first action in the request. It then enters a dispatch
            loop, which calls on the dispatcher to dispatch the action.
        </para>

        <para>
            The dispatcher needs a variety of data in order to do its work - it
            needs to know how to format controller and action names, where to
            look for controller class files, whether or not a provided module
            name is valid, and an API for determining if a given request is even
            dispatchable based on the other information available.
        </para>

        <para>
            <classname>Zend_Controller_Dispatcher_Interface</classname> defines the
            following methods as required for any dispatcher implementation:
        </para>

        <programlisting role="php"><![CDATA[
interface Zend_Controller_Dispatcher_Interface
{
    /**
     * Format a string into a controller class name.
     *
     * @param string $unformatted
     * @return string
     */
    public function formatControllerName($unformatted);

    /**
     * Format a string into an action method name.
     *
     * @param string $unformatted
     * @return string
     */
    public function formatActionName($unformatted);

    /**
     * Determine if a request is dispatchable
     *
     * @param  Zend_Controller_Request_Abstract $request
     * @return boolean
     */
    public function isDispatchable(
        Zend_Controller_Request_Abstract $request
    );

    /**
     * Set a user parameter (via front controller, or for local use)
     *
     * @param string $name
     * @param mixed $value
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function setParam($name, $value);

    /**
     * Set an array of user parameters
     *
     * @param array $params
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function setParams(array $params);

    /**
     * Retrieve a single user parameter
     *
     * @param string $name
     * @return mixed
     */
    public function getParam($name);

    /**
     * Retrieve all user parameters
     *
     * @return array
     */
    public function getParams();

    /**
     * Clear the user parameter stack, or a single user parameter
     *
     * @param null|string|array single key or array of keys for
     *        params to clear
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function clearParams($name = null);

    /**
     * Set the response object to use, if any
     *
     * @param Zend_Controller_Response_Abstract|null $response
     * @return void
     */
    public function setResponse(
        Zend_Controller_Response_Abstract $response = null
    );

    /**
     * Retrieve the response object, if any
     *
     * @return Zend_Controller_Response_Abstract|null
     */
    public function getResponse();

    /**
     * Add a controller directory to the controller directory stack
     *
     * @param string $path
     * @param string $args
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function addControllerDirectory($path, $args = null);

    /**
     * Set the directory (or directories) where controller files are
     * stored
     *
     * @param string|array $dir
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function setControllerDirectory($path);

    /**
     * Return the currently set directory(ies) for controller file
     * lookup
     *
     * @return array
     */
    public function getControllerDirectory();

    /**
     * Dispatch a request to a (module/)controller/action.
     *
     * @param  Zend_Controller_Request_Abstract $request
     * @param  Zend_Controller_Response_Abstract $response
     * @return Zend_Controller_Request_Abstract|boolean
     */
    public function dispatch(
        Zend_Controller_Request_Abstract $request,
        Zend_Controller_Response_Abstract $response
    );

    /**
     * Whether or not a given module is valid
     *
     * @param string $module
     * @return boolean
     */
    public function isValidModule($module);

    /**
     * Retrieve the default module name
     *
     * @return string
     */
    public function getDefaultModule();

    /**
     * Retrieve the default controller name
     *
     * @return string
     */
    public function getDefaultControllerName();

    /**
     * Retrieve the default action
     *
     * @return string
     */
    public function getDefaultAction();
}
]]></programlisting>

        <para>
            In most cases, however, you should simply extend the abstract class
            <classname>Zend_Controller_Dispatcher_Abstract</classname>, in which each of
            these have already been defined, or
            <classname>Zend_Controller_Dispatcher_Standard</classname> to modify
            functionality of the standard dispatcher.
        </para>

        <para>
            Possible reasons to subclass the dispatcher include a desire to
            use a different class or method naming schema in your action
            controllers, or a desire to use a different dispatching paradigm
            such as dispatching to action files under controller directories
            (instead of dispatching to class methods).
        </para>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
