Flex, Versioning & extra.symfony.require

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! Today we get to explore the, strange, mysterious, shiny world of Symfony 5. Duh, duh, duh!

Well... first we'll cover how to upgrade to Symfony 5 - which is its own fancy process - and then we'll chat about some of my favorite features.

Symfony 5: So What's New?

As far as upgrading goes, Symfony 5 doesn't make any huge changes: there isn't a totally new directory structure or some earth-shattering new paradigm like Symfony Flex and the recipe system. That's really because Symfony is in a great place right now.

So if you were looking forward to countless hours of work and huge changes to your app in order to upgrade it. Well... you're going to be disappointed. But if you're hoping for a smooth update process - and to learn about what's changed since Symfony 4.0 was released - welcome! After we're done, we should have some time left over to go eat cake.

The Release Cycle

But the fact that nothing crazy changed does not mean that nothing has been happening. Really... phew! The last 2 years since Symfony 4 was released have been huge... with the introduction of the Messenger component, Mailer and many, many other things.

Symfony releases a new "minor" version every 6 months months: 4.0 in November 2017, 4.1 in May 2018, 4.2 in November 2018, 4.3 in May 2019 and 4.4 in November 2019. It's the most boring release cycle ever... and I love it! symfony.com even has a roadmap page where you can check the timing of any past or future versions. Each of these minor versions comes packed with new features.

Will there be a Symfony 4.5? Nope! The .4 - like 3.4 or 4.4 - is always the last one. In fact, on the same day that a .4 minor is released, Symfony also releases the next major version. Yep, Symfony 4.4 and 5.0 were released on the same day. The reason deals with how upgrades work in Symfony. But more on that later.

Project Setup

So let's get to work! To composer update your upgrading skills - sorry... I couldn't help it - you should definitely download the course code from this page and code along with me. When you unzip the file, you'll find a start/ directory that holds the same code you see here.

This is a Symfony 4.3 project... but the app originally started on 4.0. So it has a decent amount of old... "stuff" that we'll need to upgrade. Open the README.md file for all the setup instructions. The last step will be to find a terminal, move into the project and use the Symfony binary to start a local web server:

symfony serve

That starts the server at https://127.0.0.1:8000. Find your browser and go there. Say hello to an application that will be very familiar to many of you: The SpaceBar: an alien news site that we've been working on since Symfony 4 was released two years ago.

What Does Upgrading Mean?

So, I have... kind of a silly question: what does it mean to upgrade Symfony? Because Symfony isn't just one big library: it's a huge number of smaller components.

Go to the project and open composer.json. Our app has grown pretty big: it has a lot of dependencies... and about half of these start with symfony/:

104 lines composer.json
{
... lines 2 - 3
"require": {
... lines 5 - 20
"symfony/asset": "^4.0",
"symfony/console": "^4.0",
"symfony/flex": "^1.0",
"symfony/form": "^4.0",
"symfony/framework-bundle": "^4.0",
"symfony/mailer": "4.3.*",
"symfony/messenger": "4.3.*",
"symfony/orm-pack": "^1.0",
"symfony/security-bundle": "^4.0",
"symfony/sendgrid-mailer": "4.3.*",
"symfony/serializer-pack": "^1.0",
"symfony/twig-bundle": "^4.0",
"symfony/twig-pack": "^1.0",
"symfony/validator": "^4.0",
"symfony/web-server-bundle": "^4.0",
"symfony/webpack-encore-bundle": "^1.4",
"symfony/yaml": "^4.0",
... lines 38 - 40
},
"require-dev": {
... lines 43 - 45
"symfony/browser-kit": "4.3.*",
"symfony/debug-bundle": "^3.3|^4.0",
"symfony/dotenv": "^4.0",
"symfony/maker-bundle": "^1.0",
"symfony/monolog-bundle": "^3.0",
"symfony/phpunit-bridge": "^3.3|^4.0",
"symfony/profiler-pack": "^1.0",
"symfony/var-dumper": "^3.3|^4.0"
},
... lines 55 - 102
}

When we talk about upgrading Symfony, we're really talking about upgrading all of the libraries that start with symfony/. Well, not all of the libraries: a few packages - like symfony/webpack-encore-bundle - are not part of the main Symfony code and follow their own versioning strategy:

104 lines composer.json
{
... lines 2 - 3
"require": {
... lines 5 - 35
"symfony/webpack-encore-bundle": "^1.4",
... lines 37 - 40
},
... lines 42 - 102
}

You can upgrade those whenever you want.

But the vast majority of the symfony/ packages are part of the main Symfony library and we usually upgrade them all at the same time. You don't have to, but it keeps life simpler.

