Symfony 4: Kernel Events y casos de uso

Principales casos de uso de los Kernel Events de Symfony

Image for post
Image for post

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 la Request o devolver directamente una Response (por ejemplo, si estamos implementando una capa de seguridad).

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:

  1. Si la Request contiene un atributo con ese nombre, asocia el valor de dicho atributo al argumento de la función.

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 :

Image for post
Image for post

En esta clase lo que hago es:

  1. Escuchar mediante un EventSubscriber el evento KernelEvents::REQUEST

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:

Image for post
Image for post

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étodo fastcgi_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:

Image for post
Image for post

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:

Written by

Entre paseo y paseo con Simba desarrollo en Symfony y React

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store