Antes de adentrarnos más profundamente en este proceso, vamos a hablar de una de las partes más importantes del flujo de trabajo de Symfony: las factorías.
Las factorías en Symfony son una serie de clases o componentes de los que depende
tu aplicación, como por ejemplo logger
o i18n
. Cada factoría se configura
en el archivo factories.yml
, que después se compila mediante un gestor de
configuración (como se explicará más adelante) para convertirlo en el código PHP
que realmente instancia los objetos factoría (puedes ver el resultado de este
proceso en el archivo cache/frontend/dev/config/config_factories.yml.php
de
tu cache).
Nota La carga de las factoría se realiza durante la inicialización de sfContext
.
Puedes ver el código de sfContext::initialize()
y sfContext::loadFactories()
para obtener más información.
En este punto ya puedes personalizar gran parte del comportamiento de Symfony
simplemente editando la configuración del archivo factories.yml
. Incluso es
posible reemplazar algunas clases internas de Symfony por tus propias clases de
tipo factoría.
Nota Si quieres conocer más detalles de las factorías, lo mejor es que leas la
Referencia de Symfony
así como el contenido del propio archivo
factories.yml
.
Si has echado un vistazo al archivo config_factories.yml.php
, habrás observado
que las factorías se instancia en un determinado orden. Este orden es muy
importante porque algunas factorías dependen de otras (el componente routing
por ejemplo requiere el componente request
para obtener la información que
necesita).
Seguidamente se va a detallar el funcionamiento de la petición (request
). Por
defecto, las peticiones se representan mediante clases de tipo sfWebRequest
.
Al crear su instancia, se invoca el método
sfWebRequest::initialize()
,
que obtiene información relevante como el método HTTP empleado y los parámetros
GET y POST enviados. Si quieres modificar el procesamiento de las peticiones,
puedes hacer uso del evento request.filter_parameters
.
10.2.1. Utilizando el evento request.filter_parameter
Imagina que tu sitio web dispone de una API pública accesible mediante HTTP.
Para que la aplicación valide la petición, cada usuario de la API debe proporcionar
una clave a través de una cabecera de la petición (llamada por ejemplo X_API_KEY
).
Todo esto se puede conseguir fácilmente mediante el evento request.filter_parameter
:
class apiConfiguration extends sfApplicationConfiguration
{
public function configure()
{
// ...
$this->dispatcher->connect('request.filter_parameters', array(
$this, 'requestFilterParameters'
));
}
public function requestFilterParameters(sfEvent $event, $parameters)
{
$request = $event->getSubject();
$api_key = $request->getHttpHeader('X_API_KEY');
if (null === $api_key || false === $api_user = Doctrine_Core::getTable('ApiUser')->findOneByToken($api_key))
{
throw new RuntimeException(sprintf('Invalid api key "%s"', $api_key));
}
$request->setParameter('api_user', $api_user);
return $parameters;
}
}
Después de ejecutar el código anterior, se puede obtener el usuario de la API directamente desde la petición:
public function executeFoobar(sfWebRequest $request)
{
$api_user = $request->getParameter('api_user');
}
Esta técnica se puede utilizar por ejemplo para validar las llamadas a los servicios web de tu aplicación.
Nota El evento request.filter_parameters
incluye mucha información sobre la
petición, tal y como se puede ver en la documentación de la API sobre el
método sfWebRequest::getRequestContext()
.
La siguiente factoría importante es el enrutamiento. La inicialización del
enrutamiento es muy sencilla, ya que sólo consiste en obtener y establecer una
serie de opciones específicas. Si quieres también puedes modificar este proceso
aprovechando el evento routing.load_configuration
.
Nota El evento routing.load_configuration
te da acceso a la instancia del objeto
con el enrutamiento actual (por defecto es un objeto de tipo
sfPatternRouting
).
Las rutas registradas se pueden manipular mediante diferentes métodos.
10.2.2. Ejemplo de uso del evento routing.load_configuration
Gracias a este evento es muy fácil añadir una nueva ruta en la aplicación:
public function setup()
{
// ...
$this->dispatcher->connect('routing.load_configuration', array(
$this, 'listenToRoutingLoadConfiguration'
));
}
public function listenToRoutingLoadConfiguration(sfEvent $event)
{
$routing = $event->getSubject();
if (!$routing->hasRouteName('my_route'))
{
$routing->prependRoute('my_route', new sfRoute(
'/my_route', array('module' => 'default', 'action' => 'foo')
));
}
}
El procesamiento de las URL ocurre justo después de la inicialización mediante
el método sfPatternRouting::parse()
.
Aunque durante este proceso intervienen varios métodos, lo único que hay que
saber es que para cuando se llega al final del método parse()
, se ha encontrado
la ruta correcta, se ha instanciado y se le han asociado los parámetros adecuados.
Nota Si quieres conocer más sobre el enrutamiento, puedes leer el capítulo "Enrutamiento avanzado" de este mismo libro.
Una vez que se han cargado y configurado correctamente todas las factorías, se
notifica el evento context.load_factories
. Este evento es importante porque
es el primer evento del framework en el que el programador tiene acceso a todos
los objetos de las factorías de Symfony (petición, respuesta, usuario, log,
bases de datos, etc.)
Este es también el punto en el que puedes conectarte a otro evento muy útil
llamado template.filter_parameters
. Este evento se notifica cada vez que
sfPHPView
procesa y muestra un archivo, por lo que permite al programador controlar los
parámetros que se le pasan a la plantilla. sfContext
utiliza este evento para
añadir algunos parámetros útiles a cada plantilla (en concreto, $sf_context
,
$sf_request
, $sf_params
, $sf_response
y $sf_user
).
Por tanto, puedes hacer uso del evento template.filter_parameters
para añadir
parámetros globales adicionales en todas las plantillas.
10.2.3. Utilizando el evento template.filter_parameters
Imagina que todas las plantillas de tu aplicación deben tener acceso a un
objeto determinado, por ejemplo un helper. En este caso, puedes añadir el
siguiente código en ProjectConfiguration
:
public function setup()
{
// ...
$this->dispatcher->connect('template.filter_parameters', array(
$this, 'templateFilterParameters'
));
}
public function templateFilterParameters(sfEvent $event, $parameters)
{
$parameters['my_helper_object'] = new MyHelperObject();
return $parameters;
}
Ahora todas las plantillas tienen acceso a una instancia de MyHelperObject
mediante la variable $my_helper_object
.
10.2.4. Resumen de sfContext
- Inicialización de
sfContext
- Se cargan las factorías
- Se notifican los siguientes eventos:
- Se añaden los parámetros globales en las plantillas