How to create an event in Symfony?

Eventos Symfony: Personalización y Gestión Avanzada

hace 2 años

Valoración: 4.1 (3289 votos)

En el desarrollo de aplicaciones web robustas y escalables con Symfony, la gestión de eventos juega un papel crucial. Permite desacoplar componentes, mejorar la mantenibilidad y extender la funcionalidad de tu aplicación de manera elegante y eficiente. En este artículo, exploraremos en profundidad el mundo de los eventos en Symfony, desde la creación de eventos personalizados y sus suscriptores, hasta la gestión de eventos de formularios y la configuración de la protección CSRF. Prepárate para sumergirte en el corazón de la arquitectura basada en eventos de Symfony y descubrir cómo puedes aprovecharla al máximo en tus proyectos.

Índice de Contenido

Eventos Personalizados y Suscriptores de Eventos en Symfony

Un evento, en el contexto de la programación, se define como algo que sucede. En un sistema de comercio electrónico, por ejemplo, eventos comunes incluyen la creación de un producto, la actualización de un producto, la eliminación de un producto, la creación de un pedido, y muchos más. Symfony, por su parte, ya incorpora una serie de eventos predefinidos, especialmente en el componente HttpKernel, que te permiten modificar el manejo de las peticiones y el proceso de retorno de las respuestas. Algunos ejemplos de estos eventos internos son kernel.request, kernel.response y kernel.terminate, entre otros, que puedes consultar en la documentación oficial de Symfony.

What are the form events?
Form Events are actions that occur on a form, to which you can add custom actions of your own. Many events fire automatically as part of the form's natural life cycle. For instance, when a form is first opened, an event called Form Creation is fired.

Para comenzar a trabajar con eventos en Symfony, ya sean los predefinidos o personalizados, es fundamental tener instalado el componente EventDispatcher. Este componente proporciona las herramientas necesarias para despachar eventos y permitir la comunicación entre diferentes componentes de tu aplicación, así como para escuchar y reaccionar a estos eventos. Puedes instalarlo fácilmente mediante Composer con el siguiente comando:

composer require symfony/event-dispatcher 

Creando Eventos Personalizados

Symfony te brinda la flexibilidad de crear tus propios eventos personalizados para adaptarlos a las necesidades específicas de tu aplicación. Para ello, debes crear una clase de evento dentro del directorio src/Event. Siguiendo con el ejemplo del comercio electrónico, vamos a crear un evento para la creación de productos:

// src/ProductCreateEvent.php <?php namespace Product\Event; use Symfony\Contracts\EventDispatcher\Event; class ProductCreateEvent extends Event { public const NAME = 'product.created'; // ... } 

Como puedes observar, la creación de un evento personalizado es bastante sencilla. Basta con extender la clase Event y definir una constante NAME que identificará de manera única a este evento. De manera similar, podrías crear eventos para la actualización (ProductUpdateEvent) y la eliminación (ProductDeleteEvent) de productos.

Creando Suscriptores de Eventos

Un suscriptor de eventos es una clase PHP que implementa la interfaz EventSubscriberInterface. Su función principal es escuchar eventos específicos que son despachados por un publicador de eventos. La interfaz EventSubscriberInterface obliga a implementar el método estático getSubscribedEvents(). Este método es crucial, ya que es el que le indica al despachador de eventos a qué eventos se suscribe esta clase. Retorna un array asociativo donde las claves son los nombres de los eventos y los valores son los nombres de los métodos que se ejecutarán cuando se despachen esos eventos.

Continuando con nuestro ejemplo, vamos a crear un suscriptor de eventos para el evento de creación de productos:

// src/Event/ProductEventSubscriber.php <?php namespace Product\Event; use Product\Event\ProductCreateEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; class ProductEventSubscriber implements EventSubscriberInterface { // Retorna un array indexado por el nombre del evento y el valor por el nombre del método a llamar public static function getSubscribedEvents() { return [ ProductCreateEvent::NAME => 'onProductCreation', // Engancha múltiples funciones con los eventos con prioridad para la secuencia de llamadas a funciones ProductUpdateEvent::NAME => [ ['onProductCreation', 1], ['onProductUpdation', 2], ], ProductDeleteEvent::NAME => 'onProductDeletion', KernelEvents::RESPONSE => 'onKernelResponse', ]; } public function onProductCreation(ProductCreateEvent $event) { // Escribe código para ejecutar en el evento de creación de producto } public function onProductUpdation(ProductUpdateEvent $event) { // Escribe código para ejecutar en el evento de actualización de producto } public function onProductDeletion(ProductDeleteEvent $event) { // Escribe código para ejecutar en el evento de eliminación de producto } public function onKernelResponse(ResponseEvent $event) { // Escribe código para ejecutar en el evento interno Kernel Response } } 

