Upgrade Symfony
Od Symfony 6.0 se v padesáti komponentách a mostech změnilo přes 650 věcí: MASTER_REQUEST
se přejmenovalo na MAIN_REQUEST, místo anotací SensioFrameworkExtraBundle se píšou atributy frameworku a jméno
příkazu se přestěhovalo do #[AsCommand]. Balíček dresscode/upgrade-symfony je popisuje všechny.
Zhruba 440 z nich DressCode rovnou opraví, zbytek ohlásí i s tím, co napsat místo toho.
Přechody ze Symfony 6 na Symfony 7 a ze Symfony 7.4 na Symfony 8 mají vlastní stránky s příkladem a postupem krok za krokem.
Instalace
Aplikaci, která ještě běží na PHP starším než 8.4, upgradujte s DressCode nainstalovaným globálně, protože sám potřebuje PHP 8.4 (viz Kde DressCode běží):
composer global require dresscode/dresscode dresscode/upgrade-symfony phpstan/phpstan
dresscode upgrade today
Konfiguraci k tomu nepotřebujete: upgrade today si data i přepisy balíčku najde sám a styl kódu nechá,
jak je. Data každé komponenty se uplatní jen tehdy, když ji projekt má, a jen pro verze, na které projekt dosáhne. Postup po jedné hlavní verzi a co dělat s tím,
co zbude, popisuje Upgrade kódu. Projekt, který už běží na PHP 8.4 až 8.6,
si balíček může přidat i jako vývojovou závislost:
composer require --dev dresscode/upgrade-symfony phpstan/phpstan, a pak spouští
vendor/bin/dresscode upgrade today.
Projekt, který vyžaduje celé symfony/symfony, má všechny komponenty, které ten balíček
nahrazuje, ve verzi symfony/symfony.
Co se opraví
Tohle je příkaz a controller psané pro Symfony 5.4, v projektu na současných verzích:
class ReportCommand extends Command
{
protected static $defaultName = 'app:report'; // Property `Symfony\Component\Console\Command\Command::$defaultName` is replaced by the attribute `#[Symfony\Component\Console\Attribute\AsCommand]`.
protected static $defaultDescription = 'Sends the daily report'; // Property `Symfony\Component\Console\Command\Command::$defaultDescription` is replaced by the attribute `#[Symfony\Component\Console\Attribute\AsCommand]`.
protected function execute(InputInterface $input, OutputInterface $output): int
{
$request = $this->requestStack->getMasterRequest(); // Method `Symfony\Component\HttpFoundation\RequestStack::getMasterRequest()` is replaced by `RequestStack::getMainRequest()`.
$output->writeln($request->get('day')); // Method `Symfony\Component\HttpFoundation\Request::get()` is forbidden: read the bag the value comes from, the `attributes`, `query` or `request` property, such as `query->get()`.
return Command::SUCCESS;
}
}
class ReportController extends AbstractController
{
/** @Security("is_granted('ROLE_ADMIN')") */ // Annotation `@Security` is replaced by the attribute `#[Symfony\Component\Security\Http\Attribute\IsGranted]`.
public function show(): Response
{
return new Response($this->getUser()->getUsername()); // Method `Symfony\Component\Security\Core\User\UserInterface::getUsername()` is replaced by `getUserIdentifier()`.
}
}
Po dresscode upgrade today:
#[AsCommand(name: 'app:report', description: 'Sends the daily report')]
class ReportCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$request = $this->requestStack->getMainRequest();
$output->writeln($request->get('day'));
return Command::SUCCESS;
}
}
class ReportController extends AbstractController
{
#[IsGranted('ROLE_ADMIN')]
public function show(): Response
{
return new Response($this->getUser()->getUserIdentifier());
}
}
Dvě statické vlastnosti se spojily do jednoho atributu a výraz anotace @Security se stal rolí atributu
#[IsGranted], obojí i s importem. Volání $request->get() zůstalo: Request::get()
hledá hodnotu v atributech, v query i v těle požadavku, a odkud ji váš kód čte, musíte rozhodnout vy.
Co všechno balíček opravuje:
- přejmenované třídy a rozhraní:
Symfony\Component\Security\Core\SecuritynaSymfony\Bundle\SecurityBundle\Security,TaggedIteratornaAutowireIterator, most Sendinblue na Brevo a další; přepíše se import, typ,new,instanceofi atribut, - přejmenované členy:
getMasterRequest()nagetMainRequest(),HttpKernelInterface::MASTER_REQUESTnaMAIN_REQUEST,getUsername()nagetUserIdentifier(),Application::add()naaddCommand(), - volání jiného tvaru: parametr, který dostal jiné jméno (
new UriSigner($secret, parameter: ...)nahashParameter:), klíč pole voleb přejmenovaný na místě (mirror()scopy_on_windowsnafollow_symlinks), funkce konfigurace kontejneruref()naservice(), - anotace SensioFrameworkExtraBundle na atributy frameworku:
@Route,@Cache,@IsGranteda@Template, a@Security, jehož výraz jen voláis_granted(), na#[IsGranted]; anotace routingu a serializeru ze jmenného prostoruAnnotationna atributy zAttribute, anotace constraintů validátoru a@UniqueEntityna stejnojmenné atributy, kromě@ExpressionLanguageSyntax, ze které je#[ExpressionSyntax], a@requiredna#[Required], - člen třídy na atribut:
$defaultNamea$defaultDescriptionpříkazu, i přepsanégetDefaultName(), na#[AsCommand], a rozhraníMessageHandlerInterfacena#[AsMessageHandler], - resolver argumentů controlleru s rozhraním
ArgumentValueResolverInterfacenaValueResolverInterface: jehosupports()se stane podmínkou na začátkuresolve(), - signatury metod v potomcích tříd frameworku: návratové typy a parametry, které komponenta doplnila
(
execute(): intpříkazu), i bez dat, podle deklarací nainstalované verze. Dopsání návratového typu je riziková oprava (risky fix), protože tělo metody může vracet něco jiného.
Co zůstane na vás
Kde náhrada není nebo se používá jinak, DressCode místo ohlásí a řekne, co napsat. Třeba služby, které controller dřív bral z kontejneru, nebo rozhraní, místo kterého patří atributy na jednotlivé metody:
Method `Symfony\Bundle\FrameworkBundle\Controller\AbstractController::getDoctrine()` is forbidden: use a constructor or action argument typed with `Doctrine\Persistence\ManagerRegistry`.
Class `Symfony\Component\Messenger\Handler\MessageSubscriberInterface` is forbidden: write the attribute `AsMessageHandler` on each method that handles a message, with what `getHandledMessages()` yields for it as its arguments.
Co komponenta jen tiše označila jako zastaralé, v datech není; s typy to DressCode ohlásí, a kde anotace náhradu
řekne, i přepíše. Změny chování, konfigurace v YAMLu a šablon Twig data nezachytí vůbec, ty najdete v průvodcích
UPGRADE-*.md repozitáře Symfony.
Aby se staré API nevracelo
Staré API může hlídat i každá kontrola, třeba v průběžné integraci. Potřebuje k tomu v konfiguraci tři věci:
typy, sadu deprecations a jméno balíčku, které pustí dovnitř jeho přepisy ze sekce symfony (viz
Upgrade kódu):
typeAnalysis: phpstan
use:
- symfony # váš standard
- deprecations
- upgrade-symfony
Anotaci @Security, i v podobě atributu #[Security] téhož bundlu, a resolver
argumentů převádějí rozhodnutí symfony.isGrantedAttribute od symfony/security-http 6.2 a
symfony.valueResolver od symfony/http-kernel 6.2. Zapnou je data sama, takže je do konfigurace psát
nemusíte a spustí je i upgrade today. Kdo některé nechce, vypne ho v sekci symfony hodnotou
keep.
Co balíček pokrývá
| komponenta | verze |
|---|---|
symfony/asset, symfony/asset-mapper |
6.0 až 7.1 |
symfony/browser-kit, symfony/dom-crawler |
6.0 až 7.4 |
symfony/cache |
6.0 až 7.1 |
symfony/config |
6.0 až 7.4 |
symfony/console |
6.0 až 7.4 |
symfony/dependency-injection |
6.0 až 8.1 |
symfony/doctrine-bridge |
6.0 až 8.2 |
symfony/event-dispatcher |
6.0 |
symfony/expression-language |
7.1 |
symfony/filesystem, symfony/finder |
6.0 až 8.2 |
symfony/form |
6.0 až 8.1 |
symfony/framework-bundle |
6.0 až 7.4 |
symfony/html-sanitizer |
7.4 |
symfony/http-client |
6.0 až 8.1 |
symfony/http-foundation |
6.0 až 8.1 |
symfony/http-kernel |
6.0 až 8.2 |
symfony/intl |
6.0 |
symfony/json-streamer, symfony/type-info |
7.2 až 8.1 |
symfony/lock |
6.0 až 6.3 |
symfony/mailer, symfony/mime, symfony/notifier |
6.0 až 7.4 |
symfony/messenger |
6.0 až 6.4 |
symfony/monolog-bridge |
6.0 až 7.4 |
symfony/options-resolver |
6.0 |
symfony/property-access, symfony/property-info |
6.0 až 7.3 |
symfony/routing |
6.0 až 7.4 |
symfony/security-bundle, symfony/security-core, symfony/security-csrf |
6.0 až 7.4 |
symfony/security-http |
6.0 až 8.1 |
symfony/serializer |
6.0 až 7.4 |
symfony/string |
7.4 |
symfony/translation |
6.2 až 7.4 |
symfony/twig-bridge |
6.2 až 7.2 |
symfony/validator |
6.0 až 8.2 |
symfony/var-dumper, symfony/var-exporter |
6.2 až 7.3 |
symfony/workflow |
6.0 až 7.3 |
mosty brevo-mailer, brevo-notifier, mail-pace-mailer, sevenio-notifier,
google-chat-notifier, slack-notifier |
6.0 až 7.3 |
Verze říkají, ve kterých vydáních komponenta změnila něco, co data zachycují. Data vyřazeného mostu patří
k mostu, který ho nahradil: přejmenování Sendinblue na Brevo se uplatní v projektu, který už má
symfony/brevo-mailer. Aplikaci na Symfony 5.4 převedete stejně, jen začnete verzí 6.0, a jak postupovat po
jedné hlavní verzi, popisuje Upgrade kódu.