gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Now that we're on Symfony 5.4, our job is simple: hunt down and update all of our deprecated code. As soon as we do that, it will be safe to upgrade to Symfony 6. That's because the only difference between Symfony 5.4 and 6.0 is that all the deprecated code paths are removed.
Fortunately, Symfony is amazing and tells us - via the web debug toolbar - exactly what code is deprecated. But understanding what all of these mean... isn't always easy. So before we even try, we're going to automate as much of this as possible. And we're going to do that with a tool called Rector.
Head to https://github.com/rectorphp/rector. This is an awesome command-line tool with one job: to automate all sorts of upgrades to your code, like upgrading your code from Symfony 5.0 compatible code to Symfony 5.4 compatible code. Or upgrading your code to be PHP 8 compatible. It's a powerful tool... and if you want to learn more about it, they even released a book where you can go deeper... and also help support the project.
All right, let's get this thing installed! Head over to your terminal and run:
composer require rector/rector --dev
Beautiful! In order for rector to work, it needs a config file. And we can bootstrap one by running rector with:
./vendor/bin/rector init
Awesome! That creates the rector.php
file... which we can see over at the root of our project.
Tip
The latest version of Rector will generate config that looks a bit different than this. But don't worry, it still works exactly the same.
Inside of this callback function, our job is to configure which types of upgrades we want to apply. These are called "rules" or sometimes "set lists" or rules. We're going to start with a set of Symfony upgrades.
... lines 1 - 9 | |
return static function (ContainerConfigurator $containerConfigurator): void { | |
// get parameters | |
$parameters = $containerConfigurator->parameters(); | |
$parameters->set(Option::PATHS, [ | |
__DIR__ . '/src' | |
]); | |
// Define what rule sets will be applied | |
$containerConfigurator->import(LevelSetList::UP_TO_PHP_74); | |
// get services (needed for register a single rule) | |
// $services = $containerConfigurator->services(); | |
// register a single rule | |
// $services->set(TypedPropertyRector::class); | |
}; |
If you look back at the documentation, you'll see a link to a Symfony repository where it tells you about a bunch of Symfony "rules" - fancy word for "upgrades" - that they've already prepared! That was nice of them!
Tip
The config on this page will now look different than in the video. But, it still works the same. Copy the latest version into your app.
Below, copy the inside of their callback function... and paste it over what we have.
... lines 1 - 7 | |
use Rector\Symfony\Set\SymfonySetList; | |
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; | |
... line 10 | |
return static function (ContainerConfigurator $containerConfigurator): void { | |
// region Symfony Container | |
$parameters = $containerConfigurator->parameters(); | |
$parameters->set( | |
Option::SYMFONY_CONTAINER_XML_PATH_PARAMETER, | |
__DIR__ . '/var/cache/dev/App_KernelDevDebugContainer.xml' | |
); | |
// endregion | |
$containerConfigurator->import(SymfonySetList::SYMFONY_52); | |
$containerConfigurator->import(SymfonySetList::SYMFONY_CODE_QUALITY); | |
$containerConfigurator->import(SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION); | |
}; |
This points Rector to a cache file that helps it do its job... and most importantly, it tells Rector that we want to upgrade our code to be Symfony 5.2 compatible, as well as upgrade our code to some Symfony code quality standards and "constructor" injection. If you want to know more about what these do, you could follow the constants to check out the code.
But, wait, we don't want to upgrade our code to Symfony 5.2! We want to upgrade it all the way to Symfony 5.4. You might expect me to just put "54" here. And we could do that. But instead, I'm going to use SymfonyLevelSetList::UP_TO_SYMFONY_54
. Oh... it looks like I also need to add a use
statement for SymfonySetList::
. Let me retype that, hit "tab" and... great!
... lines 1 - 7 | |
use Rector\Symfony\Set\SymfonyLevelSetList; | |
use Rector\Symfony\Set\SymfonySetList; | |
... lines 10 - 11 | |
return static function (ContainerConfigurator $containerConfigurator): void { | |
... lines 13 - 20 | |
$containerConfigurator->import(SymfonyLevelSetList::UP_TO_SYMFONY_54); | |
... lines 22 - 23 | |
}; |
Anyways. We need to upgrade our code from 5.0 to 5.1... then 5.1 to 5.2.. and so on up to Symfony 5.4. That's what UP_TO_SYMFONY_54
means: it will include all of the "rules" for upgrading our code to 5.1, 5.2, 5.3 and finally 5.4.
And... that's it! We're ready to run this. But before we do, I'm curious what changes this will make. So let's add all of the changes to git... and commit. Perfect!
To run Rector, say ./vendor/bin/rector process src/
. We could also point this at the config/
or templates/
directories... but the vast majority of the changes it will make apply to our classes in src/
:
vendor/bin/rector process src/
And... it's working! Awesome! Eight files were changed by Rector. Let's scroll to the top. This is cool: it shows you the file that was changed, the actual change and, below, which rules caused that change.
One modificiation it made is UserPasswordEncoderInterface
to UserPasswordHasherInterface
. That's a good change: the old interface is deprecated in favor of the new one. It also changed UsernameNotFoundException
to UserNotFoundException
. Another good, low-level update to some deprecated code.
There was also a change to a class in Kernel
... and a few other similar things. Near the bottom, the Symfony code quality set list added a Response
return type to every controller. That's optional... but nice!
So it didn't make a ton of changes, but it did fix a few deprecations without us needing to do anything.
Though... it's not perfect. One problem is that, sometimes, Rector will mess with your coding style. That's because rector doesn't really understand what your coding style is... and so it doesn't even try. But that's by design and will be easy to fix.
Second, while it did change the interface from UserPasswordEncoderInterface
to UserPasswordHasherInterface
, it inlined the whole class name... instead of adding a use
statement.
... lines 1 - 11 | |
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; | |
... lines 13 - 24 | |
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface | |
{ | |
... lines 27 - 36 | |
public function __construct(SessionInterface $session, EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, \Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface $passwordEncoder) | |
{ | |
... lines 39 - 43 | |
} | |
... lines 45 - 119 | |
} |
And third, it didn't change any variable names. So even though it changed this argument to UserPasswordHasherInterface
, the argument is still called $passwordEncoder
... along with the property. Worse, the UserPasswordHasherInterface
has a different method on it... and it didn't update the code down here to use that new method name.
... lines 1 - 24 | |
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface | |
{ | |
... lines 27 - 34 | |
private $passwordEncoder; | |
... line 36 | |
public function __construct(SessionInterface $session, EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, \Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface $passwordEncoder) | |
{ | |
... lines 39 - 42 | |
$this->passwordEncoder = $passwordEncoder; | |
} | |
... lines 45 - 119 | |
} |
So Rector is a great starting point to catch a bunch of changes. But we're going to need to take what we've found and finish the job. Let's do that next. We'll do part of that by hand... but a lot of it automatically with PHP CS Fixer.
Hey @andremoens!
Sorry for the slow reply! That's not a fun error :/. I did find an issue on this - https://github.com/rectorphp/rector/issues/6698
If I'm reading it correctly, if you upgrade Rector AND use the new config format for Rector (if you upgrade rector and run ./vendor/bin/rector init
you should get this new format), then it might not be an issue anymore... but I can't guarantee that :). The new config format should look something like this - https://github.com/rectorphp/rector-symfony#use-sets
Let me know if that helps!
Cheers!
Hi @weaverryan, you're my hero!
Thanks for your help! It's working now....
I now can continue my journey on upgrading to Symfony 6
Hey
When I execute this commande "./vendor/bin/rector init", the response : "." is not recognized as an internal control !!
I'm on window. Can someone help me? Than's.
Hey Gouchene,
That sounds like a Windows error. I believe it's due to the way you're trying to execute rector
, instead of using ./path/to/file
execute it through PHP php vendor/bin/rector init
Cheers!
you should update reactor config to look like https://github.com/rectorphp/rector-symfony
Hey Thomas,
Unfortunately, we can't change the code that was already recorded on the video. However, we can add notes to the code script and video. We will consider adding a note about it, thanks for pointing into it!
Cheers!
Haha, yea, they updated the config format WHILE I was recording the video - so I actually mention this new format later. But yes, we should add a note in this chapter about it so people aren't surprised when things look different.
Cheers!
// composer.json
{
"require": {
"php": "^8.0.2",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "^3.6", // v3.6.1
"composer/package-versions-deprecated": "^1.11", // 1.11.99.5
"doctrine/annotations": "^1.13", // 1.13.2
"doctrine/dbal": "^3.3", // 3.3.5
"doctrine/doctrine-bundle": "^2.0", // 2.6.2
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
"doctrine/orm": "^2.0", // 2.11.2
"knplabs/knp-markdown-bundle": "^1.8", // 1.10.0
"knplabs/knp-time-bundle": "^1.18", // v1.18.0
"pagerfanta/doctrine-orm-adapter": "^3.6", // v3.6.1
"pagerfanta/twig": "^3.6", // v3.6.1
"sensio/framework-extra-bundle": "^6.0", // v6.2.6
"sentry/sentry-symfony": "^4.0", // 4.2.8
"stof/doctrine-extensions-bundle": "^1.5", // v1.7.0
"symfony/asset": "6.0.*", // v6.0.7
"symfony/console": "6.0.*", // v6.0.7
"symfony/dotenv": "6.0.*", // v6.0.5
"symfony/flex": "^2.1", // v2.1.7
"symfony/form": "6.0.*", // v6.0.7
"symfony/framework-bundle": "6.0.*", // v6.0.7
"symfony/mailer": "6.0.*", // v6.0.5
"symfony/monolog-bundle": "^3.0", // v3.7.1
"symfony/property-access": "6.0.*", // v6.0.7
"symfony/property-info": "6.0.*", // v6.0.7
"symfony/proxy-manager-bridge": "6.0.*", // v6.0.6
"symfony/routing": "6.0.*", // v6.0.5
"symfony/runtime": "6.0.*", // v6.0.7
"symfony/security-bundle": "6.0.*", // v6.0.5
"symfony/serializer": "6.0.*", // v6.0.7
"symfony/stopwatch": "6.0.*", // v6.0.5
"symfony/twig-bundle": "6.0.*", // v6.0.3
"symfony/ux-chartjs": "^2.0", // v2.1.0
"symfony/validator": "6.0.*", // v6.0.7
"symfony/webpack-encore-bundle": "^1.7", // v1.14.0
"symfony/yaml": "6.0.*", // v6.0.3
"symfonycasts/verify-email-bundle": "^1.7", // v1.10.0
"twig/extra-bundle": "^2.12|^3.0", // v3.3.8
"twig/string-extra": "^3.3", // v3.3.5
"twig/twig": "^2.12|^3.0" // v3.3.10
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.1
"phpunit/phpunit": "^9.5", // 9.5.20
"rector/rector": "^0.12.17", // 0.12.20
"symfony/debug-bundle": "6.0.*", // v6.0.3
"symfony/maker-bundle": "^1.15", // v1.38.0
"symfony/var-dumper": "6.0.*", // v6.0.6
"symfony/web-profiler-bundle": "6.0.*", // v6.0.6
"zenstruck/foundry": "^1.16" // v1.18.0
}
}
Hi, when I try to run
php vendor/bin/rector process src/
I get this error:
Has anyone a clue how to fix this?