# El Front Controller

## Introducción

`Zend_Controller_Front` implementa un Front Controller pattern usado en aplicaciones Model-View-Controller (MVC). 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.

`Zend_Controller_Front` también implementa el Singleton pattern, 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.

`Zend_Controller_Front` registra un plugin broker 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.

Como mínimo, el front controller necesita una o más paths a directorios que contengan action controllers 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.

### Comportamiento por Defecto

Por defecto, el front controller carga el ErrorHandler plugin, así como al ViewRenderer action helper plugin. Estos son para simplificar el manejo de errores y el view renderering en sus controladores, respectivamente.

Para deshabilitar el `ErrorHandler`, ejecutar lo siguiente en cualquier momento antes de llamar a `dispatch()`:

    // Deshabilitar el ErrorHandler plugin:
    $front->setParam('noErrorHandler', true);

Para deshabilitar el `ViewRenderer`, haga lo siguiente antes de llamar a `dispatch()`:

    // Deshabilitar el ViewRenderer helper:
    $front->setParam('noViewRenderer', true);

## Métodos Básicos

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:

### getInstance()

`getInstance()` 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.

    $front = Zend_Controller_Front::getInstance();

### setControllerDirectory() y addControllerDirectory

`setControllerDirectory()` se usa para decirle a el dispatcher dónde buscar para los archivos de clase action controller. Acepta bien un único path o un array asociativo de pares módulo/path.

Como algunos ejemplos:

    // 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');

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

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

### addModuleDirectory() y getModuleDirectory()

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

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.

`addModuleDirectory()` 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.

Después, si quiere determinar el path a un determinado módulo o al módulo actual, puede llamar a `getModuleDirectory()`, opcionalmente puede pasar un nombre de módulo para conseguir el directorio de ese módulo específico.

### dispatch()

`dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null)` hace el trabajo pesado del front controller. Puede opcionalmente tomar un request object y/o un response object, permitiendo al desarrollador pasar objetos peronalizados para cada uno.

Si no se pasa ningun objeto solicitud o respuesta, `dispatch()` 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).

Similarmente, `dispatch()` comprueba los objetos registrados router y dispatcher , instanciando las versiones por defecto de cada uno si ninguno de ellos se encuentra.

El proceso de dispatch tiene tres eventos distintos:

- Routing

- Dispatching

- Response

El routing se lleva a cabo exactamente una vez, utilizando los valores del objeto solicitud cuando se llama a `dispatch()`. 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.

### run()

`Zend_Controller_Front::run($path)` es un método estático que toma simplemente un path a un directorio que contiene controladores. Obtiene una instancia del front controller (via getInstance(), registra el path provisto via setControllerDirectory(), y finalmente dispatches.

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

    // 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');

## Métodos Accessor Ambientales

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.

- `resetInstance()` 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.

- `(set|get)DefaultControllerName()` 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 el dispatcher.

- `(set|get)DefaultAction()` 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 el dispatcher.

- `(set|get)Request()` le permite especificar la clase u objeto el request 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á.

- `(set|get)Router()` le permite especificar la clase u objeto el router 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á.

  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).

- `(set|get)BaseUrl()` le permite especificar la URL base de la cual tirar cuando se rutean peticiones y recuperar el valor actual. El valor se provee al objeto solicitud justo antes de rutear.

- `(set|get)Dispatcher()` le permite especificar la clase u objeto el dispatcher 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á.

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

- `(set|get)Response()` le permite especificar la clase u objeto response 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á.

- `registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null)` le permite registrar plugin objects. Opcionalmente, setting `$stackIndex`, puede controlar el orden en que se ejecutarán los plugins.

- `unregisterPlugin($plugin)` le permite desregistrar plugin objects. `$plugin` puede ser tanto un objeto plugin o un string que denota la clase de plugin a desregistrar.

- `throwExceptions($flag)` 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 objeto response ; activando `throwExceptions()` se anulará este comportamiento.

  Para más información, lea .

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

  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.

## Parámetros de Front Controller

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:

- `setParam($name, $value)` permite establecer un único parámetro de `$name` con el valor `$value`.

- `setParams(array $params)` permite configurar varios parámetros a la vez usando un array asociativo.

- `getParam($name)` permite recuperar un único parámetro a la vez, utilizando como identificador a `$name`.

- `getParams()` permite recuperar toda la lista de parámetros a la vez.

- `clearParams()` 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).

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

- `useDefaultControllerAlways` se usa para indicar a el dispatcher 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.

  Ver para información más detallada sobre el uso de este setting.

- `disableOutputBuffering` se usa para indicarle a el dispatcher 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.

- `noViewRenderer` se usa para deshabilitar el ViewRenderer. Poniendo este parámetro a true, lo deshabilita.

- `noErrorHandler` se usa para deshabilitar el Error Handler plugin. Poniendo este parámetro a true, lo deshabilita.

## Extendiendo el Front Controller

Para extender el Front Controller, como mínimo que necesitará anular el método `getInstance()`:

    class My_Controller_Front extends Zend_Controller_Front
    {
        public static function getInstance()
        {
            if (null === self::$_instance) {
                self::$_instance = new self();
            }

            return self::$_instance;
        }
    }

Anulando el método `getInstance()` asegura que las subsiguientes llamadas a `Zend_Controller_Front::getInstance()` devolverá una instancia de su nueva subclase en lugar de una instancia `Zend_Controller_Front` -- esto es particularmente útil para algunos de los routers alternativos y view helpers.

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.