<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Configuration on Guillaume Delré</title><link>https://guillaumedelre.github.io/fr/tags/configuration/</link><description>Recent content in Configuration on Guillaume Delré</description><generator>Hugo</generator><language>fr-FR</language><lastBuildDate>Sat, 10 Jan 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/fr/tags/configuration/index.xml" rel="self" type="application/rss+xml"/><item><title>Symfony 7.4 LTS : signature de messages, tableaux PHP en config et le dernier 7.x</title><link>https://guillaumedelre.github.io/fr/2026/01/10/symfony-7.4-lts-signature-de-messages-tableaux-php-en-config-et-le-dernier-7.x/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/fr/2026/01/10/symfony-7.4-lts-signature-de-messages-tableaux-php-en-config-et-le-dernier-7.x/</guid><description>Part 10 of 11 in &amp;quot;Sorties Symfony&amp;quot;: Symfony 7.4 LTS ajoute la signature de messages Messenger, une configuration en tableaux PHP, et clôt la ligne 7.x.</description><category>symfony-releases</category><content:encoded><![CDATA[<p>Symfony 7.4 est sorti en novembre 2025, aux côtés de 8.0. C&rsquo;est la dernière LTS de la ligne 7.x : PHP 8.2 minimum, trois ans de corrections de bugs, quatre de sécurité. Pour les équipes qui ne peuvent pas ou ne veulent pas suivre l&rsquo;exigence PHP 8.4 de 8.0, 7.4 est l&rsquo;endroit où atterrir.</p>
<h2 id="la-signature-de-messages-dans-messenger">La signature de messages dans Messenger</h2>
<p>La sécurité des transports dans Messenger a toujours été le problème de l&rsquo;application à résoudre. 7.4 ajoute la signature de messages : un mécanisme basé sur des stamps qui signe les messages dispatchés et valide les signatures à la réception.</p>
<p>Le cas d&rsquo;usage cible est les scénarios multi-tenant ou de transport externe où on a besoin d&rsquo;une preuve cryptographique qu&rsquo;un message n&rsquo;a pas été altéré ni injecté depuis l&rsquo;extérieur. La configuration vit au niveau du transport :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">framework</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">messenger</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">transports</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">async</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">dsn</span>: <span style="color:#e6db74">&#39;%env(MESSENGER_TRANSPORT_DSN)%&#39;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">options</span>:
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">signing_key</span>: <span style="color:#e6db74">&#39;%env(MESSENGER_SIGNING_KEY)%&#39;</span>
</span></span></code></pre></div><h2 id="configuration-en-tableaux-php">Configuration en tableaux PHP</h2>
<p>Les formats de configuration de Symfony ont toujours été YAML (défaut), XML et PHP. Le format PHP existait mais était maladroit : un DSL builder fluent qui nécessitait du chaînage de méthodes et ne donnait rien d&rsquo;utile à l&rsquo;IDE.</p>
<p>7.4 remplace le format fluent par des tableaux PHP standard. Les IDEs peuvent maintenant vraiment l&rsquo;analyser, <code>config/reference.php</code> est auto-généré comme référence avec annotations de types, et le résultat ressemble à des données plutôt qu&rsquo;à du code :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">return</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">function</span> (<span style="color:#a6e22e">FrameworkConfig</span> $framework)<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> {
</span></span><span style="display:flex;"><span>    $framework<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">router</span>()<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">strictRequirements</span>(<span style="color:#66d9ef">null</span>);
</span></span><span style="display:flex;"><span>    $framework<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">session</span>()<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">enabled</span>(<span style="color:#66d9ef">true</span>);
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>Le format fluent est déprécié. Les tableaux sont l&rsquo;avenir, et honnêtement c&rsquo;est un meilleur format.</p>
<h2 id="améliorations-oidc">Améliorations OIDC</h2>
<p><code>#[IsSignatureValid]</code> valide les URLs signées directement dans les contrôleurs, supprimant le boilerplate de la validation manuelle. OpenID Connect supporte maintenant plusieurs endpoints de découverte, et une nouvelle commande <code>security:oidc-token:generate</code> rend le dev et les tests beaucoup moins pénibles.</p>
<h2 id="la-fenêtre-de-support">La fenêtre de support</h2>
<p>7.4 LTS : bugs jusqu&rsquo;en novembre 2028, correctifs de sécurité jusqu&rsquo;en novembre 2029. Le chemin vers 8.4 LTS (la prochaine cible long terme) passe par les notices de dépréciation de 7.4 et la mise à jour PHP 8.4. Corriger les dépréciations maintenant et le saut vers 8.x sera beaucoup moins douloureux.</p>
<h2 id="les-attributs-deviennent-plus-précis">Les attributs deviennent plus précis</h2>
<p><code>#[CurrentUser]</code> accepte maintenant les types union, ce qui compte en pratique quand une route est accessible par plus d&rsquo;une classe utilisateur :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">index</span>(<span style="color:#75715e">#[CurrentUser] AdminUser|Customer $user): Response
</span></span></span></code></pre></div><p><code>#[Route]</code> accepte un tableau pour l&rsquo;option <code>env</code>, donc une route de debug active seulement en <code>dev</code> et <code>test</code> n&rsquo;a plus besoin de deux définitions séparées. <code>#[AsDecorator]</code> est maintenant répétable, ce qui signifie qu&rsquo;une classe peut décorer plusieurs services à la fois. Les signatures de méthode <code>#[AsEventListener]</code> acceptent les types d&rsquo;événements union. <code>#[IsGranted]</code> reçoit une option <code>methods</code> pour limiter une vérification d&rsquo;autorisation à des verbes HTTP spécifiques sans dupliquer la route.</p>
<h2 id="la-classe-request-arrête-den-faire-trop">La classe Request arrête d&rsquo;en faire trop</h2>
<p><code>Request::get()</code> est dépréciée, et franchement bonne débarrassance. La méthode cherchait dans les attributs de route, puis les paramètres de query, puis le corps de la requête, dans cet ordre, retournant silencieusement ce qu&rsquo;elle trouvait en premier. Cette ambiguïté causait de vrais bugs. Elle est supprimée dans 8.0 ; dans 7.4 elle fonctionne encore mais déclenche une dépréciation. Les remplacements sont explicites : <code>$request-&gt;attributes-&gt;get()</code>, <code>$request-&gt;query-&gt;get()</code>, <code>$request-&gt;request-&gt;get()</code>.</p>
<p>Le parsing du corps pour les requêtes <code>PUT</code>, <code>PATCH</code>, <code>DELETE</code> et <code>QUERY</code> arrive en même temps. Auparavant Symfony ne parsait <code>application/x-www-form-urlencoded</code> et <code>multipart/form-data</code> que pour <code>POST</code>. Ces mêmes types de contenu sont maintenant parsés pour les autres méthodes accessibles en écriture aussi, ce qui tue un contournement REST API courant.</p>
<p>La surcharge de méthode HTTP pour <code>GET</code>, <code>HEAD</code>, <code>CONNECT</code> et <code>TRACE</code> est dépréciée. Surcharger une méthode sûre avec un header était de toute façon toujours sémantiquement cassé. On peut maintenant autoriser explicitement seulement les méthodes qui ont du sens pour son application :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">Request</span><span style="color:#f92672">::</span><span style="color:#a6e22e">setAllowedHttpMethodOverride</span>([<span style="color:#e6db74">&#39;PUT&#39;</span>, <span style="color:#e6db74">&#39;PATCH&#39;</span>, <span style="color:#e6db74">&#39;DELETE&#39;</span>]);
</span></span></code></pre></div><h2 id="les-workflows-acceptent-les-backedenums">Les Workflows acceptent les BackedEnums</h2>
<p>Les places et transitions de Workflow peuvent maintenant être définies avec des backed enums PHP, à la fois en YAML (via le tag <code>!php/enum</code>) et en config PHP. Le marking store fonctionne avec les valeurs d&rsquo;enum directement, donc le modèle de domaine et la définition du workflow utilisent enfin les mêmes types :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">framework</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">workflows</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">blog_publishing</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">initial_marking</span>: !<span style="color:#ae81ff">php/enum App\Status\PostStatus::Draft</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">places</span>: !<span style="color:#ae81ff">php/enum App\Status\PostStatus</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">transitions</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">publish</span>:
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">from</span>: !<span style="color:#ae81ff">php/enum App\Status\PostStatus::Review</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">to</span>: !<span style="color:#ae81ff">php/enum App\Status\PostStatus::Published</span>
</span></span></code></pre></div><h2 id="étendre-la-validation-et-la-sérialisation-pour-les-classes-tierces">Étendre la validation et la sérialisation pour les classes tierces</h2>
<p>Besoin d&rsquo;ajouter des métadonnées de validation ou de sérialisation à une classe d&rsquo;un bundle qu&rsquo;on ne possède pas ? 7.4 a <code>#[ExtendsValidationFor]</code> et <code>#[ExtendsSerializationFor]</code> pour ça. On écrit une classe compagnon avec ses annotations supplémentaires, on pointe l&rsquo;attribut vers la classe cible, et Symfony fusionne les métadonnées à la compilation du conteneur :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#75715e">#[ExtendsValidationFor(UserRegistration::class)]
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">UserRegistrationValidation</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">#[Assert\NotBlank(groups: [&#39;my_app&#39;])]
</span></span></span><span style="display:flex;"><span>    <span style="color:#75715e">#[Assert\Length(min: 3, groups: [&#39;my_app&#39;])]
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">string</span> $name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">#[Assert\Email(groups: [&#39;my_app&#39;])]
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">string</span> $email <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&#39;</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Symfony vérifie à la compilation que les propriétés déclarées existent réellement sur la classe cible. Un renommage ne cassera pas silencieusement la validation.</p>
<h2 id="dx--ce-qui-ne-fait-pas-la-une-mais-compte">DX : ce qui ne fait pas la une mais compte</h2>
<p>Le helper Question dans Console accepte un timeout. Demander à l&rsquo;utilisateur de confirmer quelque chose, et s&rsquo;il ne répond pas en N secondes, la réponse par défaut s&rsquo;applique. Très pratique dans les scripts de déploiement qui ne peuvent pas se permettre d&rsquo;attendre éternellement un humain.</p>
<p><code>messenger:consume</code> reçoit <code>--exclude-receivers</code>. Combiné avec <code>--all</code>, il permet de consommer depuis tous les transports sauf des spécifiques :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bin/console messenger:consume --all --exclude-receivers<span style="color:#f92672">=</span>low_priority
</span></span></code></pre></div><p>Le mode worker FrankenPHP est maintenant auto-détecté. Si le processus tourne dans FrankenPHP, Symfony bascule en mode worker automatiquement. Pas de package supplémentaire nécessaire.</p>
<p>La commande <code>debug:router</code> cache les colonnes <code>Scheme</code> et <code>Host</code> quand toutes les routes utilisent <code>ANY</code>, ce qui supprime beaucoup de bruit de la sortie par défaut. Les méthodes HTTP sont maintenant aussi colorées.</p>
<p>Les tests fonctionnels reçoivent <code>$client-&gt;getSession()</code> avant la première requête. Auparavant il fallait faire au moins une requête pour accéder à la session, ce qui était agaçant. Maintenant on peut pré-remplir les tokens CSRF ou les flags A/B en amont :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$session <span style="color:#f92672">=</span> $client<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">getSession</span>();
</span></span><span style="display:flex;"><span>$session<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">set</span>(<span style="color:#e6db74">&#39;_csrf/checkout&#39;</span>, <span style="color:#e6db74">&#39;test-token&#39;</span>);
</span></span><span style="display:flex;"><span>$session<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">save</span>();
</span></span></code></pre></div><h2 id="lock--store-dynamodb">Lock : store DynamoDB</h2>
<p><code>DynamoDbStore</code> arrive comme nouveau backend de Lock. Utile dans les déploiements AWS-natifs où Redis n&rsquo;est pas dans la stack, et ça fonctionne exactement comme n&rsquo;importe quel autre store :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$store <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">DynamoDbStore</span>(<span style="color:#e6db74">&#39;dynamodb://default/locks&#39;</span>);
</span></span><span style="display:flex;"><span>$factory <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">LockFactory</span>($store);
</span></span></code></pre></div><h2 id="bridge-doctrine--types-day-point-et-time-point">Bridge Doctrine : types day point et time point</h2>
<p>Deux nouveaux types de colonnes Doctrine : <code>day_point</code> stocke une valeur date uniquement (sans composant heure) et <code>time_point</code> stocke une valeur heure uniquement, tous deux mappant vers <code>DatePoint</code>. Bien quand le domaine sépare genuinement la date de l&rsquo;heure :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#75715e">#[ORM\Column(type: &#39;day_point&#39;)]
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#a6e22e">DatePoint</span> $birthDate;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#[ORM\Column(type: &#39;time_point&#39;)]
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#a6e22e">DatePoint</span> $openingTime;
</span></span></code></pre></div><h2 id="routing--paramètres-de-query-explicites">Routing : paramètres de query explicites</h2>
<p>La clé <code>_query</code> dans la génération d&rsquo;URL permet de définir les paramètres de query explicitement, séparément des paramètres de route. Ça compte quand un paramètre de route et un paramètre de query partagent le même nom :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$url <span style="color:#f92672">=</span> $urlGenerator<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">generate</span>(<span style="color:#e6db74">&#39;report&#39;</span>, [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;site&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;fr&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;_query&#39;</span> <span style="color:#f92672">=&gt;</span> [<span style="color:#e6db74">&#39;site&#39;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;us&#39;</span>],
</span></span><span style="display:flex;"><span>]);
</span></span><span style="display:flex;"><span><span style="color:#75715e">// /report/fr?site=us
</span></span></span></code></pre></div><h2 id="weblink--parsing-des-en-têtes-link-entrants">WebLink : parsing des en-têtes Link entrants</h2>
<p><code>HttpHeaderParser</code> parse les en-têtes de réponse <code>Link</code> en objets structurés. Avant ça, parser des en-têtes Link depuis des réponses d&rsquo;API nécessitait soit d&rsquo;importer une bibliothèque tierce, soit d&rsquo;écrire des regex. Le cas d&rsquo;usage : les APIs HTTP qui annoncent des ressources liées ou la pagination via des en-têtes Link, comme le fait l&rsquo;API GitHub.</p>
<h2 id="le-parsing-html5-est-plus-rapide-sur-php-84">Le parsing HTML5 est plus rapide sur PHP 8.4</h2>
<p>DomCrawler et HtmlSanitizer basculent vers le parser HTML5 natif de PHP 8.4 quand il est disponible. Pas de changements de code nécessaires de votre côté. Le parser natif est plus rapide et plus conforme à la spec que le fallback précédent. Sur PHP 8.2 ou 8.3, rien ne change.</p>
<h2 id="translation--staticmessage">Translation : StaticMessage</h2>
<p><code>StaticMessage</code> implémente <code>TranslatableInterface</code> mais ne traduit intentionnellement pas. Elle passe la string inchangée quelle que soit la locale. Le cas d&rsquo;usage : les réponses d&rsquo;API qui doivent rester dans une langue fixe quelle que soit la locale de l&rsquo;utilisateur, ou les entrées de log d&rsquo;audit où on doit préserver le texte original tel quel.</p>
]]></content:encoded></item></channel></rss>