Upgrade Symfony
Balíček dresscode/upgrade-symfony nese migrace padesáti komponent a mostů Symfony od verze
6.0 po současnou. Je v něm přes 650 položek: přejmenované třídy a metody, konstanty MASTER_REQUEST
přepsané na MAIN_REQUEST, anotace SensioFrameworkExtraBundle převedené na atributy frameworku, výchozí jméno
příkazu na atribut #[AsCommand]. Zhruba 440 z nich DressCode rovnou opraví, zbytek ohlásí i s tím, co
napsat místo toho.
Instalace
composer require --dev dresscode/upgrade-symfony phpstan/phpstan
vendor/bin/dresscode upgrade
Víc k upgradu potřeba není: upgrade vezme data balíčku i jeho pravidla sám, bez konfigurace, a styl kódu
nechá, jak je. Postup po jedné hlavní verzi a co dělat s tím, co zbude, popisuje Upgrade kódu.
Aby staré API hlídala i každá kontrola, patří do konfigurace typy, sada deprecations a jméno balíčku,
které pustí dovnitř jeho pravidla sekce symfony, jak popisuje Jak funguje upgrade knihoven:
typeAnalysis: phpstan
use:
- symfony # váš standard
- deprecations
- upgrade-symfony
Dvě rozhodnutí v sekci symfony zapnou data sama, symfony.isGrantedAttribute od
symfony/security-http 6.2 a symfony.valueResolver od symfony/http-kernel 6.2, takže je do
konfigurace psát nemusíte a pustí je i upgrade. Kdo některé nechce, vypne ho v sekci symfony
hodnotou keep. Data každé komponenty se uplatní jen tehdy, když ji projekt má, a jen ty verze, na které projekt
dosáhne. Projekt, který vyžaduje celé symfony/symfony, má ve své verzi všechny komponenty, které ten
balíček nahrazuje.
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:
#[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 z které z nich 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 z 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 psaný proti
ArgumentValueResolverInterfacenaValueResolverInterface: jehosupports()se stane podmínkou na začátkuresolve(), - signatury potomků tříd frameworku, návratové typy a parametry, které komponenta doplnila
(
execute(): intpříkazu); ty píše rozhodnutíclasses.overridingMethod.signaturez deklarací nainstalované verze, bez dat. Dopsání návratového typu je riziková oprava (risky fix), protože tělo metody může vracet něco jiného, a udělá se jen s--fix-risky, po souhlasu v--ask-risky, nebo s rozhodnutím v klíčifixRisky.
Anotaci @Security, i v podobě atributu #[Security] téhož bundlu, a resolver převádějí
rozhodnutí symfony.isGrantedAttribute a symfony.valueResolver, jejichž pravidla balíček přináší.
Zbytek dělají pravidla jádra DressCode, podle dat, a signatury i bez nich.
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 ohlásí, a kde anotace náhradu řekne,
i přepíše podle upgrading.declarations.deprecatedMember. Změny chování, konfigurace v YAML a šablony Twig
data nezachytí vůbec, ty najdete v průvodcích UPGRADE-*.md repozitáře Symfony.
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 něco změnila, co data zachycují. Data vyřazeného mostu stojí pod
mostem, 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.