PHP 8.6 vychází 19. listopadu. DressCode pro něj kód přepisuje už teď. 16 dní Přechod na novější PHP →

Přechod na Symfony 7

Symfony 7.0 jen uklidilo: odstranilo všechno, co Symfony 6 zavrhlo, třeba anotaci @Route, anotace SensioFrameworkExtraBundle, MessageHandlerInterface, renderForm() nebo vlastnost $defaultName příkazu. Náhrady za ně má už Symfony 6.4, a tak většinu upgradu ze Symfony 6 na 7 uděláte ještě na něm: DressCode s balíčkem dresscode/upgrade-symfony váš kód přepíše a co přepsat neumí, ohlásí.

Podle UPGRADE-7.0.md má verze 7.0 stejné funkce jako 6.4, jen bez těch zavržených; obě vyšly společně na konci listopadu 2023. Verze 7.0 ale potřebuje PHP 8.2, kdežto 6.4 běží i na PHP 8.1 (Symfony 7.0).

Jak to vypadá

Tenhle controller vznikl pro Symfony 6.4 a projekt má v composer.json balíčky Symfony na 6.4.*. Používá tři věci, které Symfony 7.0 odstranilo:

use Symfony\Component\Routing\Annotation\Route;


class OrderController extends AbstractController
{
	/** @Route("/orders/{id}", name="order_show") */
	public function show(Request $request, int $id): Response
	{
		$form = $this->createForm(OrderType::class);
		return $this->renderForm('order/show.html.twig', [
			'form' => $form,
			'format' => $request->getContentType(),
		]);
	}
}

Po dresscode upgrade today, pořád na Symfony 6.4:

use Symfony\Component\Routing\Attribute\Route;


class OrderController extends AbstractController
{
	#[Route('/orders/{id}', name: 'order_show')]
	public function show(Request $request, int $id): Response
	{
		$form = $this->createForm(OrderType::class);
		return $this->render('order/show.html.twig', [
			'form' => $form,
			'format' => $request->getContentTypeFormat(),
		]);
	}
}

Z anotace se stal stejnojmenný atribut, importovaný ze jmenného prostoru Attribute místo Annotation. Z renderForm() je render(), které bere formulář tak, jak je, a z getContentType() je getContentTypeFormat(). Kód dál běží na 6.4. Po zvednutí verzí v composer.json na 7.0.* už druhý běh v tomhle controlleru nenašel nic k přepsání.

Anotace SensioFrameworkExtraBundle

SensioFrameworkExtraBundle je opuštěný a jeho poslední verze 6.2.10 připouští symfony/framework-bundle jen do řady 6.x, jak ukazuje Packagist. Framework má od Symfony 6.2 pro tyto anotace vlastní atributy a DressCode je napíše místo anotací:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;


class ProductController extends AbstractController
{
	/**
	 * @IsGranted("ROLE_EDITOR")
	 * @Cache(maxage=3600, public=true)
	 * @Template("product/list.html.twig")
	 */
	public function list(): array
	{
		return ['products' => []];
	}
}
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;


class ProductController extends AbstractController
{
	#[\Symfony\Component\Security\Http\Attribute\IsGranted('ROLE_EDITOR')]
	#[\Symfony\Component\HttpKernel\Attribute\Cache(maxage: 3600, public: true)]
	#[\Symfony\Bridge\Twig\Attribute\Template('product/list.html.twig')]
	public function list(): array
	{
		return ['products' => []];
	}
}

Importy bundlu v souboru zůstanou, a tak se nové atributy píšou plně kvalifikovanými jmény, která se s nimi nemůžou střetnout. Importy smažte, až bundle odeberete. Anotace @Security, jejíž výraz jen volá is_granted(), se převede také na #[IsGranted], jak ukazuje stránka Symfony.

Co se přepíše

Data balíčku dresscode/upgrade-symfony nesou 135 změn, které Symfony zavrhlo ve verzích 6.1 až 6.4 a ve verzi 7.0 odstranilo. Z nich 98 DressCode přepíše sám a zbylých 37 ohlásí. Tabulka ukazuje příklady, každý ověřený během DressCode. Úplný seznam je v datech balíčku, kde má každá komponenta svůj soubor, třeba console.neon.

