Event dispatcher

Event dispatcher

Events and Event Listeners

  • Creating an event listener

    // src/EventListener/ExceptionListener.php
    namespace App\EventListener;
    
    class ExceptionListener
    {
        public function __invoke(ExceptionEvent $event): void // this event listener listens to Excepction events
        {
            // You get the exception object from the received event
            $exception = $event->getThrowable();
    
    				// ...
    
            // sends the modified response object to the event
            $event->setResponse($response);
        }
    }
    # config/services.yaml
    services:
      App\EventListener\ExceptionListener: # register the class and tell symfony that is an event listener 
          tags: [kernel.event_listener] # or { name: kernel.event_listener, event: kernel.exception (if not typ), method: methodName }

    Using php attributes

    namespace App\EventListener;
    
    use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
    
    #[AsEventListener(event: CustomEvent::class, method: 'onCustomEvent')]
    #[AsEventListener(event: 'foo', priority: 42)]
    #[AsEventListener(event: 'bar', method: 'onBarEvent')]
    final class MyMultiListener
    {
        public function onCustomEvent(CustomEvent $event): void
        {
            // ...
        }
    
        public function onFoo(): void
        {
            // ...
        }
    
        public function onBarEvent(): void
        {
            // ...
        }
    
        #[AsEventListener(event: 'bar')]
        public function onBarEvent(): void
        {
            // ...
        }
    }
  • Creating an Event Subscriber

Event Subscriber: Class that defines one or more methods that listen to on or various events. Self-contained, doesn’t need yaml config

// src/EventSubscriber/ExceptionSubscriber.php
namespace App\EventSubscriber;

class ExceptionSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::EXCEPTION => [
                ['processException', 10],
                ['logException', 0],
                ['notifyException', -10],
            ],
        ];
    }

    public function processException(ExceptionEvent $event): void
    {
        // ...
    }

    public function logException(ExceptionEvent $event): void
    {
        // ...
    }

    public function notifyException(ExceptionEvent $event): void
    {
        // ...
    }
}
  • Dispatch custom event

Event

// src/Event/AfterSendMailEvent.php
namespace App\Event;

use Symfony\Contracts\EventDispatcher\Event;

class AfterSendMailEvent extends Event
{
    public function __construct(
        private mixed $returnValue,
    ) {
    }

    public function getReturnValue(): mixed
    {
        return $this->returnValue;
    }

    public function setReturnValue(mixed $returnValue): void
    {
        $this->returnValue = $returnValue;
    }
}

Subscriber

// src/EventSubscriber/MailPostSendSubscriber.php
namespace App\EventSubscriber;

use App\Event\AfterSendMailEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class MailPostSendSubscriber implements EventSubscriberInterface
{
    public function onMailerPostSend(AfterSendMailEvent $event): void
    {
        $returnValue = $event->getReturnValue();
        // modify the original $returnValue value

        $event->setReturnValue($returnValue);
    }

    public static function getSubscribedEvents(): array
    {
        return [
            'mailer.post_send' => 'onMailerPostSend',
        ];
    }
}
  1. Observer Pattern:

    • Purpose: The Observer pattern is a software design pattern where an object (known as the subject) maintains a list of its dependents (observers) and notifies them automatically of any state changes, usually by calling one of their methods.

    • In Symfony: In the context of Symfony's EventDispatcher, the events are the "subjects," and the event listeners or subscribers are the "observers". When an event is dispatched, the EventDispatcher notifies all registered listeners for that event, thus "observing" the event.

    • Benefits: This pattern promotes loose coupling, as the subject doesn't need to know anything about the observers beyond the fact that they implement a certain interface. This allows for very dynamic behavior, as observers can be added, removed, or changed at runtime.

  2. Mediator Pattern:

    • Purpose: The Mediator pattern is used to reduce chaos among interconnected components in a system by encapsulating the way these components interact. It promotes the principle that "objects don't call each other directly but instead go through a mediator."

    • In Symfony: The EventDispatcher acts as a mediator in the sense that it's the object through which events (messages) pass. The components dispatching events and the listeners responding to them don't interact directly. They connect through the dispatcher, which handles the routing of events to the appropriate listeners.

    • Benefits: This central point of control allows for more controlled, maintainable interactions between objects. It also makes your system easier to understand, change, and extend.