Installing Messenger

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Yo Friends! It's Symfony Messenger time!!! So, what is Symfony Messenger? It's a tool that allows you to... um... send messages... Wait... that made no sense.

Um, What is Messenger?

Let's try again. Messenger is a tool that enables a really cool design pattern where you write "messages" and then other code that does something when that message is sent. If you've heard of CQRS - Command Query Responsibility Segregation - Messenger is a tool that enables that design pattern.

That's all great... and we're going to learn plenty about it. But there's a good chance you're watching this because you want to learn about something else that Messenger does: it allows you to run code asynchronously with queues & workers! OooooOOoo. That's the real fanciness of Messenger.

Oh, and I have two more sales pitches. First, Symfony 4.3 has a ton of new features that really make Messenger shine. And second, using Messenger is an absolute delight. So... let's do this!

Project Setup

If you want to become a command-bus-queue-processing-worker-middleware-envelope... and other buzzwords... Messenger master, warm up your coffee and code along with me. Download the course code from this page. When you unzip it, you'll find a start/ directory inside with the same code that you see here. Open up the README.md file for all the details about how to get the project running and a totally-unrelated, yet, lovely poem called "The Messenger".

The last setup step will be to find a terminal and use the Symfony binary to start a web-server at https://localhost:8000:

symfony serve

Ok, let's go check that out in our browser. Say hello to our newest SymfonyCasts creation: Ponka-fy Me. If you didn't already know, Ponka, by day, is one of the lead developers here at SymfonyCasts. By night... she is Victor's cat. Actually... due to her frequent nap schedule... she doesn't really do any coding... now that I think about it.

Ponka-fy Me

Anyways, we've been noticing a problem where we go on vacation, but Ponka can't come... so when we return, none of our photos have Ponka in them! Ponka-fy Me solves that: let's select a vacation photo... it uploads... and... yea! Check it out! Ponka seamlessly joined us in our vacation photo!

Behind the scenes, this app uses a Vue.js frontend... which isn't important for what we'll be learning. What is important to know is that this uploads to an API endpoint which stores the photo and then combines two images together. That's a pretty heavy thing to do on a web request... which is why, if you watch closely, it's kinda slow: it will finish uploading... wait... and, yep, then load the new image on the right.

Let's look at the API endpoint so you can get an idea of how this works: it lives at src/Controller/ImagePostController.php. Look for create() this is the upload API endpoint: it grabs the file, validates it, uses another service to store that file - that's the uploadImage() method, creates a new ImagePost entity, saves it to the database with Doctrine and then, down here, we have some code to add Ponka to our photo. That ponkafy() method does the really heavy-lifting: it takes the two images, splices them together and... to make it extra dramatic and slow-looking for the purposes of this tutorial, it takes a 2 second break for tea.

Mostly... all of this code is meant to be pretty boring. Sure, I've organized things into a few services... that's nice - but it's all very traditional. It's a perfect test case for Messenger!

Installing Messenger

So... let's get it installed! Find your terminal, open a new tab and run:

composer require messenger

When that finishes... we get a "message"... from Messenger! Well, from its recipe. This is great - but we'll talk about all this stuff along the way.

In addition to installing the Messenger component, its Flex recipe made two changes to our app. First, it modified .env. Let's see... it added this "transport" config. This relates to queuing messages - a lot more on that later.

36 lines .env
... lines 1 - 29
###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=doctrine://default
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
###

It also added a new messenger.yaml file, which... if you open that up... is perfectly... boring! It has transports and routing keys - again, things that relate to queuing - but it's all empty and doesn't do anything yet.

framework:
messenger:
# Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
# failure_transport: failed
transports:
# https://symfony.com/doc/current/messenger.html#transports
# async: '%env(MESSENGER_TRANSPORT_DSN)%'
# failed: 'doctrine://default?queue_name=failed'
# sync: 'sync://'
routing:
# Route your messages to the transports
# 'App\Message\YourMessage': async

So... what did installing the Messenger component give us... other than some new PHP classes inside the vendor/ directory? It gave us one new important service. Back at your terminal run:

php bin/console debug:autowiring mess

There it is! We have a new service that we can use with this MessageBusInterface type-hint. Um... what does it do? I don't know! But let's find out next! Along with learning about message classes and message handlers.

Leave a comment!

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": "*",
        "intervention/image": "^2.4", // 2.4.2
        "league/flysystem-bundle": "^1.0", // 1.1.0
        "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.1", // v1.4.4
        "symfony/framework-bundle": "4.3.*", // v4.3.2
        "symfony/messenger": "4.3.*", // v4.3.4
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/serializer-pack": "^1.0", // v1.0.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": {
        "symfony/debug-pack": "^1.0", // v1.0.7
        "symfony/maker-bundle": "^1.0", // v1.12.0
        "symfony/test-pack": "^1.0" // v1.0.6
    }
}