En este ejemplo, nuestro suscriptor ProductEventSubscriber se suscribe a tres eventos personalizados de producto (creación, actualización y eliminación) y también al evento interno KernelEvents::RESPONSE. Para cada evento, define un método que se ejecutará cuando el evento sea despachado.

Añadiendo Suscriptores y Despachando Eventos

Para que nuestro suscriptor sea efectivo, debemos registrarlo en el despachador de eventos y despachar el evento en el lugar de nuestro código donde ocurra la acción correspondiente. El método addSubscriber() del despachador de eventos se utiliza para registrar un suscriptor. Debemos pasar una instancia de la clase suscriptora como parámetro. El método dispatch() es el encargado de notificar a todos los suscriptores de un evento. Requiere dos parámetros: una instancia de la clase del evento y el nombre del evento (definido en la constante NAME de la clase del evento).

Veamos un ejemplo en un controlador:

// src/controller/ProductController.php <?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Product\Event\ProductCreateEvent; use Product\Event\ProductEventSubscriber; class ProductController extends AbstractController { public function __construct(EventDispatcherInterface $eventDispatcher) { $this->eventDispatcher = $eventDispatcher; } /** * @Route("/products/new") */ public function new(): Response { $event = new ProductCreateEvent(); $this->eventDispatcher->addSubscriber(new ProductEventSubscriber()); $this->eventDispatcher->dispatch($event, ProductCreateEvent::NAME); return new Response('Producto creado.'); } } 

En este controlador, al crear un nuevo producto, creamos una instancia de ProductCreateEvent, registramos nuestro ProductEventSubscriber y despachamos el evento ProductCreateEvent::NAME. Esto activará el método onProductCreation de nuestro suscriptor.

Alternativamente, y de manera más recomendada en Symfony, puedes registrar tus suscriptores de eventos a través del archivo de configuración services.yaml. Esto permite que Symfony gestione la instanciación y el registro de tus suscriptores de forma automática:

# config/services.yaml services: Product\Event\ProductEventSubscriber: tags: - { name: kernel.event_subscriber, event: product.created } 

Con esta configuración, Symfony registrará automáticamente ProductEventSubscriber como suscriptor del evento product.created.

How to disable CSRF in Symfony form?
To disable CSRF protection, set the csrf_protection option to false. Customizations can also be made globally in your project. For more information, see the form configuration reference section.

Eventos de Formulario en Symfony

Los eventos de formulario en Symfony son acciones que ocurren durante el ciclo de vida de un formulario, a las cuales puedes adjuntar acciones personalizadas. Muchos eventos se disparan automáticamente como parte del flujo natural de un formulario. Por ejemplo, cuando un formulario se crea por primera vez, se dispara el evento Form Creation.

Symfony proporciona varios eventos de formulario que puedes utilizar para extender y personalizar el comportamiento de tus formularios. Algunos de los eventos más comunes incluyen:

  • Form Creation: Se dispara cuando se instancia un formulario para su visualización.
  • View State Init: Se dispara durante la preparación del formulario para su visualización.
  • Event: Se dispara en cualquier evento.
  • Before Conditions: Se dispara antes de que se evalúen las condiciones del formulario, como la visibilidad o el estado habilitado de los controles.
  • After Conditions: Se dispara después de que se han procesado todas las condiciones del formulario.
  • Before Validation: Se dispara cuando se ha enviado el formulario, pero antes de que se evalúen las condiciones de validación.
  • After Validation: Se dispara después de que se han procesado todas las condiciones de validación.
  • Form Display: Se dispara cuando el formulario se muestra en el navegador. En este evento se procesan acciones como Fill Dropdown y cálculos de formulario.
  • Form Completed: Se dispara después de que la visualización del formulario ha finalizado (cuando se cierra el formulario) y justo antes de que el formulario se elimine de la memoria.
  • No Event: Placeholder para evitar que una acción se dispare en ningún evento.
  • Ajax Request: Se dispara cuando se procesa una solicitud Ajax JavaScript del lado del cliente.

