<?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>Scheduler on Guillaume Delré</title><link>https://guillaumedelre.github.io/fr/tags/scheduler/</link><description>Recent content in Scheduler on Guillaume Delré</description><generator>Hugo</generator><language>fr-FR</language><lastBuildDate>Wed, 10 Jan 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/fr/tags/scheduler/index.xml" rel="self" type="application/rss+xml"/><item><title>Symfony 6.4 LTS : AssetMapper, Scheduler, Webhook et la version long terme</title><link>https://guillaumedelre.github.io/fr/2024/01/10/symfony-6.4-lts-assetmapper-scheduler-webhook-et-la-version-long-terme/</link><pubDate>Wed, 10 Jan 2024 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/fr/2024/01/10/symfony-6.4-lts-assetmapper-scheduler-webhook-et-la-version-long-terme/</guid><description>Part 8 of 11 in &amp;quot;Sorties Symfony&amp;quot;: Symfony 6.4 LTS stabilise AssetMapper — une approche frontend sans bundler — aux côtés des composants Scheduler et Webhook.</description><category>symfony-releases</category><content:encoded><![CDATA[<p>Symfony 6.4 est sorti le 29 novembre 2023. C&rsquo;est une LTS avec une histoire : quatre composants qui sont sortis en expérimental dans des versions précédentes sont maintenant stables. Le plus important, c&rsquo;est AssetMapper.</p>
<h2 id="assetmapper">AssetMapper</h2>
<p>La gestion frontend moderne dans Symfony, ça voulait dire Webpack Encore. Encore fonctionne : il gère la transpilation, le bundling, le versioning, le hot reload. Il nécessite aussi Node.js, une étape de build séparée, et une quantité non négligeable de configuration pour ce qui est souvent un frontend assez modeste.</p>
<p>AssetMapper prend une position différente. Les navigateurs modernes supportent les modules ES nativement. Au lieu de bundler, livrer les fichiers tels quels, laisser le navigateur résoudre les imports via une importmap, et gérer les dépendances vendor via des fichiers téléchargés plutôt que des packages npm.</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>composer require symfony/asset-mapper
</span></span><span style="display:flex;"><span>php bin/console importmap:require lodash
</span></span></code></pre></div><p>Pas de Node.js. Pas de npm. Pas d&rsquo;étape de build. Les fichiers JavaScript et CSS sont versionnés et servis directement, avec un digest dans l&rsquo;URL pour le cache busting. Pour les applications où le frontend n&rsquo;est pas la principale préoccupation d&rsquo;ingénierie, ça supprime toute une chaîne d&rsquo;outils de l&rsquo;équation.</p>
<p>6.4 ajoute les fichiers CSS à l&rsquo;importmap, le préchargement CSS automatique via WebLink, et des commandes pour auditer et mettre à jour les dépendances vendor. L&rsquo;expérience package.json, sans npm.</p>
<h2 id="scheduler">Scheduler</h2>
<p>Le composant Scheduler (planification de tâches périodiques et de style cron sans runner externe) sort d&rsquo;expérimental et devient stable. L&rsquo;API utilise des attributs :</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">#[AsCronTask(&#39;0 * * * *&#39;)]
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">HourlyReport</span> <span style="color:#66d9ef">implements</span> <span style="color:#a6e22e">ScheduledTaskInterface</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">run</span>()<span style="color:#f92672">:</span> <span style="color:#a6e22e">void</span> { <span style="color:#f92672">...</span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Soutenu par les transports Messenger, les tâches tournent dans tout environnement où un worker est en cours d&rsquo;exécution. Pour beaucoup de cas d&rsquo;usage, ça remplace le pattern classique entrée <code>cron</code> + commande console.</p>
<h2 id="webhook-et-remoteevent">Webhook et RemoteEvent</h2>
<p>Aussi diplômés d&rsquo;expérimental : le composant Webhook gère les webhooks entrants depuis des services externes. Au lieu d&rsquo;écrire des contrôleurs bruts qui parsent les payloads et dispatchent des événements à la main, on configure des parseurs pour des services connus (Stripe, GitHub, Mailgun) et on obtient des événements typés.</p>
<h2 id="datepoint">DatePoint</h2>
<p>Une nouvelle classe <code>DatePoint</code> dans le composant Clock : un wrapper <code>DateTime</code> immutable qui lève des exceptions sur les modificateurs invalides au lieu de retourner silencieusement <code>false</code>. Petite chose, mais significative pour le code qui manipule des dates et veut réellement savoir quand quelque chose va mal.</p>
<h2 id="la-fenêtre-de-support">La fenêtre de support</h2>
<p>6.4 LTS reçoit des corrections de bugs jusqu&rsquo;en novembre 2026 et des correctifs de sécurité jusqu&rsquo;en novembre 2027. Le chemin de 6.4 vers 7.4 (la prochaine LTS) passe par les notices de dépréciation de 6.4, comme d&rsquo;habitude.</p>
<h2 id="routes-sans-strings-magiques">Routes sans strings magiques</h2>
<p>Les alias de routes basés sur le FQCN sont maintenant générés automatiquement. Si une méthode de contrôleur a une seule route, Symfony crée un alias en utilisant son nom de classe complet :</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">// Auparavant : seul &#39;blog_index&#39; fonctionnait
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Maintenant : les deux fonctionnent de manière identique
</span></span></span><span style="display:flex;"><span>$this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">urlGenerator</span><span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">generate</span>(<span style="color:#e6db74">&#39;blog_index&#39;</span>);
</span></span><span style="display:flex;"><span>$this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">urlGenerator</span><span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">generate</span>(<span style="color:#a6e22e">BlogController</span><span style="color:#f92672">::</span><span style="color:#a6e22e">class</span><span style="color:#f92672">.</span><span style="color:#e6db74">&#39;::index&#39;</span>);
</span></span></code></pre></div><p>Pour les contrôleurs invocables, l&rsquo;alias est juste le nom de classe. L&rsquo;avantage pratique : navigation IDE et sécurité au refactoring — on référence une constante de classe, pas une string qui peut silencieusement diverger.</p>
<h2 id="deux-nouveaux-attributs-di">Deux nouveaux attributs DI</h2>
<p><code>#[AutowireLocator]</code> et <code>#[AutowireIterator]</code> rejoignent la famille d&rsquo;attributs DI. Au lieu de configurer des service locators et des itérables taggués en YAML, on les déclare juste sur les paramètres du constructeur :</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">__construct</span>(
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">#[AutowireLocator([FooHandler::class, BarHandler::class])]
</span></span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">ContainerInterface</span> $handlers,
</span></span><span style="display:flex;"><span>) {}
</span></span></code></pre></div><p>Alias, services optionnels (préfixés avec <code>?</code>), et injection de paramètres via <code>SubscribedService</code> sont tous supportés. Le locator charge paresseusement, donc seuls les handlers qu&rsquo;on appelle vraiment sont instanciés.</p>
<h2 id="messenger-reçoit-des-handlers-intégrés">Messenger reçoit des handlers intégrés</h2>
<p>Trois nouvelles classes de message couvrent des tâches courantes qui nécessitaient auparavant des handlers personnalisés.</p>
<p><code>RunProcessMessage</code> dispatche une commande <code>Process</code> via le bus. <code>RunCommandMessage</code> fait de même pour les commandes console. Les deux retournent un objet de contexte avec le code de sortie et la sortie. <code>PingWebhookMessage</code> pingue une URL, ce qui est utile pour surveiller les tâches planifiées sans mettre en place un service de health-check dédié :</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>$this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">bus</span><span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">dispatch</span>(<span style="color:#66d9ef">new</span> <span style="color:#a6e22e">RunCommandMessage</span>(<span style="color:#e6db74">&#39;cache:clear&#39;</span>));
</span></span><span style="display:flex;"><span>$this<span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">bus</span><span style="color:#f92672">-&gt;</span><span style="color:#a6e22e">dispatch</span>(<span style="color:#66d9ef">new</span> <span style="color:#a6e22e">PingWebhookMessage</span>(<span style="color:#e6db74">&#39;GET&#39;</span>, <span style="color:#e6db74">&#39;https://healthchecks.io/ping/abc123&#39;</span>));
</span></span></code></pre></div><p>Le problème d&rsquo;héritage des sous-processus a aussi été résolu avec <code>PhpSubprocess</code>. Quand on lance PHP avec une limite mémoire personnalisée (<code>-d memory_limit=-1</code>), les processus enfants lancés avec <code>Process</code> ne l&rsquo;héritent pas. <code>PhpSubprocess</code> le fait :</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>$sub <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">PhpSubprocess</span>([<span style="color:#e6db74">&#39;bin/console&#39;</span>, <span style="color:#e6db74">&#39;app:heavy-import&#39;</span>]);
</span></span></code></pre></div><h2 id="sécurité--trois-corrections-pour-des-situations-réelles">Sécurité : trois corrections pour des situations réelles</h2>
<p>Le profiler montre maintenant comment les badges de sécurité ont été résolus pendant l&rsquo;authentification : lesquels ont passé, lesquels ont échoué, et pourquoi. Avant, il fallait ajouter de la sortie de debug manuellement quand un authentificateur personnalisé ne se comportait pas bien.</p>
<p>Le throttling de login via RateLimiter hache maintenant automatiquement les PII dans les logs. Les adresses IP et les noms d&rsquo;utilisateur sont hachés avec le secret du kernel avant d&rsquo;être écrits. Pas de config nécessaire, pas de regex sur les lignes de log.</p>
<p>Les patterns de firewall acceptent maintenant des tableaux :</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">firewalls</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">no_security</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">pattern</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#e6db74">&#34;^/register$&#34;</span>
</span></span><span style="display:flex;"><span>            - <span style="color:#e6db74">&#34;^/api/webhooks/&#34;</span>
</span></span></code></pre></div><p>Fini les acrobaties regex pour les exclusions multi-chemins.</p>
<h2 id="déconnexion-sans-contrôleur-bidon">Déconnexion sans contrôleur bidon</h2>
<p>La route de déconnexion nécessitait auparavant un contrôleur qui ne faisait rien que lever une exception, avec un commentaire expliquant que oui, c&rsquo;est intentionnel. 6.4 élimine ça :</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:#75715e"># config/routes/security.yaml</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">_security_logout</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">resource</span>: <span style="color:#ae81ff">security.route_loader.logout</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">type</span>: <span style="color:#ae81ff">service</span>
</span></span></code></pre></div><p>Le route loader s&rsquo;en occupe. Le contrôleur bidon est parti. Flex met à jour la recette.</p>
<h2 id="le-sérialiseur-en-meilleure-forme">Le sérialiseur en meilleure forme</h2>
<p>Trois améliorations du sérialiseur qui résolvent chacune un vrai problème.</p>
<p>Attribut <code>#[Groups]</code> au niveau de la classe : appliquer un groupe à la classe entière, puis surcharger par propriété. Utile quand une ressource a un groupe de sérialisation par défaut et quelques champs qui nécessitent un contrôle plus fin.</p>
<p>Les objets translatable ont maintenant un normaliseur dédié. Les strings translatable (enveloppant <code>TranslatableInterface</code> de Doctrine) sont traduites vers la locale passée via <code>NORMALIZATION_LOCALE_KEY</code> pendant la normalisation. Avant ça, il fallait écrire un normaliseur personnalisé.</p>
<p>En mode debug, les erreurs de décodage JSON utilisent maintenant <code>seld/jsonlint</code> pour de meilleurs messages. Au lieu de &ldquo;Syntax error&rdquo;, on obtient la ligne et ce qui s&rsquo;est vraiment passé :</p>
<pre tabindex="0"><code>Parse error on line 1: {&#39;foo&#39;: &#39;bar&#39;}
           ^ Invalid string, used single quotes instead of double quotes
</code></pre><h2 id="profilers-pour-les-choses-qui-nétaient-pas-des-requêtes-http">Profilers pour les choses qui n&rsquo;étaient pas des requêtes HTTP</h2>
<p>Le profiler de commande étend le profiler existant aux commandes console. Ajouter <code>--profile</code> à n&rsquo;importe quelle commande et obtenir une entrée complète dans le profiler : entrée/sortie, temps d&rsquo;exécution, mémoire, requêtes en base, messages de log. Les commandes qui nécessitaient <code>--verbose</code> plus du timing manuel ont maintenant la même expérience de debug que les requêtes HTTP.</p>
<p>Le profiler de workflow fait de même pour les machines à états. Un nouveau panneau montre une représentation graphique des workflows et les transitions déclenchées pendant la requête. Zéro configuration.</p>
<h2 id="laccumulation-de-dx">L&rsquo;accumulation de DX</h2>
<p>Plusieurs additions plus petites qui se combinent.</p>
<p><code>renderBlock()</code> et <code>renderBlockView()</code> sur <code>AbstractController</code> permettent de rendre un bloc Twig nommé et de le retourner comme <code>Response</code> ou string. Pratique pour les réponses Turbo Stream où on veut mettre à jour un fragment sans une action de contrôleur complète.</p>
<p>Le processeur d&rsquo;env <code>defined</code> retourne un booléen plutôt que la valeur : <code>true</code> si la variable existe et n&rsquo;est pas vide, <code>false</code> sinon. Utile pour les feature flags pilotés par des variables d&rsquo;environnement :</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">parameters</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">is_feature_enabled</span>: <span style="color:#e6db74">&#39;%env(defined:FEATURE_FLAG_KEY)%&#39;</span>
</span></span></code></pre></div><p><code>HttpClient</code> accepte maintenant <code>max_retries</code> par requête, surchargeant la stratégie globale de retry. La méthode <code>filter()</code> du composant Finder accepte un second argument pour élaguer des répertoires entiers tôt, ce qui compte quand on cherche dans de grands arbres.</p>
<p>La méthode <code>click()</code> de <code>BrowserKit</code> accepte maintenant des paramètres serveur comme en-têtes supplémentaires, utile dans les tests fonctionnels qui doivent simuler des appels API authentifiés en suivant des liens.</p>
<h2 id="limpersonation-devient-utilisable-dans-les-templates">L&rsquo;impersonation devient utilisable dans les templates</h2>
<p>Deux nouveaux helpers Twig : <code>impersonation_path()</code> et <code>impersonation_url()</code>. Ils génèrent les URLs correctes incluant le paramètre de query switch-user, qui est configurable et n&rsquo;a aucune raison d&rsquo;être codé en dur dans les templates. Les associer avec l&rsquo;existant <code>impersonation_exit_path()</code> pour le flux complet d&rsquo;impersonation admin.</p>
<h2 id="contrôle-des-locales-partout-où-ça-manquait">Contrôle des locales, partout où ça manquait</h2>
<p>Trois lacunes comblées. <code>TemplatedEmail</code> a maintenant une méthode <code>locale()</code> pour rendre les emails dans la langue du destinataire. <code>runWithLocale()</code> du locale switcher passe maintenant la locale comme argument au callback, donc on n&rsquo;a pas à la capturer depuis la portée extérieure. Et <code>app.enabledLocales</code> est disponible dans Twig, donc on peut construire des sélecteurs de langue sans coder en dur les listes de locales.</p>
<h2 id="déployer-sur-des-filesystems-en-lecture-seule">Déployer sur des filesystems en lecture seule</h2>
<p><code>APP_BUILD_DIR</code> est maintenant une variable d&rsquo;environnement reconnue par le kernel. La définir pour rediriger les artefacts compilés (cache du router, proxies Doctrine, traductions préchargées) vers un répertoire qui existe, même quand le répertoire cache par défaut n&rsquo;existe pas. <code>MicroKernelTrait</code> l&rsquo;utilise automatiquement. <code>WarmableInterface</code> a reçu un paramètre <code>$buildDir</code> pour supporter cette séparation : les warmers de cache personnalisés qui écrivent des artefacts en lecture seule doivent se mettre à jour en conséquence.</p>
]]></content:encoded></item></channel></rss>