Removing symfony/lts

Before we begin, if you started your project on Symfony 4.0, then inside of your composer.json file, you might have a package called symfony/lts. If you do, remove it with composer remove symfony/lts. I already removed it from this app.

symfony/lts was a, sort of "fake" package that helped you keep all of your many symfony packages at the same version. But this package was deprecated in favor of something different.

extra.symfony.require

Look inside your composer.json file for a key called extra and make sure it has a symfony key below it and another called require:

104 lines composer.json
{
... lines 2 - 95
"extra": {
"symfony": {
"id": "01C1TW989CK77ZA7B2H4HC9WAG",
"allow-contrib": true,
"require": "4.3.*"
}
}
}

This is a special piece of config that's used by Symfony Flex. Remember, Flex is the Composer plugin that give us the recipe system and a few other goodies. Flex reads extra.symfony.require and does two things. First, behind the scenes, it tells Composer that all the symfony/ repositories should be locked at version 4.3.*.

Scroll back up to the require section. See how symfony/form is set to ^4.0?

104 lines composer.json
{
... lines 2 - 3
"require": {
... lines 5 - 23
"symfony/form": "^4.0",
... lines 25 - 40
},
... lines 42 - 102
}

In Composer land, that format effectively means 4.*. If we ran composer update, it would upgrade it to the latest "4" version. So, 4.4.

But thanks to Symfony Flex and the extra.symfony.require 4.3.* config, symfony/form would actually only be updated to the latest 4.3 version.

The second thing this config does - and this is the true reason it exists - is optimize performance. When you run composer update or composer require, Flex filters out all versions of symfony/ packages that don't match 4.3.*. That actually makes Composer much faster as it has less versions to think about. If you've ever wondered why you used to run out of memory with Composer a few years ago... but don't now... this is why.

Let's see this 4.3.* require thing in action. Spin over to the terminal, open up a new tab and run:

composer update "symfony/*"

If we did not have Symfony Flex installed, we would expect that symfony/form would be updated to 4.4. But... yea! It says:

Restricting packages listed in symfony/symfony to 4.3.*

And... when we find symfony/form, it did upgrade it, but only to the latest 4.3 release - not 4.4. You can also see that it updated a few other libraries that start with symfony/* but that aren't part of the main Symfony code. Flex has no effect on these: they upgrade normally, and that's fine.

So upgrading the "patch" version of Symfony to get bug fixes and security releases is just as simple as running composer update "symfony/*". But to upgrade to the next minor version, we need to change the extra.symfony.require key. Except... there will be one other trick. Let's see what it is next.

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.110.11
        "doctrine/doctrine-bundle": "^2.0", // 2.0.6
        "doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // 2.1.2
        "doctrine/orm": "^2.5.11", // v2.7.2
        "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.0.0
        "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.23
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "league/html-to-markdown": "^4.8", // 4.8.2
        "liip/imagine-bundle": "^2.1", // 2.3.0
        "nexylan/slack-bundle": "^2.1", // v2.2.1
        "oneup/flysystem-bundle": "^3.0", // 3.3.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.2
        "symfony/console": "5.0.*", // v5.0.2
        "symfony/dotenv": "5.0.*", // v5.0.2
        "symfony/flex": "^1.0", // v1.6.2
        "symfony/form": "5.0.*", // v5.0.2
        "symfony/framework-bundle": "5.0.*", // v5.0.2
        "symfony/mailer": "5.0.*", // v5.0.2
        "symfony/messenger": "5.0.*", // v5.0.2
        "symfony/monolog-bundle": "^3.5", // v3.5.0
        "symfony/security-bundle": "5.0.*", // v5.0.2
        "symfony/sendgrid-mailer": "5.0.*", // v5.0.2
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "5.0.*", // v5.0.2
        "symfony/twig-pack": "^1.0", // v1.0.0
        "symfony/validator": "5.0.*", // v5.0.2
        "symfony/webpack-encore-bundle": "^1.4", // v1.7.2
        "symfony/yaml": "5.0.*", // v5.0.2
        "twig/cssinliner-extra": "^2.12", // v2.12.0
        "twig/extensions": "^1.5", // v1.5.4
        "twig/inky-extra": "^2.12" // v2.12.0
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.3.0
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/browser-kit": "5.0.*", // v5.0.2
        "symfony/debug-bundle": "5.0.*", // v5.0.2
        "symfony/maker-bundle": "^1.0", // v1.14.3
        "symfony/phpunit-bridge": "5.0.*", // v5.0.2
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "5.0.*" // v5.0.2
    }
}