Estos eventos se pueden utilizar para realizar diversas tareas, como modificar datos del formulario, realizar validaciones personalizadas, o ejecutar tareas adicionales antes o después de que se procese el formulario.

Deshabilitando la Protección CSRF en Formularios Symfony

CSRF (Cross-site request forgery) es una técnica maliciosa mediante la cual un atacante intenta que usuarios legítimos envíen datos de forma involuntaria. Afortunadamente, Symfony incorpora protección contra ataques CSRF mediante el uso de tokens CSRF en los formularios. De hecho, por defecto, Symfony activa y valida automáticamente los tokens CSRF en todos los formularios.

La protección CSRF funciona añadiendo un campo oculto llamado _token (por defecto) al formulario. Este campo contiene un valor secreto que solo conocen tu aplicación y el usuario. Symfony valida automáticamente la presencia y la exactitud de este token al procesar el formulario.

El campo _token se renderiza automáticamente cuando utilizas la función form_end() en tu plantilla, asegurando que todos los campos no renderizados se incluyan en el formulario.

Precaución: Dado que el token se almacena en la sesión, se inicia una sesión automáticamente al renderizar un formulario con protección CSRF.

Puedes personalizar la protección CSRF formulario por formulario. Por ejemplo, en la definición de un tipo de formulario, puedes configurar las siguientes opciones:

use AppBundle\Entity\Task; use Symfony\Component\OptionsResolver\OptionsResolver; class TaskType extends AbstractType { public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Task::class, 'csrf_protection' => true, 'csrf_field_name' => '_token', 'csrf_token_id' => 'task_item', ]); } } 

Para deshabilitar la protección CSRF en un formulario específico, simplemente debes establecer la opción csrf_protection a false:

$resolver->setDefaults([ 'csrf_protection' => false, ]); 

También puedes realizar personalizaciones globales para la protección CSRF en tu proyecto. Consulta la documentación de Symfony para obtener más información sobre la configuración de formularios.

How to create an event in Symfony?
php namespace Product\Event; use Symfony\Contracts\EventDispatcher\Event; class ProductCreateEvent extends Event { public const NAME = 'product. created'; // .... } That's it. Our event for product creation is created.

La opción csrf_token_id es opcional, pero mejora significativamente la seguridad del token generado al hacerlo diferente para cada formulario, lo cual es altamente recomendable.

Preguntas Frecuentes (FAQ) sobre Eventos en Symfony

  1. ¿Qué componente de Symfony necesito para trabajar con eventos?

    Necesitas el componente symfony/event-dispatcher. Puedes instalarlo con Composer: composer require symfony/event-dispatcher.

  2. ¿Cómo creo un evento personalizado en Symfony?

    Crea una clase en el directorio src/Event que extienda Symfony\Contracts\EventDispatcher\Event y define una constante NAME para identificar el evento.

  3. ¿Qué es un suscriptor de eventos?

    Es una clase PHP que implementa EventSubscriberInterface y escucha eventos específicos. Define los eventos a los que se suscribe en el método estático getSubscribedEvents().

  4. ¿Cómo registro un suscriptor de eventos en Symfony?

    Puedes registrarlo en un controlador usando $eventDispatcher->addSubscriber(new MySubscriber()) o, de manera más recomendada, en el archivo services.yaml.

  5. ¿Cómo deshabilito la protección CSRF en un formulario Symfony?

    En la configuración de tu tipo de formulario, establece la opción csrf_protection a false en el método configureOptions.

En resumen, los eventos son una herramienta poderosa en Symfony que te permite crear aplicaciones más flexibles, mantenibles y extensibles. Dominar la creación de eventos personalizados, suscriptores y la gestión de eventos de formulario, incluyendo la configuración de CSRF, te permitirá llevar tus proyectos Symfony a un nivel superior. ¡Sigue explorando y experimentando con los eventos en Symfony para aprovechar al máximo su potencial!

Subir