Symfony 4: Kernel Events y casos de uso
Principales casos de uso de los Kernel Events de Symfony

En este artículo quiero hablaros de dos casos de uso donde aplicar los Kernel Events
de Symfony, es decir, los eventos que Symfony lanza a medida que procesa la Request
entrante y genera la Response
.
A modo de resumen os diré que existen 8 eventos que podemos escuchar desde un EventListener
o un EventSubscriber
aunque para este artículo solo emplearemos dos de ellos. Estos 8 eventos son los siguientes:
KernelEvents::REQUEST
, que nos permite añadir información adicional a laRequest
o devolver directamente unaResponse
(por ejemplo, si estamos implementando una capa de seguridad).KernelEvents::CONTROLLER
, donde podremos inicializar aquellas partes de nuestra aplicación que así lo requieran antes de que se ejecute el controlador. Además, también es posible modificar desde este evento el controlador que se va a ejecutar mediante el métodosetController
del evento.KernelEvents::CONTROLLER_ARGUMENTS
desde el que podremos modificar los argumentos que posteriormente serán pasados a la acción del controlador.KernelEvents::VIEW
. Aunque generalmente estamos acostumbrados a que los controladores devuelvan unaResponse
, no tiene siempre por qué ser así. En el caso de que un controlador devuelva otro tipo de valor (siempre que no seanull
) desde este evento podremos modificarlo para devolver unaResponse
.KernelEvents::RESPONSE
, con el que podremos modificar el objetoResponse
que será devuelto.KernelEvents::FINISH_REQUEST
, que se ejecuta una vez que laRequest
entrante ha sido procesada completamente.KernelEvents::TERMINATE
, evento que se genera una vez que la respuesta ha sido enviada al usuario (siempre que estemos empleando un servidor con PHP-FPM) y que nos permitirá realizar operaciones complejas que habremos “retrasado” hasta ese momento de cara a devolver laResponse
lo más rápido posible.KernelEvents::EXCEPTION
donde podremos escuchar las excepciones generadas por la aplicación y actuar en consecuencia si así lo necesitásemos.
Una vez que ya conocemos todos los eventos que genera el Kernel
de Symfony, vamos a ver 3 casos de uso para ellos que creo que pueden ser interesantes.
Establecer un argumento para todos los controladores
Imaginad que queremos que todos los controladores tengan la opción de poder recibir un parámetro que no pertenece a la Request
propiamente dicha (por ejemplo, una entidad que represente un valor guardado en las cookies) sino que debe ser calculado de alguna determinada manera.
Esto, que podría sonar complicado de conseguir, es bastante sencillo si empleamos los Kernel Events y conocemos la manera en que Symfony asocia los parámetros de la Request a los argumentos de la función invocada en el controlador asociado a la ruta.
Grosso modo, lo que hace Symfony es obtener mediante reflection el nombre de los argumentos de la función a invocar e intenta asociarles su valor en 3 pasos:
- Si la
Request
contiene un atributo con ese nombre, asocia el valor de dicho atributo al argumento de la función. - Si es un argumento tipado como
Request
, directamente le asocia el objetoRequest
. - Si se trata de un tipo
variadic
comprueba si dentro de los atributos de laRequest
existe unarray
que pueda asociarlo.
Para este ejemplo lo que nos interesa es el punto 1, pues si por ejemplo nuestro controlador tiene una acción con esta forma:
public function someAction(CustomClass $object, Request $request) {
bastará con que la Request
contenga un atributo llamado object
para que Symfony lo asocie directamente. ¿Y como conseguimos eso? Mediante el KernelEvent::REQUEST
:

En esta clase lo que hago es:
- Escuchar mediante un
EventSubscriber
el eventoKernelEvents::REQUEST
- Descartar el evento si no se trata la
Request
principal (por ejemplo, el métodoforward
de la claseController
generasub-requests
) - Calcular mediante el servicio
customClassManager
el objeto que queramos o el valor a partir de laRequest
- Establecer un atributo en la
Request
llamadoobject
con el valor del objeto calculado de modo que siempre que un controlador tenga en una acción un argumento llamadoobject
, Symfony lo asociará directamente a este valor.
Como apunte final, me gustaría reseñar que este mecanismo es el que usa el componente ParamConverter
para realizar directamente la carga de entidades o la creación de objetos DateTime
a partir de fechas en la Request
:
Establecer automáticamente un valor en la Response
Otra de las aplicaciones de los Kernel Events es poder modificar el valor de la Response
antes de ser enviada al usuario. El caso más habitual es establecer una cookie en ella, de modo que no tengamos que delegar esa tarea en cada controlador de nuestra aplicación. Para ello, bastará con escuchar el evento KernelEvents::RESPONSE
del siguiente modo:

En este caso el proceso es bastante sencillo. Declaramos un EventSubscriber
asociado al evento KernelEvents::RESPONSE
y en el método onResponse
estableceremos la cookie
que queramos en las cabeceras del objeto Response
que posee el evento FilterResponseEvent
.
Realizar tareas una vez que se ha enviado la Response al usuario
Finalmente, imaginad el siguiente caso: cada formulario de contacto que recibamos tenemos que enviarlo a un CRM externo pero no queremos que el usuario tenga que esperar a que esa llamada se complete para recibir la Response
y que el navegador cargue la pantalla de ¡Gracias!
.
Una solución sería delegar esta tarea a una cola Rabbit, pero por desgracia no siempre disponemos de los recursos para montar este tipo de infraestructuras.
Sin embargo, Symfony nos provee de una alternativa que nos servirá en la mayoría de las ocasiones: el evento Kernel::TERMINATE
el cual se ejecuta una vez que la respuesta se ha enviado al usuario:
// sends the headers and echoes the content
$response->send();
// triggers the kernel.terminate event
$kernel->terminate($request, $response);
Tal y como dice la documentación, el
Kernel
emplea el métodofastcgi_finish_request
para poder ejecutar código una vez que se ha devuelto al cliente la respuesta. Sin embargo, solo arquitecturas bajo PHP-FPM soportan ese funcionamiento, por lo que el resto seguirán esperando a que se complete la tarea antes de devolver la respuesta al usuario.
Dicho esto, para ejecutar este tipo de tareas nos bastará con un nuevo EventSubscriber
con el siguiente aspecto:

Como habréis visto, el Kernel de Symfony nos da una forma bastante sencilla de interactuar con el proceso de generación de la Response
en cualquier momento, por lo que si queréis profundizar más podéis ir a la documentación del resto de eventos:
¿Quieres recibir más artículos como este?
Suscríbete a nuestra newsletter: