Events, Events & Events!

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.

Hi friends! Ok: so you already know how to use Symfony... maybe you... use it every day. Heck, I love it so much, I've been known to use it on vacation! And now, you're ready to go deeper - to find out how Symfony really works under-the-hood. If this is you, welcome! We're in for a wild ride.

In this first deep dive tutorial, we're going to the heart of what happens during the request-response process in Symfony. It all centers around a class called HttpKernel, which is an incredible class. This one class is used as the heart of Symfony and Drupal... as well as a bunch of other projects, for example, phpBB - the famous forum system.

So how can one class be the heart of technologies that are seemingly so different? That's what we're going to find out.

Project Setup

As always, if you truly want to impress your friends with your deep knowledge of Symfony, download the course code and code along with me. After you unzip the file, you'll find a start/ directory with the same code that you see here. Follow the README.md file for all the thrilling setup instructions.

The last step will be to leverage the Symfony binary to start a web server with symfony serve. I'm actually going to pass -d so it runs in the background as a daemon:

symfony serve -d

Now, spin back over to your browser and head to https://localhost:8000 to find: The SpaceBar. Some of you might recognize this from our Symfony 4 tutorials. Well, I've upgraded it to Symfony 5 and it will be our perfect guinea pig for diving deep into Symfony.

Request -> Controller -> Response. But what else?

Ok: we know that everything starts with a request: a request comes into our server, it's handled by our application, yadda, yadda, yadda, a response comes out... and profit! The goal of this tutorial is simple: find out what really happens in between.

For the homepage, let's find its controller: src/Controller/ArticleController.php. Here it is: homepage(), with the route above it.

The two things that we know happen between the start of the request and the end of the response, are that the route is matched and then something calls our controller... probably Fabien personally calls it... I don't know. And then our controller always, well usually, returns a response. That's what $this->render() returns.

What I want to know is: who executes the routing and who ultimately calls my controller? I want to see the code that does that!

Holder of Secrets: The Profiler Performance Tab

To start this journey, go back to your browser and, on the web debug toolbar on the bottom, right click on the milliseconds link and open it in a new tab to jump into the "Performance" section of the profiler.

This screen is awesome. It's meant to show you where your site might be slow, but its real superpower is that it can show you everything that's happening inside of Symfony. The trick is to change this "threshold" input box from 1 milliseconds down to 0... so that it doesn't hide anything.

Simply gorgeous. This is the request-response process. You can see - kind of in the middle here - is our controller: it took 36 milliseconds to execute. You can see the Twig templates being executed below it, and even little Doctrine queries happening along the way.

The biggest thing I want you to notice is that most of the other lines - both before and after the controller - contain the word Listener, or sometimes Subscriber, which is basically another word for "listener".

Because, at a high level, here's what happens inside Symfony: it boots, triggers some events, executes your controller, then dispatches some other events.

To get an even better view of these events, click... the Events tab! This shows all the events that were dispatched during this request. So, apparently there's an event called kernel.request: that was the first event dispatched. And here are all of the listeners - so all the "functions" - that were called when that event was triggered.

Then there's another event called kernel.controller... and many more. You can even see listeners for events that were not triggered during this request.

So... let's start messing with stuff! Next, let's create our own event listener and execute code before our controller is called.

Leave a comment!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.3.0",
        "ext-iconv": "*",
        "antishov/doctrine-extensions-bundle": "^1.4", // v1.4.2
        "aws/aws-sdk-php": "^3.87", // 3.133.20
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/doctrine-bundle": "^2.0", // 2.0.7
        "doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // 2.1.2
        "doctrine/orm": "^2.5.11", // v2.7.1
        "easycorp/easy-log-handler": "^1.0", // v1.0.9
        "http-interop/http-factory-guzzle": "^1.0", // 1.0.0
        "knplabs/knp-markdown-bundle": "^1.7", // 1.8.1
        "knplabs/knp-paginator-bundle": "^5.0", // v5.1.1
        "knplabs/knp-snappy-bundle": "^1.6", // v1.7.0
        "knplabs/knp-time-bundle": "^1.8", // v1.11.0
        "league/flysystem-aws-s3-v3": "^1.0", // 1.0.24
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "league/html-to-markdown": "^4.8", // 4.9.1
        "liip/imagine-bundle": "^2.1", // 2.3.0
        "nexylan/slack-bundle": "^2.1", // v2.2.2
        "oneup/flysystem-bundle": "^3.0", // 3.4.0
        "php-http/guzzle6-adapter": "^2.0", // v2.0.1
        "sensio/framework-extra-bundle": "^5.1", // v5.5.3
        "symfony/asset": "5.0.*", // v5.0.4
        "symfony/console": "5.0.*", // v5.0.4
        "symfony/dotenv": "5.0.*", // v5.0.4
        "symfony/flex": "^1.9", // v1.9.10
        "symfony/form": "5.0.*", // v5.0.4
        "symfony/framework-bundle": "5.0.*", // v5.0.4
        "symfony/mailer": "5.0.*", // v5.0.4
        "symfony/messenger": "5.0.*", // v5.0.4
        "symfony/monolog-bundle": "^3.5", // v3.5.0
        "symfony/security-bundle": "5.0.*", // v5.0.4
        "symfony/sendgrid-mailer": "5.0.*", // v5.0.4
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "5.0.*", // v5.0.4
        "symfony/twig-pack": "^1.0", // v1.0.0
        "symfony/validator": "5.0.*", // v5.0.4
        "symfony/webpack-encore-bundle": "^1.4", // v1.7.3
        "symfony/yaml": "5.0.*", // v5.0.4
        "twig/cssinliner-extra": "^2.12", // v2.12.5
        "twig/extensions": "^1.5", // v1.5.4
        "twig/inky-extra": "^2.12" // v2.12.5
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.3.0
        "fzaninotto/faker": "^1.7", // v1.9.1
        "symfony/browser-kit": "5.0.*", // v5.0.4
        "symfony/debug-bundle": "5.0.*", // v5.0.4
        "symfony/maker-bundle": "^1.0", // v1.14.3
        "symfony/phpunit-bridge": "5.0.*", // v5.0.4
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "5.0.*" // v5.0.4
    }
}