Updated with Symfony 4.3 simple dispatching, PHP 7.4 syntax and ::class
-based event names.
Have you ever used Symfony Event Dispatcher? No?
This post is an introduction to Event Dispatcher, how to use it, and in the end, you'll be able to cover 90 % use cases you'll ever need.
This way, you can extend 3rd party packages without rewriting them. And also allow other users to reach your code without even touching it.
Not sure how that looks? You will - at the end of this article.
This is the brain. It stores all subscribers and calls events when you need to.
This is the name of a place. When something has happened in the application: order is sent, or user is deleted.
This is the action that happens when we come to a specific event. When an order is sent (= Event), send me a confirmation SMS (= Event Subscriber). And check that all the ordered products are on stock.
1 event can invoke MORE Event Subscribers.
composer require symfony/event-dispatcher
// index.php
require_once __DIR__ . '/vendor/autoload.php';
// 1. create the Dispatcher
$eventDispatcher = new Symfony\Component\EventDispatcher\EventDispatcher;
// 2. some event happened, we dispatch it
$eventDispatcher->dispatch('youtube.newVideoPublished'); // oh: event is just a string
Try it:
php index.php
Wow! Nothing happened...
That's ok because there is no Subscriber. So let's...
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class NotifyMeOnVideoPublishedEventSubscriber implements EventSubscriberInterface
{
public bool $isUserNotified = false;
public static function getSubscribedEvents(): array
{
// in format ['event name' => 'public function name that will be called']
return ['youtube.newVideoPublished' => 'notifyUserAboutVideo'];
}
public function notifyUserAboutVideo()
{
// some logic to send notification
$this->isUserNotified = true;
}
}
Let the Dispatcher know about the Subscriber.
$eventDispatcher = new Symfony\Component\EventDispatcher\EventDispatcher;
$eventSubscriber = new NotifyMeOnVideoPublishedEventSubscriber;
$eventDispatcher->addSubscriber($eventSubscriber);
// nothing happened, default value
var_dump($eventSubscriber->isUserNotified);
// false
// this calls our Subscriber
$eventDispatcher->dispatch('youtube.newVideoPublished');
// now it's changed
var_dump($eventSubscriber->isUserNotified);
// true
Run the code again from command line:
$ php index.php
int(0)
int(1)
And now you understand EventDispatcher. At least in 90 % use cases.
Still on? Let's get advanced.
What if we need to get the name of the Youtuber into the Subscriber?
The Event objects are basically Value Objects. Pass a value in the constructor and get it with getter.
use Symfony\Component\EventDispatcher\Event;
final class YoutuberNameEvent extends Event
{
private string $youtuberName;
public function __construct(string $youtuberName)
{
$this->youtuberName = $youtuberName;
}
public function getYoutuberName(): string
{
return $this->youtuberName;
}
}
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class NotifyMeOnVideoPublishedEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return ['youtube.newVideoPublished' => 'notifyUserAboutVideo'];
}
// Event Object is passed as method argument
public function notifyUserAboutVideo(YoutuberNameEvent $youtuberNameEvent)
{
var_dump($youtuberNameEvent->getYoutuberName());
}
}
$youtuberNameEvent = new YoutuberNameEvent('Jirka Král');
$eventDispatcher->dispatch($youtuberNameEvent);
And here is the result:
$ php index.php
string('Jirka Král')
You can now:
Still hungry for knowledge? Check Symfony documentation then.
But remember: practice is the best teacher.
Happy coding!
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors.
I'd really appreciate it!