<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 15103 -->
<!-- Reviewed: no -->
<sect1 id="zend.controller.front">
    <title>El Front Controller</title>

    <sect2 id="zend.controller.front.overview">
        <title>Introducción</title>

        <para>
            <classname>Zend_Controller_Front</classname> implementa un <ulink
                url="http://www.martinfowler.com/eaaCatalog/frontController.html">Front
                Controller pattern</ulink> usado en aplicaciones <ulink
                url="http://en.wikipedia.org/wiki/Model-view-controller">Model-View-Controller
                (MVC)</ulink>. 
                Su propósito es inicializar el entorno de la solicitud, 
                rutear la solicitud entrante, y luego hacer un envío de 
                cualquier de las acciones descubiertas; le agrega las respuestas 
                y las regresa cuando se completa el proceso.  
        </para>

        <para>
            <classname>Zend_Controller_Front</classname> también implementa el <ulink
                url="http://en.wikipedia.org/wiki/Singleton_pattern">Singleton
            pattern</ulink>, significando que solo una única instancia de él 
            puede estar disponible en cualquier momento dado. 
            Esto le permite actuar también como un registro en el que los demás 
            objetos pueden extraer del proceso dispatch.
        </para>

        <para>
            <classname>Zend_Controller_Front</classname> registra un <link
                linkend="zend.controller.plugins">plugin broker</link> consigo  
            mismo, permitiendo que diversos eventos que dispara sean observados 
            por plugins. En muchos casos, esto da el desarrollador la 
            oportunidad de adaptar el proceso de dispatch al sitio sin la 
            necesidad de ampliar el Front Controller para añadir funcionalidad.
        </para>

        <para>
            Como mínimo, el front controller necesita una o más paths a 
            directorios que contengan <link linkend="zend.controller.action">
            action controllers</link> a fin de hacer su trabajo. 
            Una variedad de métodos también pueden ser invocados para seguir 
            adaptando el medio ambiente del front controller y ese a sus 
            helper classes.
        </para>

        <note>
            <title>Comportamiento por Defecto</title>
            <para>
                Por defecto, el front controller carga el <link
                    linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler</link>
                plugin, así como al <link
                    linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
                action helper plugin. Estos son para simplificar el manejo de 
                errores y el view renderering en sus controladores, respectivamente.
            </para>

            <para>
                Para deshabilitar el <methodname>ErrorHandler</methodname>, ejecutar lo 
                siguiente en cualquier momento antes de llamar a 
                <methodname>dispatch()</methodname>:
            </para>

             <programlisting language="php"><![CDATA[
// Deshabilitar el ErrorHandler plugin:
$front->setParam('noErrorHandler', true);
]]></programlisting>

            <para>
                Para deshabilitar el <methodname>ViewRenderer</methodname>, haga lo 
                siguiente antes de llamar a <methodname>dispatch()</methodname>:
            </para>

             <programlisting language="php"><![CDATA[
// Deshabilitar el ViewRenderer helper:
$front->setParam('noViewRenderer', true);
]]></programlisting>
        </note>
    </sect2>

    <sect2 id="zend.controller.front.methods.primary">
        <title>Métodos Básicos</title>

        <para>
            El front controller tiene varios accessors para establecer su 
            medio ambiente. Sin embargo, hay tres métodos básicos clave para la 
            funcionalidad del front controller:
        </para>

        <sect3 id="zend.controller.front.methods.primary.getinstance">
            <title>getInstance()</title>

            <para>
                <methodname>getInstance()</methodname> se utiliza para recuperar una 
                instancia del front controller. Como el front controller 
                implementa un patrón Singleton, este también es el único 
                medio posible para instanciar un objeto front controller.
            </para>

             <programlisting language="php"><![CDATA[
$front = Zend_Controller_Front::getInstance();
]]></programlisting>
        </sect3>

        <sect3 id="zend.controller.front.methods.primary.setcontrollerdirectory">
            <title>setControllerDirectory() y addControllerDirectory</title>

            <para>
                <methodname>setControllerDirectory()</methodname> se usa para decirle a <link
                    linkend="zend.controller.dispatcher">el dispatcher</link>
                dónde buscar para los archivos de clase <link
                    linkend="zend.controller.action">action controller</link>.
                Acepta bien un único path o un array asociativo de pares 
                módulo/path.
            </para>

            <para>
                Como algunos ejemplos:
            </para>

             <programlisting language="php"><![CDATA[
// Establer el directorio de controladores por defecto:
$front->setControllerDirectory('../application/controllers');

// Establecer varios directorios módulos a la vez:
$front->setControllerDirectory(array(
    'default' => '../application/controllers',
    'blog'    => '../modules/blog/controllers',
    'news'    => '../modules/news/controllers',
));

// Agregar un directorio de módulos 'foo':
$front->addControllerDirectory('../modules/foo/controllers', 'foo');
]]></programlisting>

            <note>
                <para>
                    Si usa <methodname>addControllerDirectory()</methodname> sin un nombre 
                    de módulo, este establecerá el directorio 
                    <methodname>default</methodname> para el módulo -- sobreescribiéndolo 
                    si ya existe.
                </para>
            </note>

            <para>
                Puede conseguir la configuración actual para el directorio del 
                controlador utilizando <methodname>getControllerDirectory()</methodname>; 
                este devolverá un array de pares módulo/directorio.
            </para>
        </sect3>

        <sect3 id="zend.controller.front.methods.primary.addmoduledirectory">
            <title>addModuleDirectory() y getModuleDirectory()</title>

            <para>
                Uno de los aspectos del front controller es que puede <link
                    linkend="zend.controller.modular"> definir una 
                estructura modular de directorio</link> para crear 
                componentes standalone; estos son llamados "módulos".
            </para>

            <para>
                Cada módulo debe estar en su propio directorio y ser un espejo 
                de la estructura del directorio del módulo por defecto -- es 
                decir, que debería tener como mínimo un subdirectorio de 
                "controladores", y típicamente un subdirectorio de "views" 
                y otros subdirectorios de aplicaciones.
            </para>

            <para>
                <methodname>addModuleDirectory()</methodname> permite pasar el nombre de 
                un directorio que contiene uno o más directorios de módulos. 
                A continuación lo analiza y los añade como directorios de 
                controladores al front controller. 
            </para>

            <para>
                Después, si quiere determinar el path a un determinado módulo 
                o al módulo actual, puede llamar a <methodname>getModuleDirectory()</methodname>, 
                opcionalmente puede pasar un nombre de módulo para conseguir el  
                directorio de ese módulo específico.
            </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>
                hace el trabajo pesado del front controller. Puede opcionalmente 
                tomar un <link linkend="zend.controller.request">request
                    object</link> y/o un <link
                    linkend="zend.controller.response">response object</link>,
                permitiendo al desarrollador pasar objetos peronalizados para 
                cada uno.
            </para>

            <para>
                Si no se pasa ningun objeto solicitud o respuesta,
                <methodname>dispatch()</methodname> comprobará por objetos previamente 
                registrados y utilizará esos o instanciará versiones por defecto 
                a utilizar en su proceso (en ambos casos, el sabor de HTTP será 
                utilizado por defecto).
            </para>

            <para>
                Similarmente, <methodname>dispatch()</methodname> 
                comprueba los objetos registrados <link
                    linkend="zend.controller.router">router</link> y <link
                    linkend="zend.controller.dispatcher">dispatcher</link>
                , instanciando las versiones por defecto de cada uno si ninguno 
                de ellos se encuentra.
            </para>

            <para>
                El proceso de dispatch tiene tres eventos distintos:
            </para>

            <itemizedlist>
                <listitem><para>Routing</para></listitem>
                <listitem><para>Dispatching</para></listitem>
                <listitem><para>Response</para></listitem>
            </itemizedlist>

            <para>
                El routing se lleva a cabo exactamente una vez, utilizando los 
                valores del objeto solicitud cuando se llama a <methodname>dispatch()</methodname>. 
                El dispatching se lleva a cabo en un bucle; una solicitud puede 
                indicar, bien múltiples acciones de dispatch, o el controlador o 
                un plugin pueden restablecer el objeto solicitud para forzar 
                medidas adicionales para dispatch. Cuando todo está hecho, 
                el front controller devuelve una respuesta.
            </para>
        </sect3>

        <sect3 id="zend.controller.front.methods.primary.run">
            <title>run()</title>

            <para>
                <classname>Zend_Controller_Front::run($path)</classname> 
                es un método estático que toma simplemente un path a un 
                directorio que contiene controladores. Obtiene una instancia 
                del front controller (via 
                <link
                    linkend="zend.controller.front.methods.primary.getinstance">getInstance()</link>,
                registra el path provisto via <link
                    linkend="zend.controller.front.methods.primary.setcontrollerdirectory">setControllerDirectory()</link>,
                y finalmente <link
                    linkend="zend.controller.front.methods.primary.dispatch">dispatches</link>.
            </para>

            <para>
                Básicamente, <methodname>run()</methodname> es un método conveniente que 
                pueden utilizarse para setups de sitios que no requieran la 
                personalización del medio ambiente del front controller.
            </para>

             <programlisting language="php"><![CDATA[
// Instanciar el front controller, establecer el directorio de controladores, 
// y hacer el dispatch fácilmente en en un solo paso:
Zend_Controller_Front::run('../application/controllers');
]]></programlisting>
        </sect3>
    </sect2>

    <sect2 id="zend.controller.front.methods.environment">
        <title>Métodos Accessor Ambientales</title>

        <para>
            Además de los métodos enumerados anteriormente, hay una serie de 
            métodos accessor que pueden utilizarse para afectar el entorno 
            del front controller -- y por lo tanto el ambiente de las clases 
            a las cuales delega el front controller.
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>resetInstance()</methodname> puede ser utilizada para 
                    borrar todos los settings actuales. Su objetivo principal 
                    es para testing, pero también puede ser utilizada para 
                    instancias donde desee encadenar múltiples front controllers.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>(set|get)DefaultControllerName()</methodname> permite 
                    especificar un nombre diferente para usar en el controlador  
                    por defecto (en caso coontrario, se usa 'index') y 
                    recuperar el valor actual.
                    Delegan a <link
                        linkend="zend.controller.dispatcher">el dispatcher</link>.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>(set|get)DefaultAction()</methodname> le deja especificar un 
                    nombre diferente a utilizar para la acción predeterminada 
                    (en caso coontrario, se usa 'index') y recuperar el valor 
                    actual.
                    Delegan a <link
                        linkend="zend.controller.dispatcher">el dispatcher</link>.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>(set|get)Request()</methodname> le permite especificar la 
                    clase u objeto <link
                        linkend="zend.controller.request">el request</link>
                    a usar durante el proceso de dispatch y recuperar el objeto 
                    actual. Al setear el objeto solicitud, puede pasarlo en un 
                    nombre de clase de solicitud, en cuyo caso el método va a 
                    cargar el archivo clase y lo instanciará.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>(set|get)Router()</methodname> le permite especificar la 
                    clase u objeto <link
                        linkend="zend.controller.router">el router</link>
                    a usar durante el proceso de dispatch y recuperar el objeto 
                    actual. Al setear el objeto router, puede pasarlo en un 
                    nombre de clase de router, en cuyo caso el método va a 
                    cargar el archivo clase y lo instanciará.
                </para>

                <para>
                    Al recuperar el objeto router, en primer lugar comprueba 
                    para ver si hay alguno presente, y si no, instancia al 
                    router por defecto(reescribe el router).
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>(set|get)BaseUrl()</methodname> le permite especificar <link
                        linkend="zend.controller.request.http.baseurl">la URL
                        base</link> de la cual tirar cuando se rutean peticiones 
                        y recuperar el valor actual. El valor se provee al 
                        objeto solicitud justo antes de rutear.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>(set|get)Dispatcher()</methodname> le permite especificar la 
                    clase u objeto <link
                        linkend="zend.controller.dispatcher">el
                        dispatcher</link> 
                    a usar durante el proceso de dispatch y recuperar el objeto 
                    actual. Al setear el objeto dispatch, puede pasarlo en un 
                    nombre de clase de dispatcher, en cuyo caso el método va a 
                    cargar el archivo clase y lo instanciará.
                </para>

                <para>
                    Al recuperar el objeto dispatch, en primer lugar comprueba 
                    para ver si hay alguno presente, y si no, instancia al  
                    dispatcher por defecto.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>(set|get)Response()</methodname> le permite especificar la 
                    clase u objeto  <link
                        linkend="zend.controller.response">response</link>
                    a usar durante el proceso de dispatch y recuperar el objeto 
                    actual. Al setear el objeto response, puede pasarlo en un 
                    nombre de clase de response, en cuyo caso el método va a 
                    cargar el archivo clase y lo instanciará.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null)</methodname>
                    le permite registrar <link
                        linkend="zend.controller.plugins">plugin objects</link>.
                    Opcionalmente, setting <methodname>$stackIndex</methodname>, puede 
                    controlar el orden en que se ejecutarán los plugins.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>unregisterPlugin($plugin)</methodname> le permite
                    desregistrar <link
                        linkend="zend.controller.plugins">plugin objects</link>.
                    <methodname>$plugin</methodname> puede ser tanto un objeto plugin o un  
                    string que denota la clase de plugin a desregistrar.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>throwExceptions($flag)</methodname> se utiliza para 
                    activar/desactivar la capacidad de arrojar excepciones 
                    durante el proceso de dispatch. Por defecto, las excepciones 
                    son capturadas y colocadas en el <link
                        linkend="zend.controller.response">objeto response
                        </link>; activando <methodname>throwExceptions()</methodname>
                    se anulará este comportamiento.
                </para>

                <para>
                    Para más información, lea <xref
                        linkend="zend.controller.exceptions" />.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>returnResponse($flag)</methodname> se usa para decirle al 
                    front controller cuando regresar la respuesta 
                    (<methodname>true</methodname>) desde <methodname>dispatch()</methodname>, o si la 
                    respuesta debe ser emitida automáticamente (<methodname>false</methodname>).
                    Por defecto, la respuesta es automáticamente emitida 
                    (llamando a                  
                    <classname>Zend_Controller_Response_Abstract::sendResponse()</classname>);
                    activando <methodname>returnResponse()</methodname>) se anulará este 
                    comportamiento.
                </para>

                <para>
                    Las razones para regresar la respuesta incluyen un deseo de 
                    comprobar las excepciones antes de emitir la respuesta, 
                    necesidad de hacer un log de diversos aspectos de la respuesta 
                    (tales como cabeceras), etc.
                </para>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.front.methods.params">
        <title>Parámetros de Front Controller</title>

        <para>
            En la introducción, se indicó que el front controller también actúa 
            como un registro de los distintos componentes del controlador. 
            Lo hace mediante una familia de métodos "param". Estos métodos le 
            permiten registrar datos arbitrarios -- objetos y variables -- 
            con el front controller, a ser devueltos en cualquier momento 
            en la cadena de dispatch. Estos valores se transmiten al router, 
            al dispatcher, y a los action controllers. Los métodos incluyen:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>setParam($name, $value)</methodname> permite establecer un 
                    único parámetro de <methodname>$name</methodname> con el valor 
                    <methodname>$value</methodname>.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setParams(array $params)</methodname> permite configurar 
                    varios parámetros a la vez usando un array asociativo.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getParam($name)</methodname> permite recuperar un único 
                    parámetro a la vez, utilizando como identificador a 
                    <methodname>$name</methodname>.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getParams()</methodname> permite recuperar toda la lista de 
                    parámetros a la vez.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>clearParams()</methodname> permite borrar un único parámetro 
                    (pasando un string identificador), parámetros con múltiples  
                    nombres (pasando un array de strings identificadores), 
                    o el stack de parámetros completo (pasando nada).
                </para>
            </listitem>
        </itemizedlist>

        <para>
            Hay varios parámetros pre-definidos que puede ser seteados para 
            tener usos específicos en la cadena de dispatch:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>useDefaultControllerAlways</methodname> se usa para indicar a
                    <link linkend="zend.controller.dispatcher">el
                        dispatcher</link> que utilice el controlador por defecto 
                        en el módulo por defecto de cualquier solicitud que no 
                        sea dispatchable (es decir, el módulo, el controlador 
                        y/o la acción no existen). Por defecto, está en off.
                </para>

                <para>
                    Ver <xref linkend="zend.controller.exceptions.internal" />
                    para información más detallada sobre el uso de este setting.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>disableOutputBuffering</methodname> se usa para indicarle a <link
                        linkend="zend.controller.dispatcher">el
                        dispatcher</link> que no debe utilizar output buffering 
                    para capturar la salida generada por los controladores 
                    de acción. Por defecto, el dispatcher captura cualquier 
                    salida y la añade al contenido del cuerpo del objeto 
                    respuesta.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>noViewRenderer</methodname> se usa para deshabilitar el <link
                        linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
                    Poniendo este parámetro a true, lo deshabilita.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>noErrorHandler</methodname> se usa para deshabilitar el <link
                        linkend="zend.controller.plugins.standard.errorhandler">Error
                        Handler plugin</link>. Poniendo este parámetro a true, 
                        lo deshabilita.
                </para>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.front.subclassing">
        <title>Extendiendo el Front Controller</title>

        <para>
            Para extender el Front Controller, como mínimo que necesitará 
            anular el método <methodname>getInstance()</methodname>:
        </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>
            Anulando el método <methodname>getInstance()</methodname> asegura que las 
            subsiguientes llamadas a
            <classname>Zend_Controller_Front::getInstance()</classname> 
            devolverá una instancia de su nueva subclase en lugar de una 
            instancia 
            <classname>Zend_Controller_Front</classname> -- esto es 
            particularmente útil para algunos de los routers alternativos y 
            view helpers.
        </para>

        <para>
            Típicamente, no necesitará una subclase del front controller 
            a menos que necesite añadir nuevas funcionalidades 
            (por ejemplo, un plugin autoloader, o una forma de especificar 
            los paths de los action helpers). Algunos de los puntos donde puede 
            querer modificar el comportamiento puede incluir modificar cómo 
            son almacenados los directorios de controladores , o qué router 
            predeterminado o dispatcher se utiliza.
        </para>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
