Chapters
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Ahora que estamos en Symfony 5.4, nuestro trabajo es sencillo: buscar y actualizar todo nuestro código obsoleto. Tan pronto como hagamos eso, será seguro actualizar a Symfony 6. Eso es porque la única diferencia entre Symfony 5.4 y 6.0 es que todas las rutas de código obsoleto se eliminan.
Afortunadamente, Symfony es increíble y nos dice -a través de la barra de herramientas de depuración web- exactamente qué código está obsoleto. Pero entender lo que significa todo esto... no siempre es fácil. Así que antes de intentarlo, vamos a automatizar todo lo posible, y lo haremos con una herramienta llamada Rector.
Instalación de Rector
Dirígete a https://github.com/rectorphp/rector. Se trata de una impresionante herramienta de línea de comandos con un único trabajo: automatizar todo tipo de actualizaciones de tu código, como actualizar tu código de compatible con Symfony 5.0 a compatible con Symfony 5.4. O actualizar tu código para que sea compatible con PHP 8. Es una herramienta poderosa... y si quieres aprender más sobre ella, incluso han publicado un libro en el que puedes profundizar... y también ayudar a apoyar el proyecto.
Muy bien, ¡vamos a instalar esta cosa! Dirígete a tu terminal y ejecuta:
composer require rector/rector --dev
¡Hermoso! Para que rector funcione, necesita un archivo de configuración. Y podemos arrancar uno ejecutando rector con:
./vendor/bin/rector init
¡Impresionante! Eso crea el archivo rector.php
... que podemos ver en la raíz de nuestro proyecto. Dentro de esta función de devolución de llamada, nuestro trabajo consiste en configurar qué tipos de actualizaciones queremos aplicar. Esto se llama "reglas" o a veces "listas de conjuntos" o reglas. Vamos a empezar con un conjunto de actualizaciones de Symfony.
Configurar Rector para la actualización de Symfony
¡Si echas un vistazo a la documentación, verás un enlace a un repositorio de Symfony donde te habla de un montón de "reglas" de Symfony -palabra elegante para "actualizaciones"- que ya han preparado! ¡Muy amable por su parte!
A continuación, copia el interior de su función callback... y pégalo sobre lo que tenemos. Esto apunta a Rector a un archivo de caché que le ayuda a hacer su trabajo... y lo más importante, le dice a Rector que queremos actualizar nuestro código para que sea compatible con Symfony 5.2, así como actualizar nuestro código a algunas normas de calidad de código de Symfony y de inyección de "constructores". Si quieres saber más sobre lo que hacen, puedes seguir las constantes para ver el código.
Pero, espera, ¡no queremos actualizar nuestro código a Symfony 5.2! Queremos actualizarlo por completo a Symfony 5.4. Podrías esperar que pusiera simplemente "54" aquí. Y podríamos hacerlo. Pero en lugar de eso, voy a utilizarSymfonyLevelSetList::UP_TO_SYMFONY_54
. Oh... parece que también tengo que añadir una declaraciónuse
para SymfonySetList::
. Déjame volver a escribir eso, pulsar "tab" y... ¡genial!
En fin. Tenemos que actualizar nuestro código de la 5.0 a la 5.1... luego de la 5.1 a la 5.2... y así hasta la Symfony 5.4. Eso es lo que significa UP_TO_SYMFONY_54
: incluirá todas las "reglas" para actualizar nuestro código a la 5.1, 5.2, 5.3 y finalmente a la 5.4.
Y... ¡ya está! Estamos listos para ejecutar esto. Pero antes de hacerlo, tengo curiosidad por saber qué cambios hará esto. Así que vamos a añadir todos los cambios a git... y a confirmarlos. ¡Perfecto!
Ejecutar Rector
Para ejecutar Rector, digamos ./vendor/bin/rector process
src/. También podríamos dirigirlo a los directorios config/
o templates/
... pero la gran mayoría de los cambios que hará se aplican a nuestras clases en src/
:
vendor/bin/rector process src/
Y... ¡funciona! ¡Espectacular! El rector ha cambiado ocho archivos. Desplacémonos hasta la parte superior. Esto es genial: te muestra el archivo que se modificó, el cambio real y, debajo, qué reglas causaron ese cambio.
Una de las modificaciones que hizo es UserPasswordEncoderInterface
aUserPasswordHasherInterface
. Es un buen cambio: la antigua interfaz queda obsoleta en favor de la nueva. También cambió UsernameNotFoundException
porUserNotFoundException
. Otra buena actualización de bajo nivel de un código obsoleto.
También hubo un cambio en una clase en Kernel
... y algunas otras cosas similares. Cerca del final, la lista de conjuntos de calidad de código Symfony añadió un tipo de retorno Response
a cada controlador. Eso es opcional... ¡pero bonito!
Así que no hizo una tonelada de cambios, pero arregló algunas desaprobaciones sin que tuviéramos que hacer nada.
Aunque... no es perfecto. Un problema es que, a veces, Rector se mete con tu estilo de codificación. Eso es porque Rector no entiende realmente cuál es tu estilo de codificación... y por eso ni siquiera lo intenta. Pero eso es por diseño y será fácil de arreglar.
En segundo lugar, aunque cambió la interfaz de UserPasswordEncoderInterface
aUserPasswordHasherInterface
, inlineó todo el nombre de la clase... en lugar de añadir una declaración use
.
Y tercero, no cambió ningún nombre de variable. Así que aunque cambió este argumento a UserPasswordHasherInterface
, el argumento sigue llamándose$passwordEncoder
... junto con la propiedad. Y lo que es peor, elUserPasswordHasherInterface
tiene un método diferente... y no actualizó el código aquí abajo para utilizar ese nuevo nombre de método.
Así que Rector es un gran punto de partida para captar un montón de cambios. Pero vamos a tener que coger lo que hemos encontrado y terminar el trabajo. Hagamos eso a continuación. Haremos parte de eso a mano... pero gran parte automáticamente con PHP CS Fixer.
20 Comments
Thanks @weekender
Second, while it did change the interface from UserPasswordEncoderInterface to UserPasswordHasherInterface, it inlined the whole class name... instead of adding a use statement.
`
To avoid that, you can tell rector to import automatically dependencies with :
$rectorConfig->importNames();
That's awesome - thanks for sharing that!
Do we just do ?
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Symfony\Set\SymfonySetList;
return RectorConfig::configure()
->withSymfonyContainerXml(__DIR__ . '/var/cache/dev/App_KernelDevDebugContainer.xml')
->withSets([
SymfonySetList::SYMFONY_54,
SymfonySetList::SYMFONY_CODE_QUALITY,
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
]);
There's no levelset I could find
Hey Slawomir,
What levelset exactly are you looking for? It might be so that you're on a different version from the one that is used in the video. I see we're using v0.12.20 of rector/rector package in the video
Cheers!
I'm using v1.2.2. There's a levelset in the video with up_to_symfony54 but there aren't any SymfonyLevelSetList::UP_TO_SYMFONY54
. Does this mean using symfony54 will include everything before or do we have to import everything before that ?
Hey Slawomir,
Yes, that seems to be deleted in https://github.com/rectorphp/rector-symfony/pull/609 because it was deprecated. Yeah, now I believe you need to use more specific set lists from the SymfonySetList, and if you need to jump over a few minor versions - you probably need to process them one by one now.
I hope that helps!
Cheers!
Hi. Love your screencasts on Symfony! I'm sure I'm doing something dumb using this code on SF 5.4.28 and Rector ^0.13.9:
declare(strict_types=1);
use Rector\Symfony\Set\SymfonySetList;
use Rector\Symfony\Set\SymfonyLevelSetList;
use Rector\Config\RectorConfig;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->symfonyContainerXml(__DIR__ . '/var/cache/dev/App_KernelDevDebugContainer.xml');
$rectorConfig->sets([
SymfonyLevelSetList::UP_TO_SYMFONY_54,
SymfonySetList::SYMFONY_CODE_QUALITY,
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
]);
};
Can you help me resolve:
% vendor/bin/rector process --dry-run src/
0/103 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
[ERROR] Could not process some files, due to:
"Child process error: sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `/opt/homebrew/Cellar/php@7.4/7.4.33_4/bin/php -n -c
/private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/43mCqq vendor/bin/rector worker --dry-run --port 60220
--identifier y0ia0ggj7z src/ --output-format json --no-ansi --config rector.php'
".
[ERROR] Could not process some files, due to:
"Child process error: sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `/opt/homebrew/Cellar/php@7.4/7.4.33_4/bin/php -n -c
/private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/dxzAO1 vendor/bin/rector worker --dry-run --port 60220
--identifier 9dtao4n7tv src/ --output-format json --no-ansi --config rector.php'
".
[ERROR] Could not process some files, due to:
"Child process error: sh: -c: line 0: syntax error near unexpected token '('
sh: -c: line 0: '/opt/homebrew/Cellar/php@7.4/7.4.33_4/bin/php -n -c
/private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/a1SGgm vendor/bin/rector worker --dry-run --port 60220
--identifier ou2u2kwak8 src/ --output-format json --no-ansi --config rector.php'
".
[ERROR] Could not process some files, due to:
"Child process error: sh: -c: line 0: syntax error near unexpected token '('
sh: -c: line 0: '/opt/homebrew/Cellar/php@7.4/7.4.33_4/bin/php -n -c
/private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/3D8vG9 vendor/bin/rector worker --dry-run --port 60220
--identifier xfqq8hp792 src/ --output-format json --no-ansi --config rector.php'
".
[ERROR] Could not process some files, due to:
"Child process error: sh: -c: line 0: syntax error near unexpected token '('
sh: -c: line 0: '/opt/homebrew/Cellar/php@7.4/7.4.33_4/bin/php -n -c
/private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/vpRjMM vendor/bin/rector worker --dry-run --port 60220
--identifier dmuohodmik src/ --output-format json --no-ansi --config rector.php'
".
[ERROR] Could not process some files, due to:
"Child process error: sh: -c: line 0: syntax error near unexpected token '('
sh: -c: line 0: '/opt/homebrew/Cellar/php@7.4/7.4.33_4/bin/php -n -c
/private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/PXtNQd vendor/bin/rector worker --dry-run --port 60220
--identifier p862em1hug src/ --output-format json --no-ansi --config rector.php'
".
[ERROR] Could not process some files, due to:
"Child process error: sh: -c: line 0: syntax error near unexpected token '('
sh: -c: line 0: '/opt/homebrew/Cellar/php@7.4/7.4.33_4/bin/php -n -c
/private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/wIOTPB vendor/bin/rector worker --dry-run --port 60220
--identifier bhmcwpe4wu src/ --output-format json --no-ansi --config rector.php'
".
Cheers,
JPS
Hey Jamuel,
Your Rector config looks fine. Try to upgrade Rector to the latest which is v0.18.3. I suppose those might be some internal issues that were fixed in a newer version. Also, try to clear the Symfony cache with rm -rf var/cache/
before running Rector just in case.
Also, are you sure you're in the root dir of your Symfony project? Do you recognize that /private/var/folders/d9/bv_yx_fx5hg9hj1t9v1lcym80000gn/T/PXtNQd
folder? It seems like you're in that temporary folder somehow and trying to run the Rector from it.
Also, please, make sure you have valid PHP syntax in your project code, it might be so that you accidentally removed some chars and now code is broken, try to run the project first to see it works well in the browser and no errors.
P.S. I see you're using php@7.4 that is a legacy PHP version and dropped in Brew package manager, i.e. you can't update or install it anymore. Maybe try a different (newer) PHP version.
I hope this helps!
Cheers!
Hi, when I try to run
php vendor/bin/rector process src/
I get this error:
[ERROR] Argument 1 passed to
Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator::__construct() must be an
instance of Symfony\Component\DependencyInjection\ContainerBuilder, instance of
RectorPrefix202304\Symfony\Component\DependencyInjection\ContainerBuilder given, called in
/Users/andremoens/Documents/onebranchtorulethemall/vendor/rector/rector/vendor/symfony/dependency-inje
ction/Loader/PhpFileLoader.php on line 67
Has anyone a clue how to fix this?
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!
Hey MollKhan
Thanks for your help, it allows me to continue the course.
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!
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// 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
}
}
gives back
"Command init is not defined"
You should instead now use
which does the same.