<?xml version="1.0" encoding="UTF-8"?>
    <!-- EN-Revision: 24249 -->
    <!-- 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 <emphasis>ErrorHandler</emphasis> ,
                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 <emphasis>ViewRenderer</emphasis> , 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
                        <emphasis>default</emphasis> 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 y 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
                    <filename>/controllers/</filename> , y típicamente un
                subdirectorio de <filename>/views/</filename> 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 <acronym>HTTP</acronym> 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>
                <methodname>Zend_Controller_Front::run($path)</methodname> 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>setDefaultAction()</methodname> y
                        <methodname>getDefaultAction()</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>setRequest()</methodname> y
                        <methodname>getRequest()</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>setRouter()</methodname>
                    <methodname>getRouter()</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>setBaseUrl()</methodname> y
                        <methodname>getBaseUrl()</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>setDispatcher()</methodname> y
                        <methodname>getDispatcher()</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>setResponse()</methodname> y
                        <methodname>getResponse()</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
                        <varname>$stackIndex</varname> , 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> . <varname>$plugin</varname>
                    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 o 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"/> MVC
                    Exceptions </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>returnResponse($flag)</methodname> se usa para
                    decirle al front controller cuando regresar la respuesta (
                        <constant>TRUE</constant> ) desde
                        <methodname>dispatch()</methodname> , o si la respuesta
                    debe ser emitida automáticamente (
                        <constant>FALSE</constant> ). Por defecto, la respuesta
                    es automáticamente emitida (llamando a
                        <methodname>Zend_Controller_Response_Abstract::sendResponse()</methodname>
                    ); 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 <varname>$name</varname>
                    con el valor <varname>$value</varname> . </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
                        <varname>$name</varname> . </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>
                    <emphasis>useDefaultControllerAlways</emphasis> 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 <link linkend="zend.controller.exceptions.internal"
                        >MVC Exceptions You May Encounter</link> para
                    información más detallada sobre el uso de este setting.
                </para>
            </listitem>

            <listitem>
                <para>
                    <emphasis>disableOutputBuffering</emphasis> 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>
                    <emphasis>noViewRenderer</emphasis> 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>
                    <emphasis>noErrorHandler</emphasis> 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
                <methodname>Zend_Controller_Front::getInstance()</methodname>
            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>