staré API nové API od verze
protected static $defaultName = 'app:import'; #[AsCommand(name: 'app:import')] u třídy symfony/console 6.1
/** @Route("/orders/{id}") */ z Routing\Annotation #[Route('/orders/{id}')] z Routing\Attribute symfony/routing 6.4
class OrderPlacedHandler implements MessageHandlerInterface #[AsMessageHandler] class OrderPlacedHandler symfony/messenger 6.2
Symfony\Component\Security\Core\Security Symfony\Bundle\SecurityBundle\Security symfony/security-bundle 6.2
$this->renderForm($view, ['form' => $form]) $this->render($view, ['form' => $form]) symfony/framework-bundle 6.2
$request->getContentType() $request->getContentTypeFormat() symfony/http-foundation 6.2
$response->setEtag() $response->setEtag(null) symfony/http-foundation 6.2
/** @required */ #[Required] symfony/dependency-injection 6.3
@Assert\Regex("/^\w+$/") #[Assert\Regex('/^\w+$/')] symfony/validator 6.4
$e->getNestedExceptions() \array_values($e->getWrappedExceptions()) symfony/messenger 6.4
Symfony\Component\HttpKernel\UriSigner Symfony\Component\HttpFoundation\UriSigner symfony/http-kernel 6.4
SendinblueApiTransport BrevoApiTransport symfony/brevo-mailer 6.4

Sekci pro 7.0 data nemají, protože 7.0 přineslo tytéž funkce jako 6.4 a jen odstranilo, co bylo zavržené. Co změnilo Symfony 6.0, třeba přejmenování MASTER_REQUEST na MAIN_REQUEST, patří k přechodu ze Symfony 5 na 6 a balíček to pokrývá také.

Co se jen ohlásí

Kde se náhrada používá jinak nebo žádná není, DressCode do kódu nesáhne, jen místo ohlásí a poradí, co tam napsat. Typickým případem je třída, která si bere služby z kontejneru:

Class `Symfony\Component\DependencyInjection\ContainerAwareInterface` is deprecated: pass the services the class needs to its constructor, or implement `Symfony\Contracts\Service\ServiceSubscriberInterface` to fetch them lazily, since symfony/dependency-injection 6.4.
staré API co místo toho od verze
ContainerAwareInterface, ContainerAwareTrait služby v konstruktoru, nebo ServiceSubscriberInterface, který je načte líně symfony/dependency-injection 6.4
CacheableSupportsMethodInterface getSupportedTypes() normalizeru, které pro každý typ řekne, jestli se smí výsledek supports*() cachovat symfony/serializer 6.3
PostSubmitEvent::setData() setData() z PreSubmitEvent nebo SubmitEvent, v listeneru, který běží před odesláním formuláře symfony/form 6.4
Symfony\Bridge\Doctrine\Logger\DbalLogger middleware DBAL, třeba Doctrine\DBAL\Logging\Middleware symfony/doctrine-bridge 6.4
StopWorkerOnSignalsListener nic, messenger:consume zastaví workera při SIGTERM a SIGINT sám; listener odeberte symfony/messenger 6.4
Kernel::stripComments() náhrada není; zkopírujte metodu do projektu symfony/http-kernel 6.4

Takové místo potvrdíte komentářem // dresscode:ignore <rozhodnutí> -- <důvod>, nebo ho přepíšete; podrobnosti najdete v kapitole Ruční úkoly po cestě.

Změny konfigurace v YAMLu, šablon Twig a chování data nezachytí. Symfony 7.0 také dalo mnoha metodám nativní návratové typy (Symfony 7.0 type declarations) a vaše metoda, která některou z nich přepisuje, potřebuje stejný typ; jak takové signatury DressCode píše, říká stránka Symfony.

Krok za krokem

DressCode potřebuje PHP 8.4. Pokud vaše aplikace běží na starším PHP, nainstalujte DressCode globálně, s PHPStanem a s daty pro Symfony:

composer global require dresscode/dresscode dresscode/upgrade-symfony phpstan/phpstan

Na PHP 8.4 a novějším může být vývojovou závislostí projektu, jak ukazuje Instalace.

  1. Začněte na Symfony 6.4 s čistým pracovním stromem. Pusťte dresscode upgrade today, a pokud to poradí, ještě jednou. Přepíše, co Symfony 6.1 až 6.4 zavrhlo, protože náhrady už v 6.4 existují.
  2. Projděte, co ohlásí, pusťte testy a PHPStan a commitněte.
  3. Zvedněte balíčky Symfony v composer.json na 7.0.* nebo na pozdější 7.x a require.php aspoň na 8.2. Se Symfony Flex zvedněte i extra.symfony.require. Pak pusťte composer update "symfony/*" -W --prefer-lowest.
  4. Pusťte znovu dresscode upgrade today. Najde, co po zvednutí zbylo, a na pozdější 7.x i to, co zavrhla ta verze. Pak pusťte testy a commitněte.

Verzi každého balíčku DressCode čte z jeho omezení v composer.json. Když má balíček Symfony v composer.json jen * a verzi nechává na extra.symfony.require, DressCode dolní mez nevidí a změny toho balíčku jen ohlásí. Napište verzi do omezení, třeba 6.4.*.

Proč --prefer-lowest a proč po jedné hlavní verzi, vysvětluje Upgrade kódu krok za krokem.

Kam dál

Zobrazit na GitHubu · Nahlásit problém se stránkou na GitHubu · 2. 11. 2026