Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Messenger vs EventDispatcher

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

If you've ever create an event listener or event subscriber in Symfony, you're creating a "listener" for an event that's dispatched through a service called the "event dispatcher". The purpose of the event dispatcher is to allow one piece of code to "notify" the app that something happened and for anyone else to "listen" to that event and run some code.

Which... huh... is the exact same purpose of dispatching an event into Messenger. What the heck? If I want to dispatch an event in my code, should I use the EventDispatcher or Messenger? Are animated image files pronounced "jif" or "gif"? Should toilet paper hang "over" the roll or "under"? Ahh!

Messenger can be Async

First, there is a practical difference between dispatching an event to the EventDispatcher versus Messenger: Messenger allows your handlers to be called asynchronously, whereas listeners to events from the EventDispatcher are always synchronous.

EventDispatcher communicates back

And this leads to a nice rule of thumb. Whenever you dispatch an event, if you want listeners to that event to be able to communicate back to you, so you can then do something based on their feedback, use the EventDispatcher. But if you simply want to say "this thing happened" and you don't need any feedback from possible listeners or handlers, use Messenger.

For example, in AddPonkaToImageHandler, suppose we wanted to dispatch an event here so that other parts of the system could tell us exactly which Ponka image should be added to this photo. In that case, we need those listeners to be able to communicate back to us. To do that we would create an Event class that holds the ImagePost object and has a setter on it that listeners can call - maybe setPonkaImageToUse(). We would then use the EventDispatcher and dispatch the message before actually adding Ponka to the image. Once all the listeners were called, we could see if any of them called that setPonkaImageToUse() method.

But what if we simply wanted to say:

Hey! We just added Ponka to an image!

... add didn't need any information back from possible handlers? In that case we would create a similar event class, leave off the setPonkaImageToUse() method and dispatch it with Messenger. Messenger is perfect if you don't need any info back from your handlers because... those handlers might end up being called asynchronously!

If it's still not clear to you, just use whichever you want. Why? Because if you end up wanting your code to run asynchronously, you'll end up choosing Messenger. And if you want your listeners to be able to communicate back to the code that dispatches the messages, you'll use EventDispatcher. Otherwise, either will work.

Next, let's use some service configuration tricks to tighten up how we've organized our commands, command handlers, events and event handlers.

Leave a comment!

2
Login or Register to join the conversation
erop Avatar

Ryan, your explanation about difference between Messenger and EventDispatcher is pretty clear. But we could also use Messenger for synchronous message (command/query/event) processing. So what do you thing of using EventDispatcher only for handling kernel's lifecycle-connected events while using Messenger specifically for domain events (NewProductAdded, etc.) both in a sync (i.e. not listed in framework.messenger.routing) and async ways ?

Reply

Hey erop!

That's basically how I think about it :). Or, to say it a slightly different way, I use EventDispatcher for adding "hooks" to my code (which I don't do very often - but that's a matter of taste - it's something much more common for re-usable libraries) and Messenger for (as you said) my domain events/messages.

But, this gets very fuzzy in some cases. Like, suppose I want to dispatch an "event" after a user register. Should I use event dispatcher because I see this as a "hook" for other parts of my code to do something? Or should I use Messenger... because this is a domain event. I could really see either... which also means that, in my opinion (which tends to be pretty relaxed), either solution would be "ok" :).

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial is built with Symfony 4.3, but will work well on Symfony 4.4 or 5.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/annotations": "^1.0", // v1.8.0
        "doctrine/doctrine-bundle": "^1.6.10", // 1.11.2
        "doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // v2.0.0
        "doctrine/orm": "^2.5.11", // v2.6.3
        "intervention/image": "^2.4", // 2.4.2
        "league/flysystem-bundle": "^1.0", // 1.1.0
        "phpdocumentor/reflection-docblock": "^3.0|^4.0", // 4.3.1
        "sensio/framework-extra-bundle": "^5.3", // v5.3.1
        "symfony/console": "4.3.*", // v4.3.2
        "symfony/dotenv": "4.3.*", // v4.3.2
        "symfony/flex": "^1.9", // v1.18.7
        "symfony/framework-bundle": "4.3.*", // v4.3.2
        "symfony/messenger": "4.3.*", // v4.3.4
        "symfony/property-access": "4.3.*", // v4.3.2
        "symfony/property-info": "4.3.*", // v4.3.2
        "symfony/serializer": "4.3.*", // v4.3.2
        "symfony/validator": "4.3.*", // v4.3.2
        "symfony/webpack-encore-bundle": "^1.5", // v1.6.2
        "symfony/yaml": "4.3.*" // v4.3.2
    },
    "require-dev": {
        "easycorp/easy-log-handler": "^1.0.7", // v1.0.7
        "symfony/debug-bundle": "4.3.*", // v4.3.2
        "symfony/maker-bundle": "^1.0", // v1.12.0
        "symfony/monolog-bundle": "^3.0", // v3.4.0
        "symfony/stopwatch": "4.3.*", // v4.3.2
        "symfony/twig-bundle": "4.3.*", // v4.3.2
        "symfony/var-dumper": "4.3.*", // v4.3.2
        "symfony/web-profiler-bundle": "4.3.*" // v4.3.2
    }
}
userVoice