Más con Symfony

10.4. Despachando y ejecutando la petición

Una vez presentadas las factorías, volvemos a la explicación del proceso que despacha las peticiones. Tras la inicialización de sfContext, se invoca el método dispatch() del controlador, sfFrontWebController::dispatch().

En Symfony el proceso que despacha las peticiones es muy sencillo. De hecho, sfFrontWebController::dispatch() simplemente obtiene el nombre del módulo y de la acción a partir de los parámetros de la petición y redirige la aplicación mediante sfController::forward().

Nota En este punto, si el enrutamiento no puede encontrar ningún módulo o acción a partir de la URL, se lanza una excepción de tipo sfError404Exception, que redirige la petición al módulo encargado de procesar la respuesta del error 404 (ver información sobre sf_error_404_module y sf_error_404_action). Si quieres mostrar un error de tipo 404 en cualquier punto de la aplicación, tu también puedes lanzar esta excepción.

El método forward realiza muchas comprobaciones previas a la ejecución, además de preparar la configuración y los datos para la acción se que va a ejecutar.

En primer lugar el controlador comprueba si existe un archivo llamado generator.yml en el módulo actual. Esta comprobación es la primera que se realiza (después de una limpieza básica del nombre del módulo y de la acción) porque el archivo de configuración generator.yml (si existe) se encarga de generar la clase base de las acciones del módulo (mediante su gestor de configuración, sfGeneratorConfigHandler). Esta comprobación es necesaria para el siguiente paso, que comprueba si existen el módulo y la acción. La comprobación se delega en el controlador, a través de su método sfController::actionExists(), que después invoca el método sfController::controllerExists(). Una vez más, si el método actionExists() falla, se lanza una excepción de tipo sfError404Exception.

Nota El gestor de configuración sfGeneratorConfigHandler es un tipo especial de gestor que se encarga de instanciar la clase generadora correcta para tu módulo y la ejecuta. Si quieres conocer más detalladamente los gestores de configuración, puedes leer la sección anterior de este mismo capítulo y también el capítulo 6 de la Referencia de Symfony.

En este punto no hay mucho que hacer salvo redefinir el método sfApplicationConfiguration::getControllerDirs() en la clase de configuración de la aplicación. Este método devuelve un array con los directorios en los que residen los controladores, además de un parámetro adicional que le indica a Symfony si debe comprobar que los controladores estén activados mediante la opción de configuración sf_enabled_modules del archivo settings.yml. El método getControllerDirs() podría tener por ejemplo el siguiente aspecto:

/**
 * Controllers in /tmp/myControllers won't need to be enabled
 * to be detected
 */
public function getControllerDirs($moduleName)
{
  return array_merge(parent::getControllerDirs($moduleName), array(
    '/tmp/myControllers/'.$moduleName => false
  ));
}

Nota Si la acción no existe, se lanza una excepción de tipo sfError404Exception.

El siguiente paso consiste en obtener una instancia del controlador que contiene la acción. De ello se encarga el método sfController::getAction(), que al igual que actionExists() es un intermediario del método sfController::getController(). Finalmente, la instancia del controlador se añade al conjunto de acciones o action stack.

Nota El conjunto de acciones es una pila de tipo FIFO (First In First Out) que contiene todas las acciones que se ejecutan durante la petición. Cada elemento de la pila se representa con un objeto de tipo sfActionStackEntry. La pila siempre está accesible mediante sfContext::getInstance()->getActionStack() o a través de $this->getController()->getActionStack() dentro de una acción.

Después de cargar algo más de configuración, ya será posible ejecutar la acción. De hecho, es necesario cargar la configuración específica del módulo, que se puede encontrar en dos lugares diferentes. Primero Symfony busca el archivo module.yml (que se encuentra normalmente en apps/frontend/modules/miModulo/config/module.yml), que como es un archivo de configuración YAML, utiliza la cache de configuración. Además, este archivo de configuración puede declarar el módulo como interno, utilizando la opción mod_miModulo_is_internal que hace que la petición produzca in error, ya que los módulos internos no se pueden acceder públicamente.

Nota Los módulos internos se utilizaban antes para generar el contenido de los emails (por ejemplo mediante getPresentationFor()). Ahora se utilizan otras técnicas, como los elementos parciales ($this->renderPartial()).

Después de cargar el archivo module.yml, se comprueba por segunda vez que el módulo actual está activado. Efectivamente, puedes establecer la opción mod_$moduleName_enabled a false si quieres deshabilitar el módulo en este punto.

Nota Como se ha mencionado, existen dos formas diferentes de activar o desactivar un módulo. La diferencia reside en lo que sucede cuando se deshabilita el módulo. En el primer caso, cuando está activada la opción sf_enabled_modules, un módulo desactivado provoca que se lance una excepción de tipo sfConfigurationException. Esta opción debería utilizarse cuando se deshabilita un módulo permanentemente. En el segundo caso, mediante la opción mod_$moduleName_enabled, el módulo deshabilitado provocará que la aplicación se redirija al módulo deshabilitado (ver las opciones sf_module_disabled_module y sf_module_disabled_action). Esta es la opción que debes utilizar cuando se deshabilita temporalmente un módulo.

La última oportunidad para configurar un módulo se encuentra en el archivo config.php (apps/frontend/modules/yourModule/config/config.php) donde puedes incluir cualquier código PHP que quieras que se ejecute dentro del contexto del método sfController::forward() (es decir, que tienes acceso a la instancia de sfController mediante la variable $this, ya que el código se ejecuta literalmente dentro de la clase sfController).

10.4.1. Resumen de cómo se despacha la petición

  1. Se invoca sfFrontWebController::dispatch()
  2. Se invoca sfController::forward()
  3. Se busca un archivo generator.yml
  4. Se comprueba que el módulo y la acción existen
  5. Se obtiene la lista de directorios de los controladores
  6. Se obtiene una instancia de la acción
  7. Se carga la configuración del módulo mediante module.yml y/o config.php