If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWe upgraded our app to Symfony 4.4 and updated all of its Symfony recipes. We rock!
And now, our path to Symfony 5 is clear: we need to find and fix all deprecated code that we're using. As soon as we've done that, it will be safe to tweak our composer.json
file, go to 5.0 and celebrate with cheesecake.
So how do we figure out what deprecated functions, config options or classes we might be using? There are two main ways. The best is down here on the web debug toolbar. This literally tells us that during this page load, we called 49 deprecated things. We'll look at these in a minute and start to eliminate them.
But even once you get this number down to zero... you can't really be sure that you've fixed all your deprecated code. Like, what if you're using a deprecated function only on some obscure AJAX call... and you forgot to check that.
That's why Symfony has a second way to find this stuff: a deprecations log file on production. Open up config/packages/prod/monolog.yaml
. This has two handlers - deprecation
and deprecation_filter
- that, together, add a log entry each time your app uses deprecated code on production:
monolog: | |
handlers: | |
... lines 3 - 15 | |
deprecation: | |
type: stream | |
path: "%kernel.logs_dir%/%kernel.environment%.deprecations.log" | |
deprecation_filter: | |
type: filter | |
handler: deprecation | |
max_level: info | |
channels: ["php"] |
So once you think you've fixed all your deprecated code, deploy it to production, wait a few hours or days, and check the log to make sure it doesn't contain anything new. Then you'll know it's safe to upgrade.
By the way, Symfony Insight has a special feature to identify and fix deprecation warnings. So if you want some extra help... or an "easy" button, give it a try.
Let's start crushing our deprecations. I'll refresh the homepage and open the deprecations link in a new window. Fixing deprecated code can be... well... an adventure! Because you might need to change a class name, method name, remove a bundle, upgrade a 3rd party library, tweak some config or do a secret handshake. Every deprecation is a little different.
But the first one is simple: it says that the WebServerBundle
is deprecated since Symfony 4.4.
At the beginning of this tutorial, we started a local web server by running:
symfony serve
This symfony
thing is the Symfony binary: a nice development tool that, in addition to other tricks, is able to start a development server. Before this existed, we used to start a local web server by running:
php bin/console server:run
A console command that comes from WebServerBundle. That's now deprecated... because the Symfony binary is shinier and more powerful.
So this deprecation is easy to fix. Inside composer.json
, find the symfony/web-server-bundle
line:
{ | |
... lines 2 - 3 | |
"require": { | |
... lines 5 - 37 | |
"symfony/web-server-bundle": "4.4.*", | |
... lines 39 - 43 | |
}, | |
... lines 45 - 102 | |
} |
Copy it, go to your terminal and remove it:
composer remove symfony/web-server-bundle
Oh! It's over-achieving! In addition to removing the bundle, it's upgrading a few related packages to the latest bug fix version. This also - importantly - unconfigured the recipe: it removed the bundle from bundles.php
and deleted a line from .gitignore
that we don't need anymore.
Hey! One deprecation is gone! Let's go find another one! Hmm, the second is something about:
Calling the
EventDispatcher::dispatch()
method with the event name as the first argument is deprecated since Symfony 4.3.
One of the trickiest things about fixing deprecations is that you need to find out where this is coming from. To make things even more, let's say, "interesting", pretty often, a deprecation won't be triggered directly by our code, but by a third-party bundle that were using.
If you show the trace, it gives info about where this is coming from. It's not super obvious... but if you look closely up here, it mentions LiipImagineBundle.
Ok, so LiipImagineBundle appears to be calling some deprecated code, which means that our current version will definitely not be compatible with Symfony 5. Fortunately, there's one clear way to fix deprecated code that's called from a vendor library: upgrade it!
Let's do this in the laziest way possible. Inside composer.json
, find that package:
{ | |
... lines 2 - 3 | |
"require": { | |
... lines 5 - 15 | |
"liip/imagine-bundle": "^2.1", | |
... lines 17 - 43 | |
}, | |
... lines 45 - 102 | |
} |
Copy its name, and run:
composer update liip/imagine-bundle
What we're hoping is that this deprecation has been fixed and - ideally - that we only need to upgrade a "minor" version to get that fix, like maybe upgrading from 2.1 to 2.2 or 2.3.
And actually... yea! It did upgrade from 2.1 to 2.2. Did that fix the deprecation? I have no idea! Let's find out! Close the profiler tab and refresh the homepage. Good sign: the deprecations went from 48 to 29. I'll open the deprecations in a new tab and... awesome: it does look like that specific deprecation is gone.
Let's keep going! We're going to focus on these TreeBuilder::root()
deprecations next. These are also coming from third-party libraries. But upgrading them will be a bit more complex.
Hey Holger,
Thanks for sharing this link to the docs that might be useful for others! :)
Cheers!
I don't have deprecation and deprecation_filter handlers in monolog, I've updated all the packages and recipes (I have a deprecations.yaml with some commented code that works only on SF5.1... But I'm on 4.4).
I've tried to add them manually but nothing is being logged, at least in dev... how can I make the deprecations logging working?
Apparently that was because they are caught by the toolbar... If I switch to prod, the deprecation exceptions are logged
Hey the_nuts,
Yes, as you can see that config is for prod, so it will work only for prod env. If you want - you may enable the same for dev env, but usually devs enable it only for prod, deploy the project, then wait some time when real users are using the website, then pull the log file from production, see what deprecations were triggered and fix them. if you have a really complex website - it's almost impossible to test everything manually to trigger all the possible depredations, that's where real users helps :)
Cheers!
// 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
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"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
"doctrine/persistence": "^1.3.7", // 1.3.8
"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.17.6
"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
}
}
@Removing deprecated WebServerBundle! For those (like me) who worked with this for a longer time, it will spare some time to know how to install the new local webserver (see https://symfony.com/doc/cur.... For all further steps of this tutorial this server is hardly needed :-)