Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Events

An event is a message saying "this happened". The code that sent it does not know who will react. That lets you add new consequences to an action — an email, a log entry, recalculated statistics — without touching the original code. Symfony itself is built on events.

A kernel event listener

While Symfony handles a request, it dispatches several events. A listener is a class with the #[AsEventListener] attribute:

// src/EventListener/ResponseHeaderListener.php
namespace App\EventListener;
 
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
 
#[AsEventListener]
class ResponseHeaderListener
{
    public function __invoke(ResponseEvent $event): void
    {
        $event->getResponse()->headers->set('X-Frame-Options', 'DENY');
    }
}

Symfony works out which event to listen to from the argument type. The header is now added to every response.

Kernel events

EventWhen it happens
RequestEventThe request arrived, no controller chosen yet
ControllerEventThe controller is chosen but not called
ResponseEventThe response is ready to be sent
ExceptionEventAn exception occurred
TerminateEventThe response has already been sent

Your own event

An event is a plain class with data:

// src/Event/PostPublished.php
namespace App\Event;
 
use App\Entity\Post;
 
class PostPublished
{
    public function __construct(public readonly Post $post) {}
}

The dispatcher sends it:

use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
 
public function publish(Post $post, EntityManagerInterface $em, EventDispatcherInterface $dispatcher): Response
{
    $post->setPublished(true);
    $em->flush();
 
    $dispatcher->dispatch(new PostPublished($post));
 
    return $this->redirectToRoute('blog_show', ['id' => $post->getId()]);
}

Listeners for your event

#[AsEventListener]
class NotifySubscribers
{
    public function __construct(private MailerInterface $mailer) {}
 
    public function __invoke(PostPublished $event): void
    {
        // email the subscribers about $event->post
    }
}

There can be any number of listeners. The controller knows nothing about them.

A subscriber

A subscriber is a class that listens to several events and lists them itself:

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
 
class LocaleSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::REQUEST => ['onRequest', 20],
        ];
    }
 
    public function onRequest(RequestEvent $event): void
    {
        $request = $event->getRequest();
        $request->setLocale($request->getSession()->get('locale', 'en'));
    }
}

The number 20 is the priority: the larger it is, the earlier the method is called.

Doctrine events

An entity can react to its own saving:

#[ORM\Entity]
#[ORM\HasLifecycleCallbacks]
class Post
{
    #[ORM\PrePersist]
    public function setCreatedAtValue(): void
    {
        $this->createdAt = new \DateTimeImmutable();
    }
}

Listing listeners

php bin/console debug:event-dispatcher
php bin/console debug:event-dispatcher kernel.request

Common mistake

Kernel event listeners run on every request. Slow work in them — a call to an external service, a heavy calculation — slows the whole site. Long tasks are sent from a listener to a queue, and the listener itself stays short.

Thanks for reading!

Donate to the site — we work hard for you.