<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom"
>
    <channel>
        <title>Symfony Blog</title>
        <atom:link href="https://feeds.feedburner.com/symfony/blog" rel="self" type="application/rss+xml" />
        <link>https://symfony.com/blog/</link>
        <description>Most recent posts published on the Symfony project blog</description>
        <pubDate>Sat, 10 Oct 2026 16:23:42 +0200</pubDate>
        <lastBuildDate>Fri, 09 Oct 2026 09:19:00 +0200</lastBuildDate>
        <language>en</language>
                        <item>
            <title><![CDATA[New in Symfony 8.2: Single-Use and Safer Signed URLs]]></title>
            <link>https://symfony.com/blog/new-in-symfony-8-2-single-use-and-safer-signed-urls?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>Signed URLs let you share links that can&#039;t be tampered with, such as password
reset links, email confirmation links or download links. Symfony provides the
UriSigner utility to create and check them, and login links to log in
users without a password. Symfony…</description>
            <content:encoded><![CDATA[
                                <p>Signed URLs let you share links that can't be tampered with, such as password
reset links, email confirmation links or download links. Symfony provides the
<a href="https://symfony.com/doc/current/routing.html#signing-uris" class="reference external">UriSigner</a> utility to create and check them, and <a href="https://symfony.com/doc/current/security/login_link.html" class="reference external">login links</a> to log in
users without a password. Symfony 8.2 makes both <strong>more secure and flexible</strong>.</p>
<div class="section">
<h2 id="single-use-signed-urls"><a class="headerlink" href="#single-use-signed-urls" title="Permalink to this headline">Single-Use Signed URLs</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/kbond">
                <img src="https://connect.symfony.com/profile/kbond.picture" alt="Kevin Bond">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/kbond">Kevin Bond</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/64408">#64408</a>
                                                </span>
            </div>
</div>
<p>A signed URL stays valid until it expires, no matter how many times it's used.
This is a problem for links like password resets, which should stop working
once they do their job. Until now, you had to implement your own invalidation
logic for these links (e.g. storing some token in the database).</p>
<p>In Symfony 8.2, the <code translate="no" class="notranslate">sign()</code>, <code translate="no" class="notranslate">check()</code>, <code translate="no" class="notranslate">checkRequest()</code> and <code translate="no" class="notranslate">verify()</code>
methods of <code translate="no" class="notranslate">UriSigner</code> accept a new <code translate="no" class="notranslate">$version</code> argument. Its value is added
to the signature (but not to the URL), so the URL is valid only while that value
stays the same. Use a value that changes once the link is used, like the hash
of the user password:</p>
<div translate="no" data-loc="12" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpFoundation</span>\<span class="hljs-title">UriSigner</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Routing</span>\<span class="hljs-title">Generator</span>\<span class="hljs-title">UrlGeneratorInterface</span>;

<span class="hljs-comment">// when sending the password reset email</span>
<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>url</span> = <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>uriSigner</span>-&gt;<span class="hljs-title invoke__">sign</span>(
    <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>this</span>-&gt;<span class="hljs-title invoke__">generateUrl</span>(<span class="hljs-string">'reset_password'</span>, [<span class="hljs-string">'id'</span> =&gt; <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>user</span>-&gt;<span class="hljs-title invoke__">getId</span>()], UrlGeneratorInterface::<span class="hljs-variable constant_">ABSOLUTE_URL</span>),
    <span class="hljs-keyword">new</span> \<span class="hljs-title invoke__">DateInterval</span>(<span class="hljs-string">'PT30M'</span>),
    <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>user</span>-&gt;<span class="hljs-title invoke__">getPassword</span>(),
);

<span class="hljs-comment">// in the controller that handles the link</span>
<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>uriSigner</span>-&gt;<span class="hljs-title invoke__">verify</span>(<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>request</span>, <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>user</span>-&gt;<span class="hljs-title invoke__">getPassword</span>());</code></pre>
    </div>
</div>
<p>Calling <code translate="no" class="notranslate">verify()</code> doesn't invalidate the link. The link becomes invalid
once the application saves the user's new password hash. Any subsequent
call to <code translate="no" class="notranslate">verify()</code> with that hash throws an <code translate="no" class="notranslate">UnverifiedSignedUriException</code>.</p>
<p>The same idea works for other links: use the last login date for login links or
the email verification date for email confirmation links.</p>
</div>
<div class="section">
<h2 id="requiring-an-expiration-for-signed-urls"><a class="headerlink" href="#requiring-an-expiration-for-signed-urls" title="Permalink to this headline">Requiring an Expiration for Signed URLs</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/kbond">
                <img src="https://connect.symfony.com/profile/kbond.picture" alt="Kevin Bond">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/kbond">Kevin Bond</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/64455">#64455</a>
                                                </span>
            </div>
</div>
<p>Signed URLs without an expiration are valid forever, so a link that leaks in
an old email or a log file can be used at any time. That's why Symfony 8.2
deprecates calling <code translate="no" class="notranslate">UriSigner::sign()</code> without an expiration. In <a href="https://symfony.com/releases/9.0" class="reference external">Symfony 9.0</a>
the expiration will be required.</p>
<p>You can pass the expiration in each <code translate="no" class="notranslate">sign()</code> call or define a default one
via the new <code translate="no" class="notranslate">$defaultExpiration</code> constructor argument (a <code translate="no" class="notranslate">\DateInterval</code>
or a number of seconds). If you use the <code translate="no" class="notranslate">uri_signer</code> service of the framework,
set the default expiration (in seconds) with the new <code translate="no" class="notranslate">uri_signer.expiration</code>
option:</p>
<div class="configuration-block">
    <div role="tablist" aria-label="Configuration formats" class="configuration-tabs configuration-tabs-length-2">
                    <button role="tab" type="button" data-language="yaml" aria-controls="configuration-block-tabpanel-bca9add75d92f5e17eb74fef6d602e7599e0f7d1" aria-selected="true" data-active="true">
                <span>YAML</span>
            </button>
                    <button role="tab" type="button" data-language="php" aria-controls="configuration-block-tabpanel-229273fd7e79c70ae72a52a7eeed064c96e64d5e" aria-selected="false" tabindex="-1">
                <span>PHP</span>
            </button>
            </div>

            <div role="tabpanel" id="configuration-block-tabpanel-bca9add75d92f5e17eb74fef6d602e7599e0f7d1" aria-label="YAML" class="configuration-codeblock" data-language="yaml" style="">
            <div translate="no" data-loc="4" class="notranslate codeblock codeblock-length-sm codeblock-yaml">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment"># config/packages/framework.yaml</span>
<span class="hljs-attr">framework:</span>
    <span class="hljs-attr">uri_signer:</span>
        <span class="hljs-attr">expiration:</span> <span class="hljs-number">3600</span></code></pre>
    </div>
</div>
        </div>
            <div role="tabpanel" id="configuration-block-tabpanel-229273fd7e79c70ae72a52a7eeed064c96e64d5e" aria-label="PHP" class="configuration-codeblock" data-language="php" style="display: none">
            <div translate="no" data-loc="10" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment">// config/packages/framework.php</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">DependencyInjection</span>\<span class="hljs-title">Loader</span>\<span class="hljs-title">Configurator</span>;

<span class="hljs-keyword">return</span> App::<span class="hljs-title invoke__">config</span>([
    <span class="hljs-string">'framework'</span> =&gt; [
        <span class="hljs-string">'uri_signer'</span> =&gt; [
            <span class="hljs-string">'expiration'</span> =&gt; <span class="hljs-number">3600</span>,
        ],
    ],
]);</code></pre>
    </div>
</div>
        </div>
    </div>
</div>
<div class="section">
<h2 id="signed-parameters-in-login-links"><a class="headerlink" href="#signed-parameters-in-login-links" title="Permalink to this headline">Signed Parameters in Login Links</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/janklan">
                <img src="https://connect.symfony.com/profile/janklan.picture" alt="Jan Klan">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/janklan">Jan Klan</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/64271">#64271</a>
                                                </span>
            </div>
</div>
<p>Login links contain the user identifier, the expiration date and a signature.
If you added other query parameters to these links (e.g. the page to redirect
to after login), anyone could change them because they weren't signed.</p>
<p>In Symfony 8.2, the <code translate="no" class="notranslate">createLoginLink()</code> method accepts a new <code translate="no" class="notranslate">$parameters</code>
argument. These parameters are added to the link URL and covered by its signature:</p>
<div translate="no" data-loc="3" class="notranslate codeblock codeblock-length-sm codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>loginLinkDetails</span> = <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>loginLinkHandler</span>-&gt;<span class="hljs-title invoke__">createLoginLink</span>(<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>user</span>, <span class="hljs-attr">parameters</span>: [
    <span class="hljs-string">'return_to'</span> =&gt; <span class="hljs-string">'/account/settings'</span>,
]);</code></pre>
    </div>
</div>
<p>If someone changes or removes any of these parameters, the login link becomes
invalid. When the link is used, Symfony stores the verified parameters in the
<code translate="no" class="notranslate">_login_link_parameters</code> request attribute:</p>
<div translate="no" data-loc="1" class="notranslate codeblock codeblock-length-sm codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>returnTo</span> = <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>request</span>-&gt;attributes-&gt;<span class="hljs-title invoke__">get</span>(<span class="hljs-string">'_login_link_parameters'</span>)[<span class="hljs-string">'return_to'</span>] ?? <span class="hljs-keyword">null</span>;</code></pre>
    </div>
</div>
<div class="admonition admonition-caution ">
    <p class="admonition-title">
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" width="24" height="24" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>
                <span>Caution</span>
    </p><p>In your authentication success handler, always read these values from the
<code translate="no" class="notranslate">_login_link_parameters</code> attribute and not from the query string. Symfony
ignores the extra query parameters that are not signed (e.g. tracking
parameters added by email clients), so anyone can add them to the URL.</p>
</div>
</div>
                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/new-in-symfony-8-2-single-use-and-safer-signed-urls?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Javier Eguiluz ]]></dc:creator>
            <pubDate>Fri, 09 Oct 2026 09:19:00 +0200</pubDate>
            <comments>https://symfony.com/blog/new-in-symfony-8-2-single-use-and-safer-signed-urls?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[SymfonyCon Warsaw 2026: Exposing Your API to AI Agents]]></title>
            <link>https://symfony.com/blog/symfonycon-warsaw-2026-exposing-your-api-to-ai-agents?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>
    


Ready to take your PHP and Symfony skills to the next level?  SymfonyCon Warsaw 2026 lands in Poland on November 26-27! Gather with developers worldwide for two high-impact days offering 3 parallel tracks and exciting community events. Mark your calendar…</description>
            <content:encoded><![CDATA[
                                <p><a class="block text-center" href="https://live.symfony.com/2026-warsaw-con" title="Nl Blog Banner">
    <img src="https://symfony.com/uploads/assets/blog/NL-BLOG-Banner.png" alt="Nl Blog Banner">
</a></p>

<p>Ready to take your PHP and Symfony skills to the next level?  <strong><a href="https://live.symfony.com/2026-warsaw-con/">SymfonyCon Warsaw 2026</a></strong> lands in Poland on November 26-27! Gather with developers worldwide for two high-impact days offering 3 parallel tracks and exciting community events. Mark your calendar and lock in your tickets now!</p>

<hr />

<h3>🎤 Speaker announcement</h3>

<p>We are thrilled to announce <strong><a href="https://connect.symfony.com/profile/soyuka">Antoine Bluchet</a></strong>, Lead developper, Les-Tilleuls.coop, for the talk <strong><a href="https://live.symfony.com/2026-warsaw-con/schedule/exposing-your-api-to-ai-agents">"Exposing Your API to AI Agents"</a></strong>. We’re excited to bring this expertise to the stage!</p>

<p>"Picture this: you connect an AI agent to your API and, all at once, dozens of "tools" pile into its context before it's done a thing. There has to be a better way, and there are a few, each with its own trade-offs.</p>

<p>After a quick refresher on the Model Context Protocol (MCP) and its PHP SDK (how an agent discovers your tools, understands what they expect, and calls them), we'll look at how to feed an agent its tools with Symfony and API Platform. From automatic strategies (generating tools from your API, or a Hydra gateway that lets the agent discover them by navigating hypermedia links) to the manual approach, declaring exactly the tools you want using PHP attributes.</p>

<p>We'll build them live and weigh them honestly: what saturates the context, what scales, what respects the constraints of REST/HATEOAS. You'll leave knowing which approach fits your own APIs."</p>

<p>Click here to see more <strong><a href="https://live.symfony.com/2026-warsaw-con/schedule">talks</a></strong>. The full schedule will be unveiled step-by-step over the coming weeks. Stay tuned!</p>

<h3>Ready to join us?</h3>

<h3>🏨 Accommodation</h3>

<p>The official conference hotel offers special preferential rates and flexible conditions for our attendees. Make sure to use our <strong><a href="https://www.hilton.com/en/book/reservation/rooms/?ctyhocn=WAWHIHI&amp;arrivalDate=2026-11-23&amp;departureDate=2026-11-29&amp;groupCode=GSYMDP&amp;room1NumAdults=1">dedicated link</a></strong> to book your room and stay right where the action happens!</p>

<h3>🥳 Save the date for the Community Party!</h3>

<p>Because SymfonyCon isn't just about code, we are happy to confirm that our traditional Community Party will take place on the evening of <strong>Thursday, November 26</strong>. Get ready for a great night of networking, fun, and connecting with peers!</p>

<h3>💻 Hackday</h3>

<p>Ready to contribute? The Hackday on <strong>Saturday, November 28</strong> (free and open to all!) will take place at "The Brain Embassy - Czackiego" thanks to the support of <a href="https://baksla.sh/">Baksla.sh</a>. Bring your laptop and your good mood!</p>

<h3>🎟️ Get your tickets</h3>

<p>Tickets are available here: <strong><a href="https://live.symfony.com/2026-warsaw-con/registration">Secure your ticket today!</a></strong></p>

<hr />

<h3>Join us online!</h3>

<p>💡Follow the "conference" blog posts to not miss anything!</p>

<p>Want the latest Symfony updates? Follow us and tune in from wherever you are 🌎</p>

<p><a class="block text-center" href="https://linktr.ee/symfony">
   <img src="https://symfony.com/uploads/assets/blog/Banner-BLOG.png" alt="Banner Blog">
</a></p>

                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/symfonycon-warsaw-2026-exposing-your-api-to-ai-agents?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Eloïse Charrier ]]></dc:creator>
            <pubDate>Thu, 08 Oct 2026 14:30:00 +0200</pubDate>
            <comments>https://symfony.com/blog/symfonycon-warsaw-2026-exposing-your-api-to-ai-agents?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[New in Symfony 8.2: EntityExists, Cron and Audio Constraints]]></title>
            <link>https://symfony.com/blog/new-in-symfony-8-2-entityexists-cron-and-audio-constraints?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>The Symfony Validator component provides over 80 built-in constraints to
validate all kinds of data. Symfony 8.2 adds three new constraints for some
common needs that previously required custom validation code.

EntityExists Constraint…</description>
            <content:encoded><![CDATA[
                                <p>The Symfony <a href="https://symfony.com/validator" class="reference external">Validator component</a> provides <a href="https://symfony.com/doc/current/validation.html#supported-constraints" class="reference external">over 80 built-in constraints</a> to
validate all kinds of data. Symfony 8.2 adds <strong>three new constraints</strong> for some
common needs that previously required custom validation code.</p>
<div class="section">
<h2 id="entityexists-constraint"><a class="headerlink" href="#entityexists-constraint" title="Permalink to this headline">EntityExists Constraint</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/evgenijvy">
                <img src="https://connect.symfony.com/profile/evgenijvy.picture" alt="Evgen Yurchenko">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/evgenijvy">Evgen Yurchenko</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/63483">#63483</a>
                                                </span>
            </div>
</div>
<p>When your application receives entity identifiers in DTOs (e.g. from an API
request or a form), you usually have to repeat the same logic: look up the entity,
check if it exists and throw an error otherwise. The new <code translate="no" class="notranslate">EntityExists</code>
constraint handles this check and reports a missing entity as a validation
violation on the property:</p>
<div translate="no" data-loc="15" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Entity</span>\<span class="hljs-title">Product</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Entity</span>\<span class="hljs-title">User</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Bridge</span>\<span class="hljs-title">Doctrine</span>\<span class="hljs-title">Validator</span>\<span class="hljs-title">Constraints</span>\<span class="hljs-title">EntityExists</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Validator</span>\<span class="hljs-title">Constraints</span> <span class="hljs-title">as</span> <span class="hljs-title">Assert</span>;

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AssignOrderCommand</span>
</span>{
    <span class="hljs-meta">#[Assert\NotBlank]</span>
    <span class="hljs-meta">#[EntityExists(<span class="hljs-attr">entityClass</span>: User::<span class="hljs-variable language_">class</span>)]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>userId</span>;

    <span class="hljs-comment">// look up the value by some field other than the entity identifier</span>
    <span class="hljs-meta">#[EntityExists(<span class="hljs-attr">entityClass</span>: Product::<span class="hljs-variable language_">class</span>, <span class="hljs-attr">identifierField</span>: <span class="hljs-string">'sku'</span>)]</span>
    <span class="hljs-keyword">public</span> ?<span class="hljs-keyword">string</span> <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>productSku</span> = <span class="hljs-keyword">null</span>;
}</code></pre>
    </div>
</div>
<p>By default, the value is looked up by the entity identifier. You can also use
the <code translate="no" class="notranslate">repositoryMethod</code> option to call your own repository method; any truthy
result (an entity, a count, <code translate="no" class="notranslate">true</code>, etc.) means that the entity exists.</p>
<p>Like most constraints, <code translate="no" class="notranslate">null</code> and empty strings are considered valid, so combine
it with <code translate="no" class="notranslate">NotBlank</code> when the value is required.</p>
</div>
<div class="section">
<h2 id="cron-constraint"><a class="headerlink" href="#cron-constraint" title="Permalink to this headline">Cron Constraint</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://github.com/ErfanMomeniii">
                <img src="https://github.com/ErfanMomeniii.png" alt="Erfan Momeni">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://github.com/ErfanMomeniii">Erfan Momeni</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/64538">#64538</a>
                                                </span>
            </div>
</div>
<p>If your application lets users define schedules, a regular expression that only
checks the format can miss invalid values such as <code translate="no" class="notranslate">60 * * * *</code> or <code translate="no" class="notranslate">*/0 * * * *</code>.
The new <code translate="no" class="notranslate">Cron</code> constraint validates cron expressions using a dedicated parser:</p>
<div translate="no" data-loc="16" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Validator</span>\<span class="hljs-title">Constraints</span> <span class="hljs-title">as</span> <span class="hljs-title">Assert</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Report</span>
</span>{
    <span class="hljs-comment">// accepts standard expressions (e.g. '0 6 * * 1-5') and aliases like '@daily'</span>
    <span class="hljs-meta">#[Assert\Cron]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>schedule</span>;

    <span class="hljs-comment">// only accepts standard 5-field expressions</span>
    <span class="hljs-meta">#[Assert\Cron(<span class="hljs-attr">mode</span>: Assert\Cron::<span class="hljs-variable constant_">MODE_STANDARD</span>)]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>strictSchedule</span>;

    <span class="hljs-comment">// also accepts the hashed expressions of the Scheduler component (e.g. '# # * * *')</span>
    <span class="hljs-meta">#[Assert\Cron(<span class="hljs-attr">mode</span>: Assert\Cron::<span class="hljs-variable constant_">MODE_HASHED</span>)]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>scheduledTask</span>;
}</code></pre>
    </div>
</div>
<p>The <code translate="no" class="notranslate">MODE_HASHED</code> mode also accepts <a href="https://symfony.com/doc/current/scheduler.html" class="reference external">hashed cron expressions</a> such as
<code translate="no" class="notranslate"># # * * *</code> and aliases like <code translate="no" class="notranslate">#daily</code>, which the Scheduler component uses
to spread recurring tasks over time. This constraint requires the
<code translate="no" class="notranslate">dragonmantank/cron-expression</code> package, which is the same one used by the
Scheduler component for cron triggers.</p>
</div>
<div class="section">
<h2 id="audio-constraint"><a class="headerlink" href="#audio-constraint" title="Permalink to this headline">Audio Constraint</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/valmonzo">
                <img src="https://connect.symfony.com/profile/valmonzo.picture" alt="Valmont Pehaut-Pietri">
            </a>
                    <a target="_blank" href="https://connect.symfony.com/profile/nicolas-grekas">
                <img src="https://connect.symfony.com/profile/nicolas-grekas.picture" alt="Nicolas Grekas">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/valmonzo">Valmont Pehaut-Pietri</a>
             and                     <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/nicolas-grekas">Nicolas Grekas</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/66143">#66143</a>
                                                </span>
            </div>
</div>
<p>Symfony 7.4 added a <a href="https://symfony.com/blog/new-in-symfony-7-4-video-constraint" class="reference external">Video constraint</a> to validate video files. Symfony 8.2 adds
its audio counterpart, the <code translate="no" class="notranslate">Audio</code> constraint, which validates audio files
based on their actual characteristics (duration, bitrate, sample rate, number
of channels, codec and container) and not only on their MIME type and size:</p>
<div translate="no" data-loc="18" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpFoundation</span>\<span class="hljs-title">File</span>\<span class="hljs-title">File</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Validator</span>\<span class="hljs-title">Constraints</span> <span class="hljs-title">as</span> <span class="hljs-title">Assert</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PodcastEpisode</span>
</span>{
    <span class="hljs-meta">#[Assert\Audio(
        <span class="hljs-attr">maxSize</span>: <span class="hljs-string">'200M'</span>,
        <span class="hljs-comment">// durations are in seconds, bitrates in bits per second and sample rates in Hz</span>
        <span class="hljs-attr">minDuration</span>: <span class="hljs-number">60</span>,
        <span class="hljs-attr">maxDuration</span>: <span class="hljs-number">3</span> * <span class="hljs-number">3</span>_600,
        <span class="hljs-attr">minBitrate</span>: <span class="hljs-number">96</span>_000,
        <span class="hljs-attr">allowedSampleRates</span>: [<span class="hljs-number">44</span>_100, <span class="hljs-number">48</span>_000],
        <span class="hljs-attr">maxChannels</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">allowedCodecs</span>: [<span class="hljs-string">'mp3'</span>, <span class="hljs-string">'aac'</span>],
        <span class="hljs-attr">allowedContainers</span>: [<span class="hljs-string">'mp3'</span>, <span class="hljs-string">'mp4'</span>],
    )]</span>
    <span class="hljs-keyword">public</span> ?File <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>audioFile</span> = <span class="hljs-keyword">null</span>;
}</code></pre>
    </div>
</div>
<p>The <code translate="no" class="notranslate">Audio</code> constraint extends the <code translate="no" class="notranslate">File</code> constraint, so all its options are
available too. Its <code translate="no" class="notranslate">mimeTypes</code> option defaults to <code translate="no" class="notranslate">audio/*</code> and, unlike the
<code translate="no" class="notranslate">Video</code> constraint, it doesn't restrict codecs or containers unless you set the
<code translate="no" class="notranslate">allowedCodecs</code> and <code translate="no" class="notranslate">allowedContainers</code> options. When you configure any of the
audio-specific checks, it uses the <a href="https://symfony.com/process" class="reference external">Process component</a> and the <code translate="no" class="notranslate">ffprobe</code> binary
from <a href="https://ffmpeg.org/" class="reference external" rel="external noopener noreferrer" target="_blank">FFmpeg</a> to inspect the file.</p>
</div>
                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/new-in-symfony-8-2-entityexists-cron-and-audio-constraints?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Javier Eguiluz ]]></dc:creator>
            <pubDate>Thu, 08 Oct 2026 09:03:00 +0200</pubDate>
            <comments>https://symfony.com/blog/new-in-symfony-8-2-entityexists-cron-and-audio-constraints?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[New in Symfony 8.2: Compiled Event Dispatcher]]></title>
            <link>https://symfony.com/blog/new-in-symfony-8-2-compiled-event-dispatcher?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>
    
                    
                
            
            
    
        Contributed by
                    Nicolas Grekas
                                         in
                                    #66122
                    ,…</description>
            <content:encoded><![CDATA[
                                <div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/nicolas-grekas">
                <img src="https://connect.symfony.com/profile/nicolas-grekas.picture" alt="Nicolas Grekas">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/nicolas-grekas">Nicolas Grekas</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/66122">#66122</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66129">#66129</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66131">#66131</a>
                     and                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66133">#66133</a>
                                                </span>
            </div>
</div>
<p>Symfony 8.2 includes lots of <a href="https://symfony.com/blog/new-in-symfony-8-2-performance-improvements" class="reference external">performance improvements</a>, but we keep looking for
new opportunities to <strong>make your applications faster</strong>.</p>
<p>For example, Symfony creates the event dispatcher at runtime for every request
by calling <code translate="no" class="notranslate">addListener()</code> for each listener and wrapping it in a closure,
even for events that the request never dispatches. But Symfony already knows
your application's <a href="https://symfony.com/doc/current/event_dispatcher.html" class="reference external">event listeners</a> when it compiles the container, so this
work can be done ahead of time.</p>
<div class="section">
<h2 id="compiled-event-dispatcher"><a class="headerlink" href="#compiled-event-dispatcher" title="Permalink to this headline">Compiled Event Dispatcher</a></h2>
<p>In Symfony 8.2, the <code translate="no" class="notranslate">event_dispatcher</code> service is a <code translate="no" class="notranslate">CompiledEventDispatcher</code>.
It receives an array of listener service IDs and methods, in the order they run,
and a service locator to load them when needed. PHP's OPcache stores the array
in shared memory, so each request doesn't need its own copy.</p>
<p>In a benchmark with 75 listeners across 31 events, creating the dispatcher
<strong>took 0.48 µs, down from 33.7 µs</strong>. The listener closures previously used about
<strong>97 KB of memory</strong>; the compiled dispatcher doesn't need them.</p>
<p>Dispatching events is as fast as before. Listener services are still created
only when they're about to run. If an event is never dispatched, or a listener
stops its propagation, the remaining listeners aren't instantiated.</p>
<p>Your existing listener and subscriber registrations benefit from this
automatically. The profiler and <code translate="no" class="notranslate">debug:event-dispatcher</code> work as before.</p>
</div>
<div class="section">
<h2 id="changing-listeners-at-runtime-is-deprecated"><a class="headerlink" href="#changing-listeners-at-runtime-is-deprecated" title="Permalink to this headline">Changing Listeners at Runtime Is Deprecated</a></h2>
<p>Adding or removing a listener at runtime forces the compiled dispatcher to
fall back to a regular <code translate="no" class="notranslate">EventDispatcher</code>, losing the performance benefit.
Symfony 8.2 therefore deprecates calling <code translate="no" class="notranslate">addListener()</code>, <code translate="no" class="notranslate">addSubscriber()</code>,
<code translate="no" class="notranslate">removeListener()</code> or <code translate="no" class="notranslate">removeSubscriber()</code> on the shared <code translate="no" class="notranslate">event_dispatcher</code>
service. These calls also trigger deprecations in <code translate="no" class="notranslate">dev</code>, where you can see
them in the profiler.</p>
<p>Register your listeners as services instead. For <strong>temporary listeners</strong>, such as
those needed while a console command runs, use the new <code translate="no" class="notranslate">ScopedEventDispatcher</code>.
It wraps the shared dispatcher and holds the extra listeners without adding them
to the shared service. Only events dispatched through the wrapper reach those
listeners:</p>
<div translate="no" data-loc="9" class="notranslate codeblock codeblock-length-sm codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">EventDispatcher</span>\<span class="hljs-title">ScopedEventDispatcher</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Messenger</span>\<span class="hljs-title">EventListener</span>\<span class="hljs-title">StopWorkerOnMessageLimitListener</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Messenger</span>\<span class="hljs-title">Worker</span>;

<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>dispatcher</span> = <span class="hljs-keyword">new</span> <span class="hljs-title invoke__">ScopedEventDispatcher</span>(<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>this</span>-&gt;eventDispatcher);
<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>dispatcher</span>-&gt;<span class="hljs-title invoke__">addSubscriber</span>(<span class="hljs-keyword">new</span> <span class="hljs-title invoke__">StopWorkerOnMessageLimitListener</span>(<span class="hljs-number">10</span>));

<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>worker</span> = <span class="hljs-keyword">new</span> <span class="hljs-title invoke__">Worker</span>(<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>receivers</span>, <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>bus</span>, <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>dispatcher</span>);
<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>worker</span>-&gt;<span class="hljs-title invoke__">run</span>();</code></pre>
    </div>
</div>
<p>The wrapper calls both sets of listeners in priority order. Symfony uses it in the
<code translate="no" class="notranslate">messenger:consume</code> and <code translate="no" class="notranslate">messenger:failed:retry</code> commands.</p>
<p>Check your functional tests too. If a test adds a listener to the shared
<code translate="no" class="notranslate">event_dispatcher</code> to check that an event was dispatched, register that
listener as a service in the test environment instead.</p>
</div>
<div class="section">
<h2 id="new-autowiring-type-for-the-event-dispatcher"><a class="headerlink" href="#new-autowiring-type-for-the-event-dispatcher" title="Permalink to this headline">New Autowiring Type for the Event Dispatcher</a></h2>
<p>Autowiring the shared dispatcher with
<code translate="no" class="notranslate">Symfony\Component\EventDispatcher\EventDispatcherInterface</code> is also
deprecated, because that interface includes methods for changing listeners.
If your service only dispatches events, <strong>switch to the contracts interface</strong>:</p>
<div translate="no" data-loc="12" class="notranslate codeblock codeblock-length-md codeblock-diff">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-deletion">- use Symfony\Component\EventDispatcher\EventDispatcherInterface;</span>
<span class="hljs-addition">+ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;</span>

class OrderPlacer
{
    public function __construct(
        private EventDispatcherInterface $dispatcher,
    ) {
    }

    // ...
}</code></pre>
    </div>
</div>
<p>To inspect registered listeners, for example in a debugging tool, autowire
<code translate="no" class="notranslate">Symfony\Contracts\EventDispatcher\ListenerIntrospectionInterface</code>. This new
interface provides <code translate="no" class="notranslate">getListeners()</code>, <code translate="no" class="notranslate">getListenerPriority()</code> and
<code translate="no" class="notranslate">hasListeners()</code>. If you also need to dispatch events, combine both interfaces
with an intersection type:</p>
<div translate="no" data-loc="7" class="notranslate codeblock codeblock-length-sm codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">EventDispatcher</span>\<span class="hljs-title">EventDispatcherInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">EventDispatcher</span>\<span class="hljs-title">ListenerIntrospectionInterface</span>;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">(
    <span class="hljs-keyword">private</span> EventDispatcherInterface&amp;ListenerIntrospectionInterface <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>dispatcher</span>,
)</span> </span>{
}</code></pre>
    </div>
</div>
</div>
                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/new-in-symfony-8-2-compiled-event-dispatcher?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Javier Eguiluz ]]></dc:creator>
            <pubDate>Wed, 07 Oct 2026 09:27:00 +0200</pubDate>
            <comments>https://symfony.com/blog/new-in-symfony-8-2-compiled-event-dispatcher?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[SymfonyCon Warsaw 2026: From 14s to 1.8s: A Symfony Cold Start Autopsy]]></title>
            <link>https://symfony.com/blog/symfonycon-warsaw-2026-from-14s-to-1-8s-a-symfony-cold-start-autopsy?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>
    

The ultimate gathering for PHP enthusiasts is heading to Poland! On November 26-27, SymfonyCon Warsaw 2026 delivers two full days of technical insights, 3 parallel tracks, and rich networking opportunities. Reserve your seat with the global community!…</description>
            <content:encoded><![CDATA[
                                <p><a class="block text-center" href="https://live.symfony.com/2026-warsaw-con" title="Nl Blog Banner">
    <img src="https://symfony.com/uploads/assets/blog/NL-BLOG-Banner.png" alt="Nl Blog Banner">
</a>
The ultimate gathering for PHP enthusiasts is heading to Poland! On November 26-27, <strong><a href="https://live.symfony.com/2026-warsaw-con/">SymfonyCon Warsaw 2026</a></strong> delivers two full days of technical insights, 3 parallel tracks, and rich networking opportunities. Reserve your seat with the global community!</p>

<hr />

<h3>🎤 Speaker announcement</h3>

<p>We are thrilled to announce <strong><a href="https://connect.symfony.com/profile/rjanot">Rémi Janot</a></strong>, CTO, Vasco, for the talk <strong><a href="https://live.symfony.com/2026-warsaw-con/schedule/from-14s-to-1-8s-a-symfony-cold-start-autopsy">"From 14s to 1.8s: A Symfony Cold Start Autopsy"</a></strong>. We’re excited to bring this expertise to the stage!</p>

<p>"On Cloud Run, our backend answered its first request in 14 seconds. Almost all of that time went to one place nobody on the team would have guessed, and the profiler alone never found it.</p>

<p>This is the full hunt: the tooling that finally showed us the truth, the framework internals we had to read to understand what we were seeing, and the obvious optimizations that quietly made cold starts worse before anything got better. Image size, autoloading, the compiled container, cache warmup, and the way they interact.</p>

<p>We finished at 1.8 seconds. You'll leave with a method for diagnosing your own cold starts, not a list of tricks to copy."</p>

<p>Click here to see more <strong><a href="https://live.symfony.com/2026-warsaw-con/schedule">talks</a></strong>. The full schedule will be unveiled step-by-step over the coming weeks. Stay tuned!</p>

<h3>Ready to join us?</h3>

<h3>🏨 Accommodation</h3>

<p>The official conference hotel offers special preferential rates and flexible conditions for our attendees. Make sure to use our <strong><a href="https://www.hilton.com/en/book/reservation/rooms/?ctyhocn=WAWHIHI&amp;arrivalDate=2026-11-23&amp;departureDate=2026-11-29&amp;groupCode=GSYMDP&amp;room1NumAdults=1">dedicated link</a></strong> to book your room and stay right where the action happens!</p>

<h3>🥳 Save the date for the Community Party!</h3>

<p>Because SymfonyCon isn't just about code, we are happy to confirm that our traditional Community Party will take place on the evening of <strong>Thursday, November 26</strong>. Get ready for a great night of networking, fun, and connecting with peers!</p>

<h3>💻 Hackday</h3>

<p>Ready to contribute? The Hackday on <strong>Saturday, November 28</strong> (free and open to all!) will take place at "The Brain Embassy - Czackiego" thanks to the support of <a href="https://baksla.sh/">Baksla.sh</a>. Bring your laptop and your good mood!</p>

<h3>🎟️ Get your tickets</h3>

<p>Tickets are available: <strong><a href="https://live.symfony.com/2026-warsaw-con/registration">Secure your ticket today!</a></strong></p>

<hr />

<h3>Join us online!</h3>

<p>💡Follow the "conference" blog posts to not miss anything!</p>

<p>Want the latest Symfony updates? Follow us and tune in from wherever you are 🌎</p>

<p><a class="block text-center" href="https://linktr.ee/symfony">
   <img src="https://symfony.com/uploads/assets/blog/Banner-BLOG.png" alt="Banner Blog">
</a></p>

                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/symfonycon-warsaw-2026-from-14s-to-1-8s-a-symfony-cold-start-autopsy?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Eloïse Charrier ]]></dc:creator>
            <pubDate>Tue, 06 Oct 2026 14:30:00 +0200</pubDate>
            <comments>https://symfony.com/blog/symfonycon-warsaw-2026-from-14s-to-1-8s-a-symfony-cold-start-autopsy?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[New in Symfony 8.2: Relative Ordering for Listeners and Services]]></title>
            <link>https://symfony.com/blog/new-in-symfony-8-2-relative-ordering-for-listeners-and-services?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>
    
                    
                
            
            
    
        Contributed by
                    Nicolas Grekas
                                         in
                                    #66012
                    ,…</description>
            <content:encoded><![CDATA[
                                <div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/nicolas-grekas">
                <img src="https://connect.symfony.com/profile/nicolas-grekas.picture" alt="Nicolas Grekas">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/nicolas-grekas">Nicolas Grekas</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/66012">#66012</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66022">#66022</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66240">#66240</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66236">#66236</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66713">#66713</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66714">#66714</a>
                    ,                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66715">#66715</a>
                     and                                     <a target="_blank" href="https://github.com/symfony/symfony/pull/66718">#66718</a>
                                                </span>
            </div>
</div>
<p>If you've ever needed to run an event listener before one provided by Symfony or
a third-party bundle, you had to find its priority, pick a slightly higher number
and hope that priority doesn't change in a future update.</p>
<p>In Symfony 8.2, you can solve this in a better way: the new <code translate="no" class="notranslate">before</code> and
<code translate="no" class="notranslate">after</code> options let you name the <a href="https://symfony.com/doc/current/event_dispatcher.html" class="reference external">event listeners</a> or <a href="https://symfony.com/doc/current/service_container/tags.html#tagged-services-with-priority" class="reference external">tagged services</a>
that yours should run before or after.</p>
<div class="section">
<h2 id="ordering-event-listeners"><a class="headerlink" href="#ordering-event-listeners" title="Permalink to this headline">Ordering Event Listeners</a></h2>
<p>Suppose your <a href="https://symfony.com/doc/current/event_dispatcher.html" class="reference external">listener</a> sets the <code translate="no" class="notranslate">_locale</code> request attribute. It needs to run
before Symfony's <code translate="no" class="notranslate">LocaleListener</code> reads that attribute to set the request's
locale. You can now declare that directly on your listener:</p>
<div translate="no" data-loc="15" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment">// src/EventListener/RequestLocaleListener.php</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">EventListener</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">EventDispatcher</span>\<span class="hljs-title">Attribute</span>\<span class="hljs-title">AsEventListener</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpKernel</span>\<span class="hljs-title">Event</span>\<span class="hljs-title">RequestEvent</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpKernel</span>\<span class="hljs-title">EventListener</span>\<span class="hljs-title">LocaleListener</span>;

<span class="hljs-meta">#[AsEventListener(<span class="hljs-attr">before</span>: LocaleListener::<span class="hljs-variable language_">class</span>.<span class="hljs-string">'::onKernelRequest'</span>)]</span>
<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RequestLocaleListener</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__invoke</span><span class="hljs-params">(RequestEvent <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>event</span>)</span>: <span class="hljs-title">void</span>
    </span>{
        <span class="hljs-comment">// ...</span>
    }
}</code></pre>
    </div>
</div>
<p>Both options accept a service ID or class name, or an array of them if you need
to refer to several listeners. The <code translate="no" class="notranslate">::onKernelRequest</code> suffix selects a
specific method. This matters here because <code translate="no" class="notranslate">LocaleListener</code> has two methods
that listen to <code translate="no" class="notranslate">kernel.request</code>. Without the suffix, your listener would run
before both of them.</p>
<p>Event subscribers registered as services can use these options too. Symfony 8.2
also lets you use named keys such as <code translate="no" class="notranslate">method</code> and <code translate="no" class="notranslate">priority</code> in
<code translate="no" class="notranslate">getSubscribedEvents()</code>, so you can write:</p>
<div translate="no" data-loc="9" class="notranslate codeblock codeblock-length-sm codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSubscribedEvents</span><span class="hljs-params">()</span>: <span class="hljs-title">array</span>
</span>{
    <span class="hljs-keyword">return</span> [
        KernelEvents::<span class="hljs-variable constant_">REQUEST</span> =&gt; [
            <span class="hljs-string">'method'</span> =&gt; <span class="hljs-string">'onKernelRequest'</span>,
            <span class="hljs-string">'before'</span> =&gt; LocaleListener::<span class="hljs-variable language_">class</span>.<span class="hljs-string">'::onKernelRequest'</span>,
        ],
    ];
}</code></pre>
    </div>
</div>
<p>A few things to keep in mind:</p>
<ul>
    <li>Ordering is resolved when compiling the container, with no extra runtime work;</li>
<li>Leave out the priority to let Symfony choose it. If you set one, constraints
can only reorder listeners within that priority;</li>
<li>References to listeners missing from the event are ignored (this way, you can
support e.g. optional bundles);</li>
<li>Conflicting priorities, circular constraints and invalid methods cause
compilation errors.</li>
</ul>
</div>
<div class="section">
<h2 id="ordering-tagged-services"><a class="headerlink" href="#ordering-tagged-services" title="Permalink to this headline">Ordering Tagged Services</a></h2>
<p>The same options are available when ordering <a href="https://symfony.com/doc/current/service_container/tags.html#tagged-services-with-priority" class="reference external">tagged services</a>. Suppose an import
bundle provides CSV and XLSX handlers with the same priority, and you want to
add your own TSV handler between them. You can express both requirements with
<code translate="no" class="notranslate">AsTaggedItem</code> or in the service's tag configuration:</p>
<div class="configuration-block">
    <div role="tablist" aria-label="Configuration formats" class="configuration-tabs configuration-tabs-length-2">
                    <button role="tab" type="button" data-language="php" aria-controls="configuration-block-tabpanel-b3ea8d3b41f745dfd9e12022c2db34838aa38cee" aria-selected="true" data-active="true">
                <span>PHP</span>
            </button>
                    <button role="tab" type="button" data-language="yaml" aria-controls="configuration-block-tabpanel-3e74d8ce239a21ad44fcf6cf7354de0b96fdce7c" aria-selected="false" tabindex="-1">
                <span>YAML</span>
            </button>
            </div>

            <div role="tabpanel" id="configuration-block-tabpanel-b3ea8d3b41f745dfd9e12022c2db34838aa38cee" aria-label="PHP" class="configuration-codeblock" data-language="php" style="">
            <div translate="no" data-loc="12" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment">// src/Handler/TsvHandler.php</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Handler</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Acme</span>\<span class="hljs-title">ImportBundle</span>\<span class="hljs-title">Handler</span>\<span class="hljs-title">CsvHandler</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Acme</span>\<span class="hljs-title">ImportBundle</span>\<span class="hljs-title">Handler</span>\<span class="hljs-title">XlsxHandler</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">DependencyInjection</span>\<span class="hljs-title">Attribute</span>\<span class="hljs-title">AsTaggedItem</span>;

<span class="hljs-meta">#[AsTaggedItem(<span class="hljs-attr">after</span>: CsvHandler::<span class="hljs-variable language_">class</span>, <span class="hljs-attr">before</span>: XlsxHandler::<span class="hljs-variable language_">class</span>)]</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TsvHandler</span>
</span>{
    <span class="hljs-comment">// ...</span>
}</code></pre>
    </div>
</div>
        </div>
            <div role="tabpanel" id="configuration-block-tabpanel-3e74d8ce239a21ad44fcf6cf7354de0b96fdce7c" aria-label="YAML" class="configuration-codeblock" data-language="yaml" style="display: none">
            <div translate="no" data-loc="7" class="notranslate codeblock codeblock-length-sm codeblock-yaml">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment"># config/services.yaml</span>
<span class="hljs-attr">services:</span>
    <span class="hljs-string">App\Handler\TsvHandler:</span>
        <span class="hljs-attr">tags:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">'app.handler'</span>
              <span class="hljs-attr">after:</span> <span class="hljs-string">'Acme\ImportBundle\Handler\CsvHandler'</span>
              <span class="hljs-attr">before:</span> <span class="hljs-string">'Acme\ImportBundle\Handler\XlsxHandler'</span></code></pre>
    </div>
</div>
        </div>
    </div>
<p>In the PHP example, the handler must already have the tag used by the import
bundle, for example through <a href="https://symfony.com/doc/current/service_container.html#the-autoconfigure-option" class="reference external">autoconfiguration</a>. <code translate="no" class="notranslate">AsTaggedItem</code> configures its
order; it doesn't add the tag itself.</p>
</div>
<div class="section">
<h2 id="ordering-decorators"><a class="headerlink" href="#ordering-decorators" title="Permalink to this headline">Ordering Decorators</a></h2>
<p><a href="https://symfony.com/doc/current/service_container/decoration.html" class="reference external">Service decorators</a> had the same problem. When several decorators wrap a service,
their priorities define which one is closer to the original service. To put yours
in the right place, you had to check the priorities of the other decorators.</p>
<p>Symfony 8.2 adds two options for that: <code translate="no" class="notranslate">within</code> lists the decorators that
wrap yours, and <code translate="no" class="notranslate">around</code> lists the decorators that yours wraps. Suppose you
sign every outgoing HTTP request and want each retry to be signed again. Your
decorator must be inside Symfony's <code translate="no" class="notranslate">RetryableHttpClient</code>:</p>
<div class="configuration-block">
    <div role="tablist" aria-label="Configuration formats" class="configuration-tabs configuration-tabs-length-2">
                    <button role="tab" type="button" data-language="php" aria-controls="configuration-block-tabpanel-870d6a6c6b782272c7c35018e7098cbd1cd1d44d" aria-selected="true" data-active="true">
                <span>PHP</span>
            </button>
                    <button role="tab" type="button" data-language="yaml" aria-controls="configuration-block-tabpanel-ea4071709f37faeda8231f62f81ef9f14c7d18d8" aria-selected="false" tabindex="-1">
                <span>YAML</span>
            </button>
            </div>

            <div role="tabpanel" id="configuration-block-tabpanel-870d6a6c6b782272c7c35018e7098cbd1cd1d44d" aria-label="PHP" class="configuration-codeblock" data-language="php" style="">
            <div translate="no" data-loc="12" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment">// src/HttpClient/SigningHttpClient.php</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">HttpClient</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">DependencyInjection</span>\<span class="hljs-title">Attribute</span>\<span class="hljs-title">AsDecorator</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpClient</span>\<span class="hljs-title">RetryableHttpClient</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">HttpClient</span>\<span class="hljs-title">HttpClientInterface</span>;

<span class="hljs-meta">#[AsDecorator(<span class="hljs-string">'http_client'</span>, <span class="hljs-attr">within</span>: RetryableHttpClient::<span class="hljs-variable language_">class</span>)]</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SigningHttpClient</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HttpClientInterface</span>
</span>{
    <span class="hljs-comment">// ...</span>
}</code></pre>
    </div>
</div>
        </div>
            <div role="tabpanel" id="configuration-block-tabpanel-ea4071709f37faeda8231f62f81ef9f14c7d18d8" aria-label="YAML" class="configuration-codeblock" data-language="yaml" style="display: none">
            <div translate="no" data-loc="5" class="notranslate codeblock codeblock-length-sm codeblock-yaml">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment"># config/services.yaml</span>
<span class="hljs-attr">services:</span>
    <span class="hljs-string">App\HttpClient\SigningHttpClient:</span>
        <span class="hljs-attr">decorates:</span> <span class="hljs-string">http_client</span>
        <span class="hljs-attr">decoration_within:</span> <span class="hljs-string">http_client.retryable</span></code></pre>
    </div>
</div>
        </div>
    </div>
<p>These options work the same way as <code translate="no" class="notranslate">before</code> and <code translate="no" class="notranslate">after</code>: they accept service
IDs or class names (or a list of them), names that don't match any other
decorator of the same service are ignored, and if you leave out the priority,
Symfony chooses it for you. They also work with <code translate="no" class="notranslate">#[AsTagDecorator]</code> when
decorating all services with a given tag.</p>
</div>
<div class="section">
<h2 id="ordering-doctrine-listeners-and-messenger-handlers"><a class="headerlink" href="#ordering-doctrine-listeners-and-messenger-handlers" title="Permalink to this headline">Ordering Doctrine Listeners and Messenger Handlers</a></h2>
<p>Doctrine event listeners and Messenger handlers are ordered by priority too, and
they get the same <code translate="no" class="notranslate">before</code> and <code translate="no" class="notranslate">after</code> options. The <code translate="no" class="notranslate">doctrine.event_listener</code>
tag uses them to order the listeners of an event on a connection:</p>
<div translate="no" data-loc="7" class="notranslate codeblock codeblock-length-sm codeblock-yaml">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment"># config/services.yaml</span>
<span class="hljs-attr">services:</span>
    <span class="hljs-string">App\EventListener\SearchIndexer:</span>
        <span class="hljs-attr">tags:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">'doctrine.event_listener'</span>
              <span class="hljs-attr">event:</span> <span class="hljs-string">'postPersist'</span>
              <span class="hljs-attr">after:</span> <span class="hljs-string">'App\EventListener\AuditLogger'</span></code></pre>
    </div>
</div>
<p>Support for these options in the <code translate="no" class="notranslate">#[AsDoctrineListener]</code> attribute is
<a href="https://github.com/doctrine/DoctrineBundle/pull/2301" class="reference external" rel="external noopener noreferrer" target="_blank">proposed in DoctrineBundle</a>.</p>
<p>The <code translate="no" class="notranslate">#[AsMessageHandler]</code> attribute and the <code translate="no" class="notranslate">messenger.message_handler</code> tag
use them to order the handlers of a message on a bus:</p>
<div translate="no" data-loc="14" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment">// src/MessageHandler/SendWelcomeEmailHandler.php</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">MessageHandler</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Message</span>\<span class="hljs-title">UserRegistered</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Messenger</span>\<span class="hljs-title">Attribute</span>\<span class="hljs-title">AsMessageHandler</span>;

<span class="hljs-meta">#[AsMessageHandler(<span class="hljs-attr">after</span>: AuditLogHandler::<span class="hljs-variable language_">class</span>)]</span>
<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SendWelcomeEmailHandler</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__invoke</span><span class="hljs-params">(UserRegistered <span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>message</span>)</span>: <span class="hljs-title">void</span>
    </span>{
        <span class="hljs-comment">// ...</span>
    }
}</code></pre>
    </div>
</div>
<p>Constraints only apply between handlers of the same message class. Handlers of a
parent class, of an interface, or registered for <code translate="no" class="notranslate">*</code> can't be referenced.</p>
</div>
<div class="section">
<h2 id="ordering-firewall-listeners"><a class="headerlink" href="#ordering-firewall-listeners" title="Permalink to this headline">Ordering Firewall Listeners</a></h2>
<p>Bundles that add <a href="https://symfony.com/doc/current/security.html" class="reference external">firewall listeners</a>, for example to handle two-factor
authentication, also had to pick priorities relative to Symfony's own listeners.
The new <code translate="no" class="notranslate">#[FirewallListenerOrder]</code> attribute lets them name those listeners
instead:</p>
<div translate="no" data-loc="10" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Security</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Attribute</span>\<span class="hljs-title">FirewallListenerOrder</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Security</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Firewall</span>\<span class="hljs-title">AbstractListener</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Security</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Firewall</span>\<span class="hljs-title">AccessListener</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Security</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Firewall</span>\<span class="hljs-title">ContextListener</span>;

<span class="hljs-meta">#[FirewallListenerOrder(<span class="hljs-attr">after</span>: ContextListener::<span class="hljs-variable language_">class</span>, <span class="hljs-attr">before</span>: AccessListener::<span class="hljs-variable language_">class</span>)]</span>
<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TwoFactorListener</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractListener</span>
</span>{
    <span class="hljs-comment">// ...</span>
}</code></pre>
    </div>
</div>
<p>Firewall listeners always have a priority, so these constraints only reorder the
listeners that share it. A constraint that would need a different priority makes
compiling the container fail. This way, a bundle can't move Symfony's own
security listeners by mistake.</p>
</div>
<div class="section">
<h2 id="using-them-as-safety-checks"><a class="headerlink" href="#using-them-as-safety-checks" title="Permalink to this headline">Using Them as Safety Checks</a></h2>
<p>You can also keep an explicit priority and add <code translate="no" class="notranslate">before</code> or <code translate="no" class="notranslate">after</code> as a
check. Symfony now does this for its own listeners and argument value resolvers
whose priority was chosen relative to another one. For example, the resolvers of
<code translate="no" class="notranslate">Request</code>, <code translate="no" class="notranslate">Session</code> and <code translate="no" class="notranslate">#[CurrentUser]</code> arguments declare that they run
before Doctrine's <code translate="no" class="notranslate">EntityValueResolver</code>. Their priorities didn't change, but if
one of them is ever lowered below the Doctrine one, compiling the container fails
instead of silently changing which resolver handles those arguments.</p>
<p>For more examples, see the docs on <a href="https://symfony.com/doc/8.2/event_dispatcher.html#ordering-event-listeners" class="reference external">ordering event listeners</a>,
<a href="https://symfony.com/doc/8.2/service_container/tags.html#tagged-services-with-ordering-constraints" class="reference external">ordering tagged services</a> and <a href="https://symfony.com/doc/8.2/service_container/decoration.html#placing-decorators-relative-to-each-other" class="reference external">ordering decorators</a>.</p>
</div>
                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/new-in-symfony-8-2-relative-ordering-for-listeners-and-services?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Javier Eguiluz ]]></dc:creator>
            <pubDate>Tue, 06 Oct 2026 09:23:00 +0200</pubDate>
            <comments>https://symfony.com/blog/new-in-symfony-8-2-relative-ordering-for-listeners-and-services?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[SymfonyCon Warsaw 2026: final class Entity: Doctrine Mapping for Modern PHP]]></title>
            <link>https://symfony.com/blog/symfonycon-warsaw-2026-final-class-entity-doctrine-mapping-for-modern-php?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>
    

Connect with the global developer ecosystem at SymfonyCon Warsaw 2026, taking place November 26-27 in Poland. Dive into two days of intense learning across 3 parallel tracks alongside vibrant community side-events. Secure your spot today!



🎤 Speaker…</description>
            <content:encoded><![CDATA[
                                <p><a class="block text-center" href="https://live.symfony.com/2026-warsaw-con" title="Nl Blog Banner">
    <img src="https://symfony.com/uploads/assets/blog/NL-BLOG-Banner.png" alt="Nl Blog Banner">
</a>
Connect with the global developer ecosystem at <strong><a href="https://live.symfony.com/2026-warsaw-con/">SymfonyCon Warsaw 2026</a></strong>, taking place November 26-27 in Poland. Dive into two days of intense learning across 3 parallel tracks alongside vibrant community side-events. Secure your spot today!</p>

<hr />

<h3>🎤 Speaker announcement</h3>

<p>Please welcome <strong><a href="https://connect.symfony.com/profile/derrabus">Alexander M. Turek</a></strong>, CTO, SensioLabs Deutschland. Join us to catch the talk <strong><a href="https://live.symfony.com/2026-warsaw-con/schedule/final-class-entity">"final class Entity: Doctrine Mapping for Modern PHP"</a></strong>.</p>

<p>"For fifteen years, Doctrine shaped the way we write entities, and not always for the better. Entities could not be final, because proxies had to extend them. Every field grew a getter and a setter. Domain concepts like money, addresses and identifiers ended up as strings and floats, because mapping anything richer was more trouble than it was worth.</p>

<p>None of that was a design decision. Those were workarounds for things PHP could not express yet.</p>

<p>It can now. Attributes, backed enums, property hooks, asymmetric visibility, native lazy objects, and an arbitrary-precision number object in core. Doctrine ORM 3.4 and DBAL 4.3 pick all of it up, and ORM 4 will be built on it.</p>

<p>We take one realistic entity, too many lines of accessors and primitives, and refactor it live on the slides: final classes, no setters, enums, typed identifiers, embedded value objects, custom DBAL types that register themselves. Same database schema at the end. No migration. Considerably less code."</p>

<p>Click here to see more <strong><a href="https://live.symfony.com/2026-warsaw-con/schedule">talks</a></strong>. The full schedule will be unveiled step-by-step over the coming weeks. Stay tuned!</p>

<h3>Ready to join us?</h3>

<h3>🏨 Accommodation</h3>

<p>The official conference hotel offers special preferential rates and flexible conditions for our attendees. Make sure to use our <strong><a href="https://www.hilton.com/en/book/reservation/rooms/?ctyhocn=WAWHIHI&amp;arrivalDate=2026-11-23&amp;departureDate=2026-11-29&amp;groupCode=GSYMDP&amp;room1NumAdults=1">dedicated link</a></strong> to book your room and stay right where the action happens!</p>

<h3>🥳 Save the date for the Community Party!</h3>

<p>Because SymfonyCon isn't just about code, we are happy to confirm that our traditional Community Party will take place on the evening of <strong>Thursday, November 26</strong>. Get ready for a great night of networking, fun, and connecting with peers!</p>

<h3>💻 Hackday</h3>

<p>Ready to contribute? The Hackday on <strong>Saturday, November 28</strong> (free and open to all!) will take place at "The Brain Embassy - Czackiego" thanks to the support of <a href="https://baksla.sh/">Baksla.sh</a>. Bring your laptop and your good mood!</p>

<h3>🎟️ Get your tickets</h3>

<p>Tickets are available: <a href="https://live.symfony.com/2026-warsaw-con/registration">Secure your ticket today!</a>**</p>

<hr />

<h3>Join us online!</h3>

<p>💡Follow the "conference" blog posts to not miss anything!</p>

<p>Want the latest Symfony updates? Follow us and tune in from wherever you are 🌎</p>

<p><a class="block text-center" href="https://linktr.ee/symfony">
   <img src="https://symfony.com/uploads/assets/blog/Banner-BLOG.png" alt="Banner Blog">
</a></p>

                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/symfonycon-warsaw-2026-final-class-entity-doctrine-mapping-for-modern-php?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Eloïse Charrier ]]></dc:creator>
            <pubDate>Mon, 05 Oct 2026 17:30:00 +0200</pubDate>
            <comments>https://symfony.com/blog/symfonycon-warsaw-2026-final-class-entity-doctrine-mapping-for-modern-php?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[New in Symfony 8.2: Targeted Cache-Control and Cache-Status Headers]]></title>
            <link>https://symfony.com/blog/new-in-symfony-8-2-targeted-cache-control-and-cache-status-headers?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>An HTTP response can pass through several caches before it reaches the user,
and you may want different rules for each one. Symfony 8.2 adds support for two
HTTP headers: one to set those rules, and another to see what happened to a
request.

Targeted Cache-Control…</description>
            <content:encoded><![CDATA[
                                <p>An HTTP response can pass through several caches before it reaches the user,
and you may want different rules for each one. <strong>Symfony 8.2 adds support for two
HTTP headers</strong>: one to set those rules, and another to see what happened to a
request.</p>
<div class="section">
<h2 id="targeted-cache-control-headers"><a class="headerlink" href="#targeted-cache-control-headers" title="Permalink to this headline">Targeted Cache-Control Headers</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/nicolas-grekas">
                <img src="https://connect.symfony.com/profile/nicolas-grekas.picture" alt="Nicolas Grekas">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/nicolas-grekas">Nicolas Grekas</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/65282">#65282</a>
                                                </span>
            </div>
</div>
<p>You might want your CDN to cache a page for an hour, while keeping a much
shorter cache lifetime in the browser. That's because you can purge the CDN
cache when the content changes, but you can't purge the copies stored in your
visitors' browsers. <strong>Targeted cache-control headers</strong>, defined in
<a href="https://www.rfc-editor.org/rfc/rfc9213.html" class="reference external" rel="external noopener noreferrer" target="_blank">RFC 9213</a>, let you give each cache its own rules.</p>
<p>For example, a CDN that supports <code translate="no" class="notranslate">CDN-Cache-Control</code> uses it instead of
<code translate="no" class="notranslate">Cache-Control</code>. Browsers continue to use <code translate="no" class="notranslate">Cache-Control</code>.
In Symfony 8.2, call the new <code translate="no" class="notranslate">cacheControl()</code> method on a <code translate="no" class="notranslate">Response</code> with
the target name (<code translate="no" class="notranslate">CDN</code>, not <code translate="no" class="notranslate">CDN-Cache-Control</code>):</p>
<div translate="no" data-loc="7" class="notranslate codeblock codeblock-length-sm codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment">// browsers consider the response stale immediately...</span>
<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>response</span>-&gt;<span class="hljs-title invoke__">setMaxAge</span>(<span class="hljs-number">0</span>)-&gt;<span class="hljs-title invoke__">setPrivate</span>();

<span class="hljs-comment">// ...but the CDN can cache it for one hour</span>
<span class="hljs-variable"><span class="hljs-variable-other-marker">$</span>response</span>-&gt;<span class="hljs-title invoke__">cacheControl</span>(<span class="hljs-string">'CDN'</span>)
    -&gt;<span class="hljs-title invoke__">setMaxAge</span>(<span class="hljs-number">3600</span>)
    -&gt;<span class="hljs-title invoke__">setStaleWhileRevalidate</span>(<span class="hljs-number">60</span>);</code></pre>
    </div>
</div>
<p>This code generates the following headers:</p>
<div translate="no" data-loc="2" class="notranslate codeblock codeblock-length-sm codeblock-text">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code>Cache-Control: max-age=0, private
CDN-Cache-Control: max-age=3600, stale-while-revalidate=60</code></pre>
    </div>
</div>
<p>You can use methods such as <code translate="no" class="notranslate">setPublic()</code>, <code translate="no" class="notranslate">setPrivate()</code> and
<code translate="no" class="notranslate">setStaleIfError()</code> on the returned object, or <code translate="no" class="notranslate">set()</code> for other directives.
Use <code translate="no" class="notranslate">setMaxAge()</code> for the lifetime: there's no <code translate="no" class="notranslate">setSharedMaxAge()</code> because
the target already identifies the cache these rules apply to.</p>
</div>
<div class="section">
<h2 id="the-cache-status-header"><a class="headerlink" href="#the-cache-status-header" title="Permalink to this headline">The Cache-Status Header</a></h2>
<div class="blog-post-contributor-info">
    <div class="blog-post-contributor-avatar">
                    <a target="_blank" href="https://connect.symfony.com/profile/Amoifr">
                <img src="https://connect.symfony.com/profile/Amoifr.picture" alt="Pascal CESCON">
            </a>
            </div>
    <div class="blog-post-contributor-contents">
        <span>Contributed by</span>
                    <a target="_blank" class="blog-post-contributor-name" href="https://connect.symfony.com/profile/Amoifr">Pascal CESCON</a>
                                        <span class="blog-post-contributor-prs"> in
                                    <a target="_blank" href="https://github.com/symfony/symfony/pull/65573">#65573</a>
                                                </span>
            </div>
</div>
<p>When you're debugging HTTP caching, you need to know whether a cache served
the response or forwarded the request to your application. The <code translate="no" class="notranslate">Cache-Status</code>
header, defined in <a href="https://www.rfc-editor.org/rfc/rfc9211.html" class="reference external" rel="external noopener noreferrer" target="_blank">RFC 9211</a>, gives caches a common way to report this.</p>
<p>To enable it in <a href="https://symfony.com/doc/current/http_cache.html" class="reference external">Symfony's HTTP cache</a>, set the new <code translate="no" class="notranslate">cache_status</code> option
to the name you want to use for your cache:</p>
<div class="configuration-block">
    <div role="tablist" aria-label="Configuration formats" class="configuration-tabs configuration-tabs-length-2">
                    <button role="tab" type="button" data-language="yaml" aria-controls="configuration-block-tabpanel-31f4efab623942f22144a7857a740d7e7c228929" aria-selected="true" data-active="true">
                <span>YAML</span>
            </button>
                    <button role="tab" type="button" data-language="php" aria-controls="configuration-block-tabpanel-dd64b5f3a4df576df200085956986fc3509c5585" aria-selected="false" tabindex="-1">
                <span>PHP</span>
            </button>
            </div>

            <div role="tabpanel" id="configuration-block-tabpanel-31f4efab623942f22144a7857a740d7e7c228929" aria-label="YAML" class="configuration-codeblock" data-language="yaml" style="">
            <div translate="no" data-loc="5" class="notranslate codeblock codeblock-length-sm codeblock-yaml">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment"># config/packages/framework.yaml</span>
<span class="hljs-attr">framework:</span>
    <span class="hljs-attr">http_cache:</span>
        <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
        <span class="hljs-attr">cache_status:</span> <span class="hljs-string">'Symfony'</span></code></pre>
    </div>
</div>
        </div>
            <div role="tabpanel" id="configuration-block-tabpanel-dd64b5f3a4df576df200085956986fc3509c5585" aria-label="PHP" class="configuration-codeblock" data-language="php" style="display: none">
            <div translate="no" data-loc="11" class="notranslate codeblock codeblock-length-md codeblock-php">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code><span class="hljs-comment">// config/packages/framework.php</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">DependencyInjection</span>\<span class="hljs-title">Loader</span>\<span class="hljs-title">Configurator</span>;

<span class="hljs-keyword">return</span> App::<span class="hljs-title invoke__">config</span>([
    <span class="hljs-string">'framework'</span> =&gt; [
        <span class="hljs-string">'http_cache'</span> =&gt; [
            <span class="hljs-string">'enabled'</span> =&gt; <span class="hljs-keyword">true</span>,
            <span class="hljs-string">'cache_status'</span> =&gt; <span class="hljs-string">'Symfony'</span>,
        ],
    ],
]);</code></pre>
    </div>
</div>
        </div>
    </div>
<p>With this configuration, responses include a <code translate="no" class="notranslate">Cache-Status</code> header such as:</p>
<div translate="no" data-loc="3" class="notranslate codeblock codeblock-length-sm codeblock-text">
        <div class="codeblock-scroll">
        
        <pre class="codeblock-code"><code>Cache-Status: Symfony; hit; ttl=58
Cache-Status: Symfony; fwd=miss; stored
Cache-Status: Symfony; fwd=stale; fwd-status=304; stored</code></pre>
    </div>
</div>
<p>The first example is a cache hit with 58 seconds of freshness left. The second
is a cache miss: Symfony fetched the response from your application and stored
it. In the third, the cached response was stale, but the application returned
<code translate="no" class="notranslate">304 Not Modified</code>, so Symfony could reuse it. A negative <code translate="no" class="notranslate">ttl</code> means the
cache served a stale response.</p>
<p>If another cache has already added a <code translate="no" class="notranslate">Cache-Status</code> header, Symfony appends
its own entry, so you can follow the response through the caches.</p>
<p>You can enable this header in production, unlike the <code translate="no" class="notranslate">X-Symfony-Cache</code>
debug header. It's disabled by default (<code translate="no" class="notranslate">cache_status: null</code>), since it
exposes details about your cache that you may not want to share publicly.</p>
</div>
                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/new-in-symfony-8-2-targeted-cache-control-and-cache-status-headers?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Javier Eguiluz ]]></dc:creator>
            <pubDate>Mon, 05 Oct 2026 09:19:00 +0200</pubDate>
            <comments>https://symfony.com/blog/new-in-symfony-8-2-targeted-cache-control-and-cache-status-headers?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[A Week of Symfony #1031 (September 28 – October 4, 2026)]]></title>
            <link>https://symfony.com/blog/a-week-of-symfony-1031-september-28-october-4-2026?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>This week, Symfony 6.4.47, 7.4.20, and 8.1.8 were released, along with Symfony Reprise 1.3.0. Meanwhile, we continued introducing Symfony 8.2 features, including OpenID Connect login, PGP/MIME signed and encrypted emails, sudo mode, more flexible serialization…</description>
            <content:encoded><![CDATA[
                                <p>This week, Symfony <a href="https://symfony.com/blog/symfony-6-4-47-released" class="reference external">6.4.47</a>, <a href="https://symfony.com/blog/symfony-7-4-20-released" class="reference external">7.4.20</a>, and <a href="https://symfony.com/blog/symfony-8-1-8-released" class="reference external">8.1.8</a> were released, along with <a href="https://symfony.com/blog/symfony-reprise-1-3-0-released" class="reference external">Symfony Reprise 1.3.0</a>. Meanwhile, we continued introducing Symfony 8.2 features, including <a href="https://symfony.com/blog/new-in-symfony-8-2-openid-connect-login" class="reference external">OpenID Connect login</a>, <a href="https://symfony.com/blog/new-in-symfony-8-2-pgp-mime-signed-and-encrypted-emails" class="reference external">PGP/MIME signed and encrypted emails</a>, <a href="https://symfony.com/blog/new-in-symfony-8-2-sudo-mode" class="reference external">sudo mode</a>, <a href="https://symfony.com/blog/new-in-symfony-8-2-more-flexible-serialization-groups" class="reference external">more flexible serialization groups</a>, and <a href="https://symfony.com/blog/new-in-symfony-8-2-performance-improvements" class="reference external">performance improvements</a>. Finally, we announced more talks for <a href="https://live.symfony.com/2026-warsaw-con/" class="reference external">SymfonyCon Warsaw 2026</a>.</p>
<div class="section">
<h2 id="symfony-development-highlights"><a class="headerlink" href="#symfony-development-highlights" title="Permalink to this headline">Symfony development highlights</a></h2>
<p>This week, 364 pull requests were merged (191 in code, 63 in docs, 101 in UX and 9 in AI) and 92 issues were closed (33 in code, 47 in docs, 8 in UX and 4 in AI). Excluding merges, 67 authors made additions and deletions. See details for <a href="https://github.com/symfony/symfony/pulse" class="reference external" rel="external noopener noreferrer" target="_blank">code</a>, <a href="https://github.com/symfony/symfony-docs/pulse" class="reference external" rel="external noopener noreferrer" target="_blank">docs</a>, <a href="https://github.com/symfony/ux/pulse" class="reference external" rel="external noopener noreferrer" target="_blank">UX</a> and <a href="https://github.com/symfony/ai/pulse" class="reference external" rel="external noopener noreferrer" target="_blank">AI</a>.</p>
<p><a href="https://github.com/symfony/symfony/commits/6.4" class="reference external" rel="external noopener noreferrer" target="_blank">6.4 changelog</a>:</p>
<ul>
    <li><a href="https://github.com/symfony/symfony/commit/7a9b16465148403c7ffe982c5544c94a7934cc09" class="reference external" rel="external noopener noreferrer" target="_blank">7a9b164</a>: [Serializer] fix the cache key of MetadataAwareNameConverter when the context can't be serialized</li>
<li><a href="https://github.com/symfony/symfony/commit/a7fe780d9bf29b17fe908e514b63ec660a8b67c9" class="reference external" rel="external noopener noreferrer" target="_blank">a7fe780</a>: [FrameworkBundle] disable HTTP/2 push on the default HTTP client</li>
<li><a href="https://github.com/symfony/symfony/commit/410b9c3bf7eab9ca6717c967dcfab02894af8003" class="reference external" rel="external noopener noreferrer" target="_blank">410b9c3</a>: [HttpKernel] fix the log level of exceptions mapped to an HTTP status code</li>
<li><a href="https://github.com/symfony/symfony/commit/7e59fe05a5bc99bbad132b15fc8af528d788dd9e" class="reference external" rel="external noopener noreferrer" target="_blank">7e59fe0</a>: [Serializer] don't include the debug trace id in the attributes cache key</li>
<li><a href="https://github.com/symfony/symfony/commit/243d1730af6dfdead95638030bfd9cb883195f83" class="reference external" rel="external noopener noreferrer" target="_blank">243d173</a>: [DoctrineBridge] never claim an object as a collection key type</li>
<li><a href="https://github.com/symfony/symfony/commit/2b7cf9134e22a59f2d1ca465bc833a67ff05c94d" class="reference external" rel="external noopener noreferrer" target="_blank">2b7cf91</a>: [WebProfilerBundle] escape the workflow diagram source and listener map in the profiler</li>
<li><a href="https://github.com/symfony/symfony/commit/cfbee39dd9f81d762b5a1bddad5291a3eaf72f37" class="reference external" rel="external noopener noreferrer" target="_blank">cfbee39</a>: [DoctrineBridge] don't map the uuid and ulid type names to uid classes in DoctrineExtractor</li>
<li><a href="https://github.com/symfony/symfony/commit/983d5a5e7849e06f92529b2c811c189afb19dd40" class="reference external" rel="external noopener noreferrer" target="_blank">983d5a5</a>: [Cache] escape glob characters when clearing Redis namespaces</li>
<li><a href="https://github.com/symfony/symfony/commit/35f513ecc7839e38cfd663f425d22a2ed67f1235" class="reference external" rel="external noopener noreferrer" target="_blank">35f513e</a>: [DependencyInjection] export the service id when sharing a circular wither service</li>
<li><a href="https://github.com/symfony/symfony/commit/f8e2d141185d86c0db4d833b0ee23af9a379ff47" class="reference external" rel="external noopener noreferrer" target="_blank">f8e2d14</a>: [FrameworkBundle] fix the description of an empty webhook routing secret</li>
<li><a href="https://github.com/symfony/symfony/commit/60cf68377354efae4fe717f1adba34cd8f3b50a8" class="reference external" rel="external noopener noreferrer" target="_blank">60cf683</a>: [DependencyInjection, Routing] escape identifiers in generated PHP</li>
<li><a href="https://github.com/symfony/symfony/commit/ce086d41d84a222ae1fc890541560b6e55e770e1" class="reference external" rel="external noopener noreferrer" target="_blank">ce086d4</a>: [DependencyInjection] track env placeholders reused after a previous extension dropped them</li>
<li><a href="https://github.com/symfony/symfony/commit/b53068584df068b9abfe5e93491a8ba35f983f59" class="reference external" rel="external noopener noreferrer" target="_blank">b530685</a>: [String] update wcswidth data with Unicode 18</li>
<li><a href="https://github.com/symfony/symfony/commit/3172f3f7c8f68bb01f0379688a8ad44fa2feb290" class="reference external" rel="external noopener noreferrer" target="_blank">3172f3f</a>: [String] fix the width of emoji sequences and conjoining Hangul jamo</li>
<li><a href="https://github.com/symfony/symfony/commit/be608ca12e992943a31be317d72d4e2ea9a238b4" class="reference external" rel="external noopener noreferrer" target="_blank">be608ca</a>: [Messenger] fix decoding ErrorDetailsStamp with Serializer::create()</li>
<li><a href="https://github.com/symfony/symfony/commit/af9e4e491cf764dc0f62f2cf5f00e9e8205d4c1d" class="reference external" rel="external noopener noreferrer" target="_blank">af9e4e4</a>: [HttpClient] cap the timeout passed to curl_multi_select()</li>
<li><a href="https://github.com/symfony/symfony/commit/6ad469dd30bd76c3e8860451d29ef67732e3c08a" class="reference external" rel="external noopener noreferrer" target="_blank">6ad469d</a>: [Messenger] fix decoding ErrorDetailsStamp with the XML format</li>
<li><a href="https://github.com/symfony/symfony/commit/6aa5b27b0f0b36ddc8c125f7071385d50da248ef" class="reference external" rel="external noopener noreferrer" target="_blank">6aa5b27</a>: [Messenger] don't send handler results to transports</li>
<li><a href="https://github.com/symfony/symfony/commit/db66f78576ed3a6891fd963ebbcf1d7fe345b417" class="reference external" rel="external noopener noreferrer" target="_blank">db66f78</a>: [Messenger] turn any error thrown while decoding into a MessageDecodingFailedException</li>
<li><a href="https://github.com/symfony/symfony/commit/c58810850ebc9a369fe70fbe39b3785bf722d0cf" class="reference external" rel="external noopener noreferrer" target="_blank">c588108</a>: [Messenger] fix decoding in XML an ErrorDetailsStamp that has no FlattenException</li>
<li><a href="https://github.com/symfony/symfony/commit/fe8998a3f1ff4c2aa196ab0ff4749c17b31b6e39" class="reference external" rel="external noopener noreferrer" target="_blank">fe8998a</a>: [Messenger] fix decoding in XML a ValidationStamp that has one group or none</li>
<li><a href="https://github.com/symfony/symfony/commit/fff4db54a436471cf1c167bac4d02ee61f76d789" class="reference external" rel="external noopener noreferrer" target="_blank">fff4db5</a>: [Messenger] fix recognizing a repeated error when its code does not keep its type in XML</li>
<li><a href="https://github.com/symfony/symfony/commit/82fab8aa090c1f492963d9757e405539bde6cb12" class="reference external" rel="external noopener noreferrer" target="_blank">82fab8a</a>: [Messenger] fix decoding a ValidationStamp that holds a GroupSequence</li>
<li><a href="https://github.com/symfony/symfony/commit/983971e6479dfab8819386cab720b026121a2d5b" class="reference external" rel="external noopener noreferrer" target="_blank">983971e</a>: [HttpFoundation] fix HeaderUtils::split() when a separator is a whitespace character</li>
<li><a href="https://github.com/symfony/symfony/commit/c2aee896d9d1146ec8c42d1d1954f2fb598d3662" class="reference external" rel="external noopener noreferrer" target="_blank">c2aee89</a>: [String] fix width() of skin tones on keycap and text-default bases, and of format characters</li>
<li><a href="https://github.com/symfony/symfony/commit/7a5c6a75d53d9806e1a6e1be459a0124fa833ad3" class="reference external" rel="external noopener noreferrer" target="_blank">7a5c6a7</a>: [Messenger] fix moving a message between transports that use different serialization formats</li>
<li><a href="https://github.com/symfony/symfony/commit/e465d4558b64443d83037e1278f7e185fbf02c3b" class="reference external" rel="external noopener noreferrer" target="_blank">e465d45</a>: [String] fix width() of OSC sequences terminated by BEL</li>
<li><a href="https://github.com/symfony/symfony/commit/16c8fdb75df8af3e4d8210fcf2849f108019422b" class="reference external" rel="external noopener noreferrer" target="_blank">16c8fdb</a>: [String] fix width() of escape sequences with an intermediate or a digit final byte</li>
<li><a href="https://github.com/symfony/symfony/commit/2a5c8f76a645fddb0a7bab4d2030e9c1e6a66cee" class="reference external" rel="external noopener noreferrer" target="_blank">2a5c8f7</a>: [Yaml] fix round-tripping literal blocks that start with spaces-only lines</li>
<li><a href="https://github.com/symfony/symfony/commit/32d3f8e3f74623da2a8f18e0d3777643f8fc625e" class="reference external" rel="external noopener noreferrer" target="_blank">32d3f8e</a>: [PhpUnitBridge] remove silencing of __sleep/wakeup() deprecations</li>
<li><a href="https://github.com/symfony/symfony/commit/4800ae850758464593e0317899a61fdeb995ae77" class="reference external" rel="external noopener noreferrer" target="_blank">4800ae8</a>: [Messenger] reject decoded messages that carry non-sendable stamps and validate the stamps of unserialized envelopes</li>
<li><a href="https://github.com/symfony/symfony/commit/f4d6d8baf70ae0ed20c90ed8bad44c5e6afc452f" class="reference external" rel="external noopener noreferrer" target="_blank">f4d6d8b</a>: [Messenger] recommend not decoding non-sendable stamps in SerializerInterface::decode()</li>
<li><a href="https://github.com/symfony/symfony/commit/47ec709ce5a0a6d346811f14c638b82ca0365869" class="reference external" rel="external noopener noreferrer" target="_blank">47ec709</a>: [HttpFoundation] keep the session ID when the session handler fails to read</li>
<li><a href="https://github.com/symfony/symfony/commit/e763561b6b0d4caeb812c37f750bb802b63406aa" class="reference external" rel="external noopener noreferrer" target="_blank">e763561</a>: [Yaml] fix dumping tagged multi-line literal blocks</li>
<li><a href="https://github.com/symfony/symfony/commit/513e96d1400f2971c0ef2997748cb5bb911129b9" class="reference external" rel="external noopener noreferrer" target="_blank">513e96d</a>: [Messenger] fix losing delayed messages when retrying the message that dispatched them</li>
<li><a href="https://github.com/symfony/symfony/commit/3614876f3744f31891330d10303ec42afd584b80" class="reference external" rel="external noopener noreferrer" target="_blank">3614876</a>: [Messenger] fix the Doctrine transport masking commit failures</li>
<li><a href="https://github.com/symfony/symfony/commit/beb4c9c202921081a2bd78a372a8d3f4444e6c8d" class="reference external" rel="external noopener noreferrer" target="_blank">beb4c9c</a>: [Security] pass only stringable request attributes to the URL generator in HttpUtils</li>
<li><a href="https://github.com/symfony/symfony/commit/68051a67ccb0927721e4f44c44623a456a211060" class="reference external" rel="external noopener noreferrer" target="_blank">68051a6</a>: [FrameworkBundle] don't list aliases of abstract services in <code translate="no" class="notranslate">debug:autowiring</code></li>
<li><a href="https://github.com/symfony/symfony/commit/ec54b1efdd7a739bf0218a483339dc2636bb4d8b" class="reference external" rel="external noopener noreferrer" target="_blank">ec54b1e</a>: [Yaml] quote .inf and .nan strings when dumping</li>
<li><a href="https://github.com/symfony/symfony/commit/132867d3ab15d464fac889c4c766999c195431e7" class="reference external" rel="external noopener noreferrer" target="_blank">132867d</a>: [String] fix wordwrap() with $cut when the string ends with the break</li>
</ul>
<p><a href="https://github.com/symfony/symfony/commits/7.4" class="reference external" rel="external noopener noreferrer" target="_blank">7.4 changelog</a>:</p>
<ul>
    <li><a href="https://github.com/symfony/symfony/commit/30802f469a6802c85a15546426353b5fc4fcdf4d" class="reference external" rel="external noopener noreferrer" target="_blank">30802f4</a>: [JsonStreamer] fix generic types replacement in array shapes</li>
<li><a href="https://github.com/symfony/symfony/commit/ad7c073181977a458f385c0663d73bc51a4e75a7" class="reference external" rel="external noopener noreferrer" target="_blank">ad7c073</a>: [TypeInfo] fix accepts() of union and intersection types</li>
<li><a href="https://github.com/symfony/symfony/commit/03654e1a86c21826e3b8f14fb5a8e64232719f70" class="reference external" rel="external noopener noreferrer" target="_blank">03654e1</a>: [TypeInfo] fix quoted strings resolution with phpstan/phpdoc-parser 1.x</li>
<li><a href="https://github.com/symfony/symfony/commit/489d20d2dd38e37b8d379a71efdd7e3c4da10dc3" class="reference external" rel="external noopener noreferrer" target="_blank">489d20d</a>: [Serializer, Validator] fix compile-time discovery of attributes on non-public members</li>
<li><a href="https://github.com/symfony/symfony/commit/bb5fdd68acacce1addbd571df2976c5a59d6818f" class="reference external" rel="external noopener noreferrer" target="_blank">bb5fdd6</a>: [HtmlSanitizer] fix sanitizeFor() with table-related, image and plaintext contexts</li>
<li><a href="https://github.com/symfony/symfony/commit/f25ca4f833b77aba97b69ba7a4289ec13070734d" class="reference external" rel="external noopener noreferrer" target="_blank">f25ca4f</a>: [HtmlSanitizer] don't render comments as elements when the default action is Allow</li>
<li><a href="https://github.com/symfony/symfony/commit/21e5e2a7756ae5f7e6842342af172864952e091c" class="reference external" rel="external noopener noreferrer" target="_blank">21e5e2a</a>: [TypeInfo] fix printing array shape keys that contain quotes or backslashes</li>
<li><a href="https://github.com/symfony/symfony/commit/c4621778915181d56b606b8bc69511e3492a25d6" class="reference external" rel="external noopener noreferrer" target="_blank">c462177</a>: [JsonStreamer] fix replacing templates by mixed in union types</li>
<li><a href="https://github.com/symfony/symfony/commit/c2e593dc0b6c2914d14bbdc6dc06a9c42bb9a1b0" class="reference external" rel="external noopener noreferrer" target="_blank">c2e593d</a>: [ObjectMapper] construct nested lazy-ghost targets when the mapper is decorated</li>
<li><a href="https://github.com/symfony/symfony/commit/94e5b55795ce2b4d27d6515d76af6983f7e967f6" class="reference external" rel="external noopener noreferrer" target="_blank">94e5b55</a>: [TypeInfo] fix Type::union() with mixed as the only non-null type</li>
<li><a href="https://github.com/symfony/symfony/commit/0c4996e00340464ed0b681580eb067ea1e275d80" class="reference external" rel="external noopener noreferrer" target="_blank">0c4996e</a>: [PropertyInfo] fix quoted strings resolution in PhpStanExtractor with phpstan/phpdoc-parser 1.x</li>
<li><a href="https://github.com/symfony/symfony/commit/6321df044688833d06bac8bb81ab00c2ac25aff2" class="reference external" rel="external noopener noreferrer" target="_blank">6321df0</a>: [TypeInfo] fix infinite recursion on recursive type aliases</li>
<li><a href="https://github.com/symfony/symfony/commit/fb7d2b3ca8cc618131fdb371cefac0716d139467" class="reference external" rel="external noopener noreferrer" target="_blank">fb7d2b3</a>: [Security] give each role its own node in the Mermaid dump</li>
<li><a href="https://github.com/symfony/symfony/commit/3571209c164fbf9dcb71768c4248f162a20cc852" class="reference external" rel="external noopener noreferrer" target="_blank">3571209</a>: [JsonStreamer] fix generated readers and writers for names holding quotes</li>
<li><a href="https://github.com/symfony/symfony/commit/a3f66cc2987f7bff46ef71c02335a2470a92ed3e" class="reference external" rel="external noopener noreferrer" target="_blank">a3f66cc</a>: [Cache] bind namespaces in PDO-based cache invalidation</li>
<li><a href="https://github.com/symfony/symfony/commit/7dcbcde44e5f168d4251989ac2fc72fc05b1c49a" class="reference external" rel="external noopener noreferrer" target="_blank">7dcbcde</a>: [Security] bind discovered OIDC keys to issuers</li>
<li><a href="https://github.com/symfony/symfony/commit/43dce2d8c79acc8a3b5fab855cce93c15860ae73" class="reference external" rel="external noopener noreferrer" target="_blank">43dce2d</a>: [JsonStreamer] escape types in generated PHP comments</li>
<li><a href="https://github.com/symfony/symfony/commit/41e11de947c25ef60259a4e397be15bc800fc5d9" class="reference external" rel="external noopener noreferrer" target="_blank">41e11de</a>: [Messenger] prevent PhpSerializer::getMessageType() from autoloading classes</li>
<li><a href="https://github.com/symfony/symfony/commit/ee2ab09caaed3d6b2520bd7178c5be6b20d6818a" class="reference external" rel="external noopener noreferrer" target="_blank">ee2ab09</a>: [Mailer, Sweego] send the Reply-To address through the dedicated API field</li>
<li><a href="https://github.com/symfony/symfony/commit/9ef2936e6afd1f6a01324cce45b7b7182623f14b" class="reference external" rel="external noopener noreferrer" target="_blank">9ef2936</a>: use full setting name in deprecation message for consistency</li>
<li><a href="https://github.com/symfony/symfony/commit/d6f029e0c27283d36c7e5642c120a3eb791698d3" class="reference external" rel="external noopener noreferrer" target="_blank">d6f029e</a>: [Messenger] fix workers stopping on messages that fail signature verification</li>
<li><a href="https://github.com/symfony/symfony/commit/722eb742ad4b3bb2fe3ba76556c513e274280f97" class="reference external" rel="external noopener noreferrer" target="_blank">722eb74</a>: [Mailer, Sweego] accept fractional seconds in webhook timestamps</li>
<li><a href="https://github.com/symfony/symfony/commit/8d7dadc0c2addfa8b5f7e7b816507f4510a39871" class="reference external" rel="external noopener noreferrer" target="_blank">8d7dadc</a>: [Lock] fix denormalizing in XML a Key that has no expiring time or no state</li>
<li><a href="https://github.com/symfony/symfony/commit/78b2cea0c97baf98007305ddbd798a500313cc4e" class="reference external" rel="external noopener noreferrer" target="_blank">78b2cea</a>: [Messenger] fix skipping a message that has no original transport in <code translate="no" class="notranslate">messenger:failed:retry</code></li>
<li><a href="https://github.com/symfony/symfony/commit/d8cb53144cb62777fd2ea736a5757628a883f921" class="reference external" rel="external noopener noreferrer" target="_blank">d8cb531</a>: [FrameworkBundle, Messenger, Scheduler] require a signature for RedispatchMessage and ServiceCallMessage</li>
<li><a href="https://github.com/symfony/symfony/commit/6d252949162bf00e74b90fdc4fea9ef03502831c" class="reference external" rel="external noopener noreferrer" target="_blank">6d25294</a>: [Mailer, MicrosoftGraph] only forward headers that Graph can accept</li>
<li><a href="https://github.com/symfony/symfony/commit/990636bdeb56a88ab6b8c6c537be246bb48dc664" class="reference external" rel="external noopener noreferrer" target="_blank">990636b</a>: [HttpClient] fix using HTTP/3 with CurlHttpClient</li>
<li><a href="https://github.com/symfony/symfony/commit/ffc1b79fdf763e8daf4d62b4095398cb8bac1dd5" class="reference external" rel="external noopener noreferrer" target="_blank">ffc1b79</a>: [JsonPath] fix index and slice selectors dropping null array elements</li>
<li><a href="https://github.com/symfony/symfony/commit/8881c9cb743f92ad2a790ab0e6d4c44022f2d713" class="reference external" rel="external noopener noreferrer" target="_blank">8881c9c</a>: [JsonPath] fix anchoring and slash escaping in match() and search()</li>
<li><a href="https://github.com/symfony/symfony/commit/6b8537d6031150f2adfcbedcc749824e2d8d3c9c" class="reference external" rel="external noopener noreferrer" target="_blank">6b8537d</a>: [Scheduler] fix processOnlyLastMissedRun() skipping every missed run after a restart</li>
</ul>
<p><a href="https://github.com/symfony/symfony/commits/8.1" class="reference external" rel="external noopener noreferrer" target="_blank">8.1 changelog</a>:</p>
<ul>
    <li><a href="https://github.com/symfony/symfony/commit/c505a392fa635779054b24accdf2158107456c79" class="reference external" rel="external noopener noreferrer" target="_blank">c505a39</a>: [DependencyInjection, FrameworkBundle] fix describing services that have env closure arguments</li>
<li><a href="https://github.com/symfony/symfony/commit/6dc4600aac4512e728efa8b0191b0e7c824b44d1" class="reference external" rel="external noopener noreferrer" target="_blank">6dc4600</a>: [TypeInfo] fix object shape keys resolution in StringTypeResolver</li>
<li><a href="https://github.com/symfony/symfony/commit/963994d8838172897071e6c80b34e07c3d4871a1" class="reference external" rel="external noopener noreferrer" target="_blank">963994d</a>: [TypeInfo] fix printing object shape keys that contain quotes or backslashes</li>
<li><a href="https://github.com/symfony/symfony/commit/abce89edbc6efc71a621d4fad0752eac7fe629c9" class="reference external" rel="external noopener noreferrer" target="_blank">abce89e</a>: [JsonStreamer] fix generic types replacement in object shapes</li>
<li><a href="https://github.com/symfony/symfony/commit/739581a8f803c11526af7d348239ea3cd2afb9c6" class="reference external" rel="external noopener noreferrer" target="_blank">739581a</a>: [FrameworkBundle] require symfony/dependency-injection ^8.1.8</li>
<li><a href="https://github.com/symfony/symfony/commit/82c3ec20a6d7a0fc9a3a63e3f9e64df55cb1659f" class="reference external" rel="external noopener noreferrer" target="_blank">82c3ec2</a>: [Tui] repaint the viewport without clearing the screen when overflowing content shrinks</li>
<li><a href="https://github.com/symfony/symfony/commit/335148d37373073035b952093dcd35846bb43afd" class="reference external" rel="external noopener noreferrer" target="_blank">335148d</a>: [Tui] paint lines already in the scrollback in place when overflowing content grows back</li>
<li><a href="https://github.com/symfony/symfony/commit/55d26caafdcafd5b40da2c9e135a38ec4b4deb80" class="reference external" rel="external noopener noreferrer" target="_blank">55d26ca</a>: [JsonStreamer] export the type as a literal in the generated encoding error message</li>
<li><a href="https://github.com/symfony/symfony/commit/2e56795f4ecbff21f62ec4dc60376993617db8d5" class="reference external" rel="external noopener noreferrer" target="_blank">2e56795</a>: [Tui] fix slicing counting a combining mark as a column</li>
<li><a href="https://github.com/symfony/symfony/commit/0c3f6ee5aff639425f2988ff046a6c5a6edeed8e" class="reference external" rel="external noopener noreferrer" target="_blank">0c3f6ee</a>: [Messenger] keep the signature of signed messages that fail to decode</li>
<li><a href="https://github.com/symfony/symfony/commit/ccfe5b6b33fa7bdba117ed682d67861261de4b73" class="reference external" rel="external noopener noreferrer" target="_blank">ccfe5b6</a>: [Messenger] don't retry messages rejected for their signature</li>
<li><a href="https://github.com/symfony/symfony/commit/a6d9000317604c74828fcce9af4c2ecc1a400d81" class="reference external" rel="external noopener noreferrer" target="_blank">a6d9000</a>: [Tui] measure an emoji ZWJ, modifier or tag sequence as two columns</li>
<li><a href="https://github.com/symfony/symfony/commit/6fd896e39c468ad40b7b0a4b18555f8291c96339" class="reference external" rel="external noopener noreferrer" target="_blank">6fd896e</a>: [Messenger] fix acking messages that InMemoryTransport fails to decode</li>
<li><a href="https://github.com/symfony/symfony/commit/42952ca3e30fb0caf960e9deb22dfac1ce0922d8" class="reference external" rel="external noopener noreferrer" target="_blank">42952ca</a>: [Messenger] fix endless retries of messages with an empty body or an undecodable stamp header</li>
<li><a href="https://github.com/symfony/symfony/commit/0eef6c795557057c5f5252f52d7bb63b2be4689c" class="reference external" rel="external noopener noreferrer" target="_blank">0eef6c7</a>: [Messenger] fix duplicated stamps when a message that failed to decode is decoded on replay</li>
<li><a href="https://github.com/symfony/symfony/commit/bba9ddbdfb4ef8b756f8f2d7892ddebd1ea97900" class="reference external" rel="external noopener noreferrer" target="_blank">bba9ddb</a>: [Messenger] fix losing the payload of a message without a type header when it is retried</li>
<li><a href="https://github.com/symfony/symfony/commit/00d18e6588bfa71658dd819a11a071ee0bd4b162" class="reference external" rel="external noopener noreferrer" target="_blank">00d18e6</a>: [Messenger] fix ack/reject of Redis messages listed by the failed messages commands</li>
<li><a href="https://github.com/symfony/symfony/commit/1cf261c6ecae3a1cdf488e01ef13f6d260e47b05" class="reference external" rel="external noopener noreferrer" target="_blank">1cf261c</a>: [Messenger] route a message that PhpSerializer fails to decode to its own bus</li>
<li><a href="https://github.com/symfony/symfony/commit/d0607484c5398cb11f5f550273e1c644d30dd7f5" class="reference external" rel="external noopener noreferrer" target="_blank">d060748</a>: [Tui] fix wrapLineIntoChunks() returning a chunk wider than the width after wrapping at a space</li>
<li><a href="https://github.com/symfony/symfony/commit/fc6822c15125be3f8b9fb9f9e077cda7a608d0cc" class="reference external" rel="external noopener noreferrer" target="_blank">fc6822c</a>: [Tui] give no width to format characters and lone combining marks</li>
<li><a href="https://github.com/symfony/symfony/commit/3217edfe321372e6c8fdd1a662adec126b3f3f47" class="reference external" rel="external noopener noreferrer" target="_blank">3217edf</a>: [Messenger] add the default stamps of a message to its replayed decoding failure</li>
<li><a href="https://github.com/symfony/symfony/commit/1db8c7cb64c70dce415ea58522f708839a390357" class="reference external" rel="external noopener noreferrer" target="_blank">1db8c7c</a>: [Tui] fix parse() and matches() of modified function keys</li>
<li><a href="https://github.com/symfony/symfony/commit/6cebc11593588f3486200448183a79b97d6b6cb3" class="reference external" rel="external noopener noreferrer" target="_blank">6cebc11</a>: [Tui] match a modified escape that parse() names</li>
</ul>
<p><a href="https://github.com/symfony/symfony/commits/8.2" class="reference external" rel="external noopener noreferrer" target="_blank">8.2 changelog</a>:</p>
<ul>
    <li><a href="https://github.com/symfony/symfony/commit/296470b29d883bc7b046c2d80f2616d5f77d18a5" class="reference external" rel="external noopener noreferrer" target="_blank">296470b</a>: [PropertyInfo] create the inflector and the type resolver of ReflectionExtractor on first use</li>
<li><a href="https://github.com/symfony/symfony/commit/91cdb3d8221b9d6f3f5dd5e51f017c4f75480755" class="reference external" rel="external noopener noreferrer" target="_blank">91cdb3d</a>: [TypeInfo] parse the class docblock once when creating a type context</li>
<li><a href="https://github.com/symfony/symfony/commit/7d66574d44551b32669096fa9ed544ebf1598a32" class="reference external" rel="external noopener noreferrer" target="_blank">7d66574</a>: [Cache] clone the calls of CacheDataCollector once per profile</li>
<li><a href="https://github.com/symfony/symfony/commit/8c4eb689d8ec119e228b071b8a382b394ddb446c" class="reference external" rel="external noopener noreferrer" target="_blank">8c4eb68</a>: [AssetMapper] load each cached asset once per request and from a single file</li>
<li><a href="https://github.com/symfony/symfony/commit/720a5ef021a1d96ffa37954ad63bd6174b8b6094" class="reference external" rel="external noopener noreferrer" target="_blank">720a5ef</a>: [TwigBundle] skip templates already warmed up under another name</li>
<li><a href="https://github.com/symfony/symfony/commit/343fa46e1cfd5bc1d7401dc3a59ca5b24a159085" class="reference external" rel="external noopener noreferrer" target="_blank">343fa46</a>: [HttpKernel] compute the cURL command of RequestDataCollector in lateCollect()</li>
<li><a href="https://github.com/symfony/symfony/commit/245ca50f3a5b9d5668d2f204cb16b9d2bc0ef947" class="reference external" rel="external noopener noreferrer" target="_blank">245ca50</a>: [AssetMapper, FrameworkBundle, WebProfilerBundle] build neither the profiler nor Twig when the dev server serves an asset</li>
<li><a href="https://github.com/symfony/symfony/commit/8d581ad27653dc5a2a1b4241d4bde891cc86ca8e" class="reference external" rel="external noopener noreferrer" target="_blank">8d581ad</a>: [FrameworkBundle] build the configuration trees once for reference.php and schema.json</li>
<li><a href="https://github.com/symfony/symfony/commit/b73db07d0856297fc78dfd224544dc6fb5b41cba" class="reference external" rel="external noopener noreferrer" target="_blank">b73db07</a>: [PropertyInfo] parse the constructor docblock once per class</li>
<li><a href="https://github.com/symfony/symfony/commit/8823b6f7a1a46ad46b0b164b0364b557720c9bba" class="reference external" rel="external noopener noreferrer" target="_blank">8823b6f</a>: [Serializer] reduce the per-attribute overhead of normalizing objects</li>
<li><a href="https://github.com/symfony/symfony/commit/f606ec9fa2168cbf798532a29f0b11b12c3ea7ea" class="reference external" rel="external noopener noreferrer" target="_blank">f606ec9</a>: [Serializer] speed up name conversion when normalizing objects</li>
<li><a href="https://github.com/symfony/symfony/commit/1248d08320616cd30a51ae4e30d558cf6e584981" class="reference external" rel="external noopener noreferrer" target="_blank">1248d08</a>: [PropertyInfo, Serializer, Validator] warm up property info for the classes mapped by the serializer and the validator</li>
<li><a href="https://github.com/symfony/symfony/commit/590ba128ac12c5b88c2bd5a44361b34a32a71075" class="reference external" rel="external noopener noreferrer" target="_blank">590ba12</a>: [HtmlSanitizer] skip parsing plain text</li>
<li><a href="https://github.com/symfony/symfony/commit/9b9212a33624a77a163981f88e5bbbbeb92431df" class="reference external" rel="external noopener noreferrer" target="_blank">9b9212a</a>: [Serializer] aggregate nested calls in SerializerDataCollector as they happen</li>
<li><a href="https://github.com/symfony/symfony/commit/0ffd5b3d22fac632462bb2f74b40199bc34da21c" class="reference external" rel="external noopener noreferrer" target="_blank">0ffd5b3</a>: [HttpKernel] log client errors at the warning level instead of error</li>
<li><a href="https://github.com/symfony/symfony/commit/d827566e976a8e81fac05a4d736996caef425b82" class="reference external" rel="external noopener noreferrer" target="_blank">d827566</a>: [HttpKernel] log exceptions without flattening them</li>
<li><a href="https://github.com/symfony/symfony/commit/69cf483fbed57dd0317419cb3822069a088a8177" class="reference external" rel="external noopener noreferrer" target="_blank">69cf483</a>: [Validator] reuse the IntlDateFormatter of ConstraintValidator::formatValue()</li>
<li><a href="https://github.com/symfony/symfony/commit/93a532a27b43b7881cb19d7ae97919276b1b3ac1" class="reference external" rel="external noopener noreferrer" target="_blank">93a532a</a>: [PropertyAccess] reduce the overhead of reading properties</li>
<li><a href="https://github.com/symfony/symfony/commit/7020f706bd769b7ecb05883fd61fd9e3505ee439" class="reference external" rel="external noopener noreferrer" target="_blank">7020f70</a>: [Serializer] look up constructor parameters before property info when denormalizing</li>
<li><a href="https://github.com/symfony/symfony/commit/c43fb8c07a8e7fed31210fccaba039e7497749e1" class="reference external" rel="external noopener noreferrer" target="_blank">c43fb8c</a>: [Serializer] don't read class files when resolving the types of constructor parameters</li>
<li><a href="https://github.com/symfony/symfony/commit/ae2f63bd7fbcd33455ddd883306748ed5f0b856d" class="reference external" rel="external noopener noreferrer" target="_blank">ae2f63b</a>: [HttpKernel] collect the static data of ConfigDataCollector in lateCollect()</li>
<li><a href="https://github.com/symfony/symfony/commit/c0bc6eb3ecc7f4b964b1fb3425772c36c955f960" class="reference external" rel="external noopener noreferrer" target="_blank">c0bc6eb</a>: [SecurityBundle] move the static work of SecurityDataCollector to lateCollect()</li>
<li><a href="https://github.com/symfony/symfony/commit/f5e38b5b7929a101ecc95b42a269679bbe506d65" class="reference external" rel="external noopener noreferrer" target="_blank">f5e38b5</a>: conflict with outdated Symfony UX packages when requiring symfony/symfony</li>
<li><a href="https://github.com/symfony/symfony/commit/659cd62917d4a60a817ee2cb57fa7684331b119f" class="reference external" rel="external noopener noreferrer" target="_blank">659cd62</a>: [TwigBundle] warm up only reachable form themes</li>
<li><a href="https://github.com/symfony/symfony/commit/0447e59b78bcee798cf8040aec11b615d7bc23bf" class="reference external" rel="external noopener noreferrer" target="_blank">0447e59</a>: [FrameworkBundle, HttpKernel] skip resolving the runtime mode on web requests</li>
<li><a href="https://github.com/symfony/symfony/commit/d3b022add30a86c548cd60b53d18bff1674463be" class="reference external" rel="external noopener noreferrer" target="_blank">d3b022a</a>: [DependencyInjection] skip encoding plain ASCII values in XmlDumper</li>
<li><a href="https://github.com/symfony/symfony/commit/d49cb69dd27f914dcf72528c9d2b652f833b799c" class="reference external" rel="external noopener noreferrer" target="_blank">d49cb69</a>: [Serializer] don't create a property accessor per denormalized object</li>
<li><a href="https://github.com/symfony/symfony/commit/6686941abf179eb0f3e2e4dd69bfb0af7a317c42" class="reference external" rel="external noopener noreferrer" target="_blank">6686941</a>: [TypeInfo, Serializer, JsonStreamer] add Type::map()</li>
<li><a href="https://github.com/symfony/symfony/commit/1eba7ceeaa902c8ba59521f41f971246f90890b2" class="reference external" rel="external noopener noreferrer" target="_blank">1eba7ce</a>: [KeyManagement] record the key ARN returned by AWS KMS in ciphertexts</li>
<li><a href="https://github.com/symfony/symfony/commit/9c6ba2287e1e5a3fab6d0b29edffc8dd255d2c14" class="reference external" rel="external noopener noreferrer" target="_blank">9c6ba22</a>: [Translation] extract messages from match expressions, interpolated strings, variables and method return values</li>
<li><a href="https://github.com/symfony/symfony/commit/f212f28f3dba03ce7f07c2c9de06e4ae96eee449" class="reference external" rel="external noopener noreferrer" target="_blank">f212f28</a>: [HttpClient] allow repeating fields in the query and body options</li>
<li><a href="https://github.com/symfony/symfony/commit/df1286f45f69c8f71e22540c0b4ed7933344521b" class="reference external" rel="external noopener noreferrer" target="_blank">df1286f</a>: [Validator] make Constraint objects invokable</li>
<li><a href="https://github.com/symfony/symfony/commit/3b94fb11d63e39856bf4a68f1175775ab03c6311" class="reference external" rel="external noopener noreferrer" target="_blank">3b94fb1</a>: [SecurityBundle] fix the role hierarchy diagram in the profiler</li>
<li><a href="https://github.com/symfony/symfony/commit/0a71f5f395bed32dc8ea92c8c343445e6ba6b094" class="reference external" rel="external noopener noreferrer" target="_blank">0a71f5f</a>: [Messenger] allow using a named serializer for messenger.transport.symfony_serializer</li>
<li><a href="https://github.com/symfony/symfony/commit/775c1c2769652197a9d88c8bbf3adc4c51f23898" class="reference external" rel="external noopener noreferrer" target="_blank">775c1c2</a>: [FrameworkBundle] allow using a named serializer for #[MapRequestPayload], #[MapQueryString] &amp; #[Serialize]</li>
<li><a href="https://github.com/symfony/symfony/commit/a4916cb3f44b6e7303ce0d79fd6b83de25dae90b" class="reference external" rel="external noopener noreferrer" target="_blank">a4916cb</a>: [Mailer, Scaleway] bind webhook requests to the configured topic ARN</li>
<li><a href="https://github.com/symfony/symfony/commit/a1bff76fb7a177ecb6dae5150166bea743050e39" class="reference external" rel="external noopener noreferrer" target="_blank">a1bff76</a>: [String] skip the per-character width measurement for printable ASCII</li>
<li><a href="https://github.com/symfony/symfony/commit/7eaf80ce911f438d2f5c86df274ab59369c80b8c" class="reference external" rel="external noopener noreferrer" target="_blank">7eaf80c</a>: [KeyManagement] reject empty column values in the DBAL type</li>
<li><a href="https://github.com/symfony/symfony/commit/4732193beac1ee9b1c6cfca622c900085489fa4d" class="reference external" rel="external noopener noreferrer" target="_blank">4732193</a>: [Messenger] fix redispatching a message that failed to decode</li>
<li><a href="https://github.com/symfony/symfony/commit/977b90ba6b3281d9d1ffa691dd452bd0abde74d1" class="reference external" rel="external noopener noreferrer" target="_blank">977b90b</a>: [Messenger] retry a claim that could not be retrieved with its original reference</li>
<li><a href="https://github.com/symfony/symfony/commit/a6d7e8477f06eccc1d31b52d695c60442a0305bb" class="reference external" rel="external noopener noreferrer" target="_blank">a6d7e84</a>: [Security] let voters tell which denials a re-authentication can cure</li>
<li><a href="https://github.com/symfony/symfony/commit/616a19c75af454038109f23ab7390360476d0d62" class="reference external" rel="external noopener noreferrer" target="_blank">616a19c</a>: [Security, SecurityBundle] let the discovery endpoints of the oidc token handler be pinned to their issuer</li>
<li><a href="https://github.com/symfony/symfony/commit/fec3f91ac74eae6745e8ffa7662387ece16e2363" class="reference external" rel="external noopener noreferrer" target="_blank">fec3f91</a>: [Messenger] fix unverified decoding failures putting their stamps on signed messages</li>
<li><a href="https://github.com/symfony/symfony/commit/e661238002beb59ecafadc756c222195f2ff2a57" class="reference external" rel="external noopener noreferrer" target="_blank">e661238</a>: [Messenger] fix endless retries of a claim that cannot be retrieved</li>
<li><a href="https://github.com/symfony/symfony/commit/d1659d214d77d2bab43f815cddc92135abd76c4a" class="reference external" rel="external noopener noreferrer" target="_blank">d1659d2</a>: [Security] start a re-authentication for a check made by an allow_if expression or an #[IsGranted] closure</li>
<li><a href="https://github.com/symfony/symfony/commit/494d536ed390bf17166213a6b64eccaf84f69f95" class="reference external" rel="external noopener noreferrer" target="_blank">494d536</a>: [Mime] keep the explicit encoding of parts in FormDataPart</li>
<li><a href="https://github.com/symfony/symfony/commit/feb08caba31934fdb17cfd44d31619b7a6ca065f" class="reference external" rel="external noopener noreferrer" target="_blank">feb08ca</a>: [Messenger] route a claim that cannot be retrieved to the bus of its message</li>
<li><a href="https://github.com/symfony/symfony/commit/3bf30ac8646b8c9bb9b9ce6fa93a59081926f767" class="reference external" rel="external noopener noreferrer" target="_blank">3bf30ac</a>: [Messenger] reject an unverified decoding failure that runs on another bus than its signed message</li>
<li><a href="https://github.com/symfony/symfony/commit/7cc98e4d2dff9b50e9c28668c734c2193d7f26d5" class="reference external" rel="external noopener noreferrer" target="_blank">7cc98e4</a>: [TwigBundle] skip checking known template directories on each request</li>
<li><a href="https://github.com/symfony/symfony/commit/7384daaf16a9e86c83a687fc696f6029099f7f24" class="reference external" rel="external noopener noreferrer" target="_blank">7384daa</a>: [Security] make FormLoginAuthenticator a re-authentication entry point</li>
<li><a href="https://github.com/symfony/symfony/commit/7614f747a6b48d2f1fe3791bbf8fa99277e57ccf" class="reference external" rel="external noopener noreferrer" target="_blank">7614f74</a>: [Messenger, Scheduler] replace RedispatchMessageHandler by a non-sendable RedispatchStamp</li>
<li><a href="https://github.com/symfony/symfony/commit/fa61c6409565b50bb3644e692dead13db0e687a9" class="reference external" rel="external noopener noreferrer" target="_blank">fa61c64</a>: [Messenger] let a flow carry its context in stamps: propagation, handler arguments and identity</li>
<li><a href="https://github.com/symfony/symfony/commit/f9cce704c15b8bdcf32f9b50b5e0215e4198d999" class="reference external" rel="external noopener noreferrer" target="_blank">f9cce70</a>: [Messenger] keep an application-defined message id generator when symfony/uid is missing</li>
<li><a href="https://github.com/symfony/symfony/commit/13a9950a4cd1458def535d8ed6f929fa5b879c54" class="reference external" rel="external noopener noreferrer" target="_blank">13a9950</a>: [Messenger] merge the identity and propagation middlewares into FlowContextMiddleware and track delayed messages</li>
<li><a href="https://github.com/symfony/symfony/commit/9917e11582f1882cf124a76aba6ed2ca841dd6b7" class="reference external" rel="external noopener noreferrer" target="_blank">9917e11</a>: [Messenger, Scheduler] add a sign option to transports to sign every message</li>
<li><a href="https://github.com/symfony/symfony/commit/95b3e617dc7983c188122deb8b422cc6ae164369" class="reference external" rel="external noopener noreferrer" target="_blank">95b3e61</a>: [Messenger] make SyncTransport trust the messages dispatched in this process</li>
<li><a href="https://github.com/symfony/symfony/commit/515f227238fab1090883dc47b5d56285302bc0d2" class="reference external" rel="external noopener noreferrer" target="_blank">515f227</a>: [Messenger] stop forwarding a redispatched message again once it was sent</li>
<li><a href="https://github.com/symfony/symfony/commit/d547b96166b7d6cff6893e71116ea1d63cab4ffe" class="reference external" rel="external noopener noreferrer" target="_blank">d547b96</a>: [Messenger] refuse to call handlers that require a signature for untrusted envelopes</li>
<li><a href="https://github.com/symfony/symfony/commit/0520527dfb341a78ce13a974eeb627d41b359d6a" class="reference external" rel="external noopener noreferrer" target="_blank">0520527</a>: [FrameworkBundle, RateLimiter] register RateLimitAttributeListener in FrameworkBundle</li>
<li><a href="https://github.com/symfony/symfony/commit/37457dbd9a0e98eb3566bc3050fcee356bc8e270" class="reference external" rel="external noopener noreferrer" target="_blank">37457db</a>: [Tui] add the super, hyper and meta modifiers to key ids</li>
<li><a href="https://github.com/symfony/symfony/commit/e13014339133a608ec6cc1f9b0e1c92939a2b38c" class="reference external" rel="external noopener noreferrer" target="_blank">e130143</a>: [Messenger] fix sending stamps and trust to parallel workers</li>
<li><a href="https://github.com/symfony/symfony/commit/1b33dca34db2e7b00d36be8b2e38795f485f39bb" class="reference external" rel="external noopener noreferrer" target="_blank">1b33dca</a>: [Messenger] fix delaying acks until after the idle sleep with --concurrency</li>
<li><a href="https://github.com/symfony/symfony/commit/e469e86718f657524f8036c99efa546acc036e33" class="reference external" rel="external noopener noreferrer" target="_blank">e469e86</a>: [Tui] reject a key id naming an unknown key when creating Keybindings</li>
<li><a href="https://github.com/symfony/symfony/commit/b024412db9aabf0ae3252a9d456968a5f016795d" class="reference external" rel="external noopener noreferrer" target="_blank">b024412</a>: [HttpClient] use HTTP/2 with prior knowledge when http_version is 2.0</li>
<li><a href="https://github.com/symfony/symfony/commit/d56d7938cc45e8f75c43d60d33b75442fd1f10ec" class="reference external" rel="external noopener noreferrer" target="_blank">d56d793</a>: [Messenger] add ChainStamp to dispatch messages one after another</li>
<li><a href="https://github.com/symfony/symfony/commit/8318c7604f2ab1bcbc01a61c8c18612ab7dfaf23" class="reference external" rel="external noopener noreferrer" target="_blank">8318c76</a>: [Messenger] add DispatchOnFailureStamp to dispatch a message when another one fails</li>
<li><a href="https://github.com/symfony/symfony/commit/77b77973f0d8d2fdc15b8d87a9a2c1c26d9b77f4" class="reference external" rel="external noopener noreferrer" target="_blank">77b7797</a>: [KeyManagement] bind a stored data key to its reference and scope</li>
<li><a href="https://github.com/symfony/symfony/commit/be05acb5a93b4d773cb8652fc827ab9cb52da733" class="reference external" rel="external noopener noreferrer" target="_blank">be05acb</a>: [Tui] add Tui::getWidgetRect()</li>
<li><a href="https://github.com/symfony/symfony/commit/e9a0f11179fe0fd17d946d9f940848ceb4160cc2" class="reference external" rel="external noopener noreferrer" target="_blank">e9a0f11</a>: [Form] add the sort_choices option to ChoiceType</li>
<li><a href="https://github.com/symfony/symfony/commit/24809fd98d669c4843af97fbed56b33921b17258" class="reference external" rel="external noopener noreferrer" target="_blank">24809fd</a>: [FrameworkBundle, HttpFoundation, Messenger, Security, SecurityBundle] allow rotating the secrets that sign URIs, remember-me cookies, login links and messages</li>
<li><a href="https://github.com/symfony/symfony/commit/ed4c60b1ca622b9e358781170c39285b8b2fb7d2" class="reference external" rel="external noopener noreferrer" target="_blank">ed4c60b</a>: [FrameworkBundle] improve the hints shown by <code translate="no" class="notranslate">debug:autowiring</code></li>
<li><a href="https://github.com/symfony/symfony/commit/de96277f61ff633452268e4cdb2ef6eb984439d5" class="reference external" rel="external noopener noreferrer" target="_blank">de96277</a>: [JsonStreamer, Mailer, Notifier, SecurityBundle, Webhook] deprecate autowiring aliases named after implementations</li>
<li><a href="https://github.com/symfony/symfony/commit/5a5cd5b493c228cbc60b19c26512850ca7e9f45a" class="reference external" rel="external noopener noreferrer" target="_blank">5a5cd5b</a>: [DependencyInjection] move PriorityTaggedServiceUtil to its own file so that it can be autoloaded</li>
<li><a href="https://github.com/symfony/symfony/commit/cb263b088f03fdc29f891fa99de35063a274a1de" class="reference external" rel="external noopener noreferrer" target="_blank">cb263b0</a>: [Config, DependencyInjection] add NodeDefinition::inlineEnvVars() to inline env vars while the container is compiled</li>
<li><a href="https://github.com/symfony/symfony/commit/cb53c822165dc9a3441aba2d7b4d6138d04f8d56" class="reference external" rel="external noopener noreferrer" target="_blank">cb53c82</a>: [DependencyInjection] add within and around constraints to order decorators</li>
<li><a href="https://github.com/symfony/symfony/commit/08829a17285a450350370b8f2e38980095197813" class="reference external" rel="external noopener noreferrer" target="_blank">08829a1</a>: [Config] fix enum nodes and validation rules that inline env vars</li>
</ul>
</div>
<div class="section">
<h2 id="symfony-ux-development-highlights"><a class="headerlink" href="#symfony-ux-development-highlights" title="Permalink to this headline">Symfony UX development highlights</a></h2>
<p><a href="https://github.com/symfony/ux/commits/3.x" class="reference external" rel="external noopener noreferrer" target="_blank">3.x changelog</a>:</p>
<ul>
    <li><a href="https://github.com/symfony/ux/commit/683b467b2b984bfcf52f82d57affc80b16b11117" class="reference external" rel="external noopener noreferrer" target="_blank">683b467</a>: [Image] add the UX Image package and its Cloudflare and KeyCDN bridges</li>
<li><a href="https://github.com/symfony/ux/commit/865e53231455e9be7e337199a95012bf3998cdfd" class="reference external" rel="external noopener noreferrer" target="_blank">865e532</a>: [Toolkit] ship kit preview assets and add a preview app</li>
<li><a href="https://github.com/symfony/ux/commit/19c7ad86586f8b6c15b7e4eaf4fcdc10cdfb9ae8" class="reference external" rel="external noopener noreferrer" target="_blank">19c7ad8</a>: [Toolkit] add visual tests for recipes</li>
<li><a href="https://github.com/symfony/ux/commit/e7e7f1b1cdf461b686a9512e4dd9fb8bad567369" class="reference external" rel="external noopener noreferrer" target="_blank">e7e7f1b</a>: [Toolkit, Shadcn] fix the popover not focusing its content on a busy browser</li>
<li><a href="https://github.com/symfony/ux/commit/27da0432ed545471d2c1c4dc7fb0a7d0a8629b15" class="reference external" rel="external noopener noreferrer" target="_blank">27da043</a>: [Toolkit] shard the browser tests and keep the server logs out of the CI output</li>
<li><a href="https://github.com/symfony/ux/commit/402afd1d1dd6a2d339982dad0e939ba3b2f6d229" class="reference external" rel="external noopener noreferrer" target="_blank">402afd1</a>: [Toolkit, Flowbite] fix the modal having no accessible name</li>
<li><a href="https://github.com/symfony/ux/commit/dd302b348c660795367a0530ee01efe9bc1b3154" class="reference external" rel="external noopener noreferrer" target="_blank">dd302b3</a>: [Toolkit, Flowbite] fix inactive tabs being unreadable in dark mode</li>
<li><a href="https://github.com/symfony/ux/commit/cdc28780ae1deb53c4f3be5df1902debc922793e" class="reference external" rel="external noopener noreferrer" target="_blank">cdc2878</a>: [Toolkit, Shadcn] fix the arrow keys getting stuck before a disabled accordion item</li>
<li><a href="https://github.com/symfony/ux/commit/01b3ed40559210b0e6570a7636ebc894faa75b8b" class="reference external" rel="external noopener noreferrer" target="_blank">01b3ed4</a>: [Toolkit, Shadcn] fix alert dialogs opening on page load</li>
<li><a href="https://github.com/symfony/ux/commit/db56b43705c772aae291706497bc07f2c4c17330" class="reference external" rel="external noopener noreferrer" target="_blank">db56b43</a>: [Toolkit, Shadcn] fix a closed drawer staying reachable with the keyboard</li>
<li><a href="https://github.com/symfony/ux/commit/8d2b82f6c7cd52c6e6e3cb99c62279db460a1859" class="reference external" rel="external noopener noreferrer" target="_blank">8d2b82f</a>: [Toolkit, Shadcn] fix the combobox list not lining up with its trigger</li>
<li><a href="https://github.com/symfony/ux/commit/3ebdfa05ad406be7de3a52ab35ab546bdb55a39d" class="reference external" rel="external noopener noreferrer" target="_blank">3ebdfa0</a>: [Toolkit, Shadcn] fix the radio indicator of the dropdown menu being a ring instead of a dot</li>
<li><a href="https://github.com/symfony/ux/commit/183536e1729fd4f24f4c12037b46211c03dd76b7" class="reference external" rel="external noopener noreferrer" target="_blank">183536e</a>: [Toolkit, Shadcn] fix dropdown submenus wrapping their labels</li>
<li><a href="https://github.com/symfony/ux/commit/99e0def25d1a3f4ebadffffae0dac50833e5239a" class="reference external" rel="external noopener noreferrer" target="_blank">99e0def</a>: [Toolkit, Shadcn] fix the date picker focusing "Previous month" instead of a day</li>
<li><a href="https://github.com/symfony/ux/commit/3e74e95954ab34d5b01c8307f7d7be638383c450" class="reference external" rel="external noopener noreferrer" target="_blank">3e74e95</a>: [Toolkit, Shadcn] fix the radio indicator of the menubar being a ring instead of a dot</li>
<li><a href="https://github.com/symfony/ux/commit/b2d63a8504beb935d636b0b54a4d62daca309eac" class="reference external" rel="external noopener noreferrer" target="_blank">b2d63a8</a>: [Toolkit, Shadcn] fix menubar submenus wrapping long labels</li>
<li><a href="https://github.com/symfony/ux/commit/fb844e7d2ac58a51071f231cbcabf5161713305b" class="reference external" rel="external noopener noreferrer" target="_blank">fb844e7</a>: [Toolkit, Shadcn] fix the dialog trigger's aria-expanded getting out of sync</li>
<li><a href="https://github.com/symfony/ux/commit/4fd09a2e2c4df484fdf836e397c950e986bf054d" class="reference external" rel="external noopener noreferrer" target="_blank">4fd09a2</a>: [Toolkit, Shadcn] fix Tab skipping the panels of the navigation menu</li>
<li><a href="https://github.com/symfony/ux/commit/e5896b13c595c12fc2a3c459b97b4d013d2d3a63" class="reference external" rel="external noopener noreferrer" target="_blank">e5896b1</a>: [Toolkit, Shadcn] fix the resizable handle missing its separator state</li>
<li><a href="https://github.com/symfony/ux/commit/9525e93f3bc78995e4bffc5723c9dbb3e1e79e51" class="reference external" rel="external noopener noreferrer" target="_blank">9525e93</a>: [Toolkit, Shadcn] fix a closed sheet staying reachable with the keyboard</li>
<li><a href="https://github.com/symfony/ux/commit/a2e0e03d05e5349b94d31c4d76d08408964d21d6" class="reference external" rel="external noopener noreferrer" target="_blank">a2e0e03</a>: [Toolkit, Shadcn] fix a disabled slider still reacting to the keyboard</li>
<li><a href="https://github.com/symfony/ux/commit/893bd575ab7e92dcbbe38e613973fbd8934f8173" class="reference external" rel="external noopener noreferrer" target="_blank">893bd57</a>: [Toolkit, Shadcn] fix the slider losing the focus after a click on its track</li>
<li><a href="https://github.com/symfony/ux/commit/c3f8aa504e43a91fb834e423ff51286b13a612b3" class="reference external" rel="external noopener noreferrer" target="_blank">c3f8aa5</a>: [Toolkit, Shadcn] fix the close button and the action of a toast ignoring mouse clicks</li>
<li><a href="https://github.com/symfony/ux/commit/b505c4c3e9b90690183023d747e75a89f0150322" class="reference external" rel="external noopener noreferrer" target="_blank">b505c4c</a>: [Toolkit, Shadcn] fix the bookmark icon not filling in the toggle examples</li>
<li><a href="https://github.com/symfony/ux/commit/cf264f63bf4983459a149dc0f9d0d6bc244516a2" class="reference external" rel="external noopener noreferrer" target="_blank">cf264f6</a>: [Toolkit, Shadcn] fix the tooltip of the disabled button example never opening</li>
<li><a href="https://github.com/symfony/ux/commit/07052f9b7206d14b56db89e370c2e295af5ff0da" class="reference external" rel="external noopener noreferrer" target="_blank">07052f9</a>: [Toolkit] fix <code translate="no" class="notranslate">ux:install</code> not overwriting a file newer than the recipe</li>
<li><a href="https://github.com/symfony/ux/commit/9becbddd204090f712187e42e769a90e43cda637" class="reference external" rel="external noopener noreferrer" target="_blank">9becbdd</a>: [Image] add presets</li>
<li><a href="https://github.com/symfony/ux/commit/4cfdb0812cfa5386bb2f60d104b15f37636ca5ca" class="reference external" rel="external noopener noreferrer" target="_blank">4cfdb08</a>: [Icons] warm local icons on <code translate="no" class="notranslate">cache:warmup</code></li>
<li><a href="https://github.com/symfony/ux/commit/7d06bf1972bb1a1b034602224bc62c981fdc13fe" class="reference external" rel="external noopener noreferrer" target="_blank">7d06bf1</a>: [TwigComponent] copy plain text in one go when pre-lexing templates</li>
<li><a href="https://github.com/symfony/ux/commit/cfae61f5b94437ce5e598595e845be91aea4e0ac" class="reference external" rel="external noopener noreferrer" target="_blank">cfae61f</a>: [Toolkit, Shadcn] align combobox with the upstream Shadcn UI component</li>
<li><a href="https://github.com/symfony/ux/commit/02971279099cca305035090d8fa56863cd188e96" class="reference external" rel="external noopener noreferrer" target="_blank">0297127</a>: [Toolkit, Shadcn] align input-group with the upstream Shadcn InputGroup</li>
<li><a href="https://github.com/symfony/ux/commit/41789cec8c36f49f7023fa5b43432d39666f38cb" class="reference external" rel="external noopener noreferrer" target="_blank">41789ce</a>: [Toolkit, Shadcn] fix data-slot being shadowed when forwarded to a child component</li>
<li><a href="https://github.com/symfony/ux/commit/1ece7c61f9f74f621061ac737970ac590a8d98fa" class="reference external" rel="external noopener noreferrer" target="_blank">1ece7c6</a>: [Toolkit, Shadcn] align select with the upstream Shadcn Select</li>
<li><a href="https://github.com/symfony/ux/commit/f23c8991331d75699adbd237fe7005f0b6d41a64" class="reference external" rel="external noopener noreferrer" target="_blank">f23c899</a>: [Toolkit] show a diff when <code translate="no" class="notranslate">ux:install</code> asks to overwrite a file</li>
<li><a href="https://github.com/symfony/ux/commit/e3960868bc24f395a96c406d567666905e0dadc3" class="reference external" rel="external noopener noreferrer" target="_blank">e396086</a>: [Toolkit, Shadcn] keep the tooltip inside the viewport and fit it to its text</li>
<li><a href="https://github.com/symfony/ux/commit/ee36b37805938ebba01912e8fc7b567240653cc6" class="reference external" rel="external noopener noreferrer" target="_blank">ee36b37</a>: [Toolkit, Shadcn] fix resizable handle moving twice as far once moved in the DOM</li>
<li><a href="https://github.com/symfony/ux/commit/0e54cdf0ca26287250ce0a64891798b05e58b93f" class="reference external" rel="external noopener noreferrer" target="_blank">0e54cdf</a>: [Toolkit, Shadcn] fix sonner losing its toasts once moved in the DOM</li>
<li><a href="https://github.com/symfony/ux/commit/06803d9c90c73d2ff0ba1d67f575b299f4e352ad" class="reference external" rel="external noopener noreferrer" target="_blank">06803d9</a>: [Toolkit, Shadcn] fix dialog no longer being modal once moved in the DOM</li>
<li><a href="https://github.com/symfony/ux/commit/c57118aaf9eb8366c9ea1ac2579089eb69a64afd" class="reference external" rel="external noopener noreferrer" target="_blank">c57118a</a>: [Toolkit, Flowbite] fix modal no longer being modal once moved in the DOM</li>
<li><a href="https://github.com/symfony/ux/commit/30ae7852fe3d814f83b31fcb48154adde74c1caf" class="reference external" rel="external noopener noreferrer" target="_blank">30ae785</a>: [Toolkit, Shadcn] fix navigation-menu never opening again once moved in the DOM</li>
<li><a href="https://github.com/symfony/ux/commit/8ae6aef4c723c1cac4e39bc4fcbe3c8052be3ba3" class="reference external" rel="external noopener noreferrer" target="_blank">8ae6aef</a>: [Toolkit, Shadcn] fix alert-dialog no longer being modal once moved in the DOM</li>
<li><a href="https://github.com/symfony/ux/commit/9be21228a1707b1c2e44aa05ed9fdacda1e4335f" class="reference external" rel="external noopener noreferrer" target="_blank">9be2122</a>: [Toolkit, Shadcn] fix questionnaire freeform answer losing its name once moved in the DOM</li>
<li><a href="https://github.com/symfony/ux/commit/49ab9cc90040ca9e04d21a350633e213ac753d7b" class="reference external" rel="external noopener noreferrer" target="_blank">49ab9cc</a>: [LiveComponent] fix AssertDispatchedEvent::withPayloadSubset() crashing on non-scalar payload values</li>
<li><a href="https://github.com/symfony/ux/commit/b8d4038ec974710a598b2bee6e4efd1a624d531d" class="reference external" rel="external noopener noreferrer" target="_blank">b8d4038</a>: [Pagination] fix Cursor pagination with DATETIMETZ_MUTABLE columns</li>
<li><a href="https://github.com/symfony/ux/commit/5ef8a78303d03758642f0825214a3eccf3b92e4f" class="reference external" rel="external noopener noreferrer" target="_blank">5ef8a78</a>: [Turbo] support the Mercure protocol 1.0 in turbo_stream_from()</li>
<li><a href="https://github.com/symfony/ux/commit/c19924f68e65406dfb07be39eed5c4958c8a5d5d" class="reference external" rel="external noopener noreferrer" target="_blank">c19924f</a>: [Turbo] only trigger the TurboStreamListenRenderer deprecation when the service is used</li>
<li><a href="https://github.com/symfony/ux/commit/dcbeef0f2adf83e3e01d049ba8b752948d3d8687" class="reference external" rel="external noopener noreferrer" target="_blank">dcbeef0</a>: [LiveComponent] add the <code translate="no" class="notranslate">render:started</code> hook to the ComponentHooks type</li>
<li><a href="https://github.com/symfony/ux/commit/40eaad0ccf18f621b977ab1ceff4badee003e33b" class="reference external" rel="external noopener noreferrer" target="_blank">40eaad0</a>: [LiveComponent] fix child components lost inside a data-skip-morph element</li>
<li><a href="https://github.com/symfony/ux/commit/9613d1377115ef4dcb2692d0f7254dfae3bca2d0" class="reference external" rel="external noopener noreferrer" target="_blank">9613d13</a>: [LiveComponent] finish the loading state when a request fails</li>
</ul>
</div>
<div class="section">
<h2 id="newest-issues-and-pull-requests"><a class="headerlink" href="#newest-issues-and-pull-requests" title="Permalink to this headline">Newest issues and pull requests</a></h2>
<ul>
    <li><a href="https://github.com/symfony/symfony/pull/66515" class="reference external" rel="external noopener noreferrer" target="_blank">[HttpKernel][Lock] Add #[Lock] attribute to reject or delay concurrent requests</a></li>
<li><a href="https://github.com/symfony/symfony/pull/66450" class="reference external" rel="external noopener noreferrer" target="_blank">[Messenger][MongoDb] Listen to multiple queues in a single request</a></li>
<li><a href="https://github.com/symfony/symfony/pull/66574" class="reference external" rel="external noopener noreferrer" target="_blank">[Messenger] Add InteropSerializer to exchange messages with another application</a></li>
<li><a href="https://github.com/symfony/symfony/pull/66511" class="reference external" rel="external noopener noreferrer" target="_blank">[Validator] Piped Validation</a></li>
<li><a href="https://github.com/symfony/symfony/pull/66586" class="reference external" rel="external noopener noreferrer" target="_blank">[Messenger] Add the messages and unwrap_exceptions options of buses</a></li>
</ul>
</div>
<div class="section">
<h2 id="symfony-jobs"><a class="headerlink" href="#symfony-jobs" title="Permalink to this headline">Symfony Jobs</a></h2>
<p>These are some of the most recent Symfony job offers:</p>
<ul>
    <li>
        <strong>Symfony Developer</strong> at Steward<br>
        Part-time / Temporary - $8,700 – $13,000 / month<br>
        Full remote<br>
        <a href="https://symfony.com/jobs/69885c2">View details</a>
    </li>
    <li>
        <strong>Symfony Developer</strong> at ATH<br>
        Contract / Freelance - €25 – €50 / hour<br>
        Full remote<br>
        <a href="https://symfony.com/jobs/4a82fc1">View details</a>
    </li>
</ul>
<p>You can <a href="https://symfony.com/jobs" class="reference external">publish a Symfony job offer for free</a> on symfony.com.</p>
</div>
<div class="section">
<h2 id="symfonycasts-updates"><a class="headerlink" href="#symfonycasts-updates" title="Permalink to this headline">SymfonyCasts Updates</a></h2>
<p><a href="https://symfonycasts.com/" class="reference external" rel="external noopener noreferrer" target="_blank">SymfonyCasts</a> is the official way to learn Symfony.
Select a track for a guided path through 100+ video tutorial courses about
Symfony, PHP and JavaScript.</p>
<p>This week, SymfonyCasts published the following updates:</p>
<ul>
    <li>(Video) <a href="https://symfonycasts.com/screencast/symfony8-security-extra/super-admin-voter" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony Security: Going Further: Creating a Super Admin Voter</a></li>
<li>(Video) <a href="https://symfonycasts.com/screencast/symfony8-security-extra/sudo-mode" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony Security: Going Further: Sudo Mode: Requiring Full Authentication</a></li>
</ul>
</div>
<div class="section">
<h2 id="they-talked-about-us"><a class="headerlink" href="#they-talked-about-us" title="Permalink to this headline">They talked about us</a></h2>
<ul>
    <li><a href="https://marmelab.com/blog/2026/09/29/symfony-ai.html" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony AI in Practice: Building a Writing Assistant for Dyslexic Adults</a></li>
<li><a href="https://dev.to/symfonycasts/playwright-php-changes-the-game-for-symfony-testing-p5e" class="reference external" rel="external noopener noreferrer" target="_blank">Playwright-PHP Changes the Game for Symfony Testing</a></li>
<li><a href="https://blog.stackademic.com/part-2-symfony-8-2-single-use-signed-urls-without-extra-storage-1820726e905f?sk=47d2e745678304069f801c5e52b13e3e" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony 8.2 — Single-Use Signed URLs, Without Extra Storage</a></li>
<li><a href="https://dev.to/mollenthiel/symfony-74-to-81-measured-twice-a-month-apart-two-of-the-scary-parts-were-fixed-in-patch-32h8" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony 7.4 to 8.1, measured twice a month apart: two of the scary parts were fixed in patch releases</a></li>
<li><a href="https://wengerk.medium.com/http-query-in-symfony-when-your-get-doesnt-fit-on-a-postcard-a3150623a2ba?sk=95dc5861710f34f04ba313676271958a" class="reference external" rel="external noopener noreferrer" target="_blank">HTTP QUERY in Symfony: when your GET doesn’t fit on a postcard</a></li>
<li><a href="https://medium.com/@youssefbassim/translatable-enums-in-symfony-problems-solutions-and-when-to-use-them-9ed9ec99e43e?sk=a879d0ca14dc7bef03d8b664a33b9187" class="reference external" rel="external noopener noreferrer" target="_blank">Translatable Enums in Symfony: Problems, Solutions, and When to Use Them</a></li>
<li><a href="https://medium.com/@tiwabrayan/setting-up-mcp-with-symfony-and-connecting-it-to-gemini-spark-3a692e1dc2e1" class="reference external" rel="external noopener noreferrer" target="_blank">Setting Up MCP with Symfony and Connecting It to Gemini Spark</a></li>
<li><a href="https://medium.com/@prem_sg/how-i-built-a-langgraph-style-ai-agent-in-php-27e265851b30" class="reference external" rel="external noopener noreferrer" target="_blank">How I Built an AI Agent in PHP</a></li>
<li><a href="https://tuhinbepari.medium.com/domain-driven-design-in-symfony-5e69fa90d1ed" class="reference external" rel="external noopener noreferrer" target="_blank">Domain Driven Design in Symfony</a></li>
<li><a href="https://dev.to/_er2es_/i-couldnt-touch-the-database-so-i-built-search-next-to-it-1pjn" class="reference external" rel="external noopener noreferrer" target="_blank">I couldn't touch the database, so I built search next to it</a></li>
<li><a href="https://medium.com/ekino-france/how-to-no-longer-suffer-project-migration-de8fd0f91528" class="reference external" rel="external noopener noreferrer" target="_blank">How to no longer suffer project migration</a></li>
<li><a href="https://medium.com/@przemyslaw.rafal.jez/doctrine-lifecycle-listeners-are-a-dangerous-place-for-gdpr-erasure-64f91457e5a6" class="reference external" rel="external noopener noreferrer" target="_blank">Doctrine Lifecycle Listeners Are a Dangerous Place for GDPR Erasure</a></li>
<li><a href="https://dev.to/javiereguiluz/introducing-easyadmin-pro-331o" class="reference external" rel="external noopener noreferrer" target="_blank">Introducing EasyAdmin Pro</a></li>
<li><a href="https://dev.to/dev_iadicola/objectmapper-in-symfony-8-trasformare-dto-senza-boilerplate-3962" class="reference external" rel="external noopener noreferrer" target="_blank">ObjectMapper in Symfony 8: trasformare DTO senza boilerplate</a></li>
<li><a href="https://dev.to/dev_iadicola/multi-step-forms-in-symfony-8-form-complessi-senza-dolore-2c7k" class="reference external" rel="external noopener noreferrer" target="_blank">Multi-step forms in Symfony 8: form complessi senza dolore</a></li>
<li><a href="https://habr.com/ru/articles/1089854/" class="reference external" rel="external noopener noreferrer" target="_blank">Как мы перестраивали e‑commerce‑платформу в production: от legacy‑системы к Next.js и Symfony</a></li>
</ul>
</div>
<div class="section">
<h2 id="upcoming-symfony-events"><a class="headerlink" href="#upcoming-symfony-events" title="Permalink to this headline">Upcoming Symfony Events</a></h2>
<ul>
    <li><a href="https://c.sensiolabs.de/events/symfony-meetup-mannheim" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony/PHP Meetup Mannheim by SensioLabs</a>: Mannheim, Germany (October 22, 2026)</li>
<li><a href="https://luma.com/hbjqmcau" class="reference external" rel="external noopener noreferrer" target="_blank">Meetup #1 - Symfony Québec</a>: Montréal, Canada (October 28, 2026)</li>
</ul>
</div>
<div class="section">
<h2 id="call-to-action"><a class="headerlink" href="#call-to-action" title="Permalink to this headline">Call to Action</a></h2>
<ul>
    <li>Follow Symfony <a href="https://x.com/symfony" class="reference external" rel="external noopener noreferrer" target="_blank">on X</a>, <a href="https://mastodon.social/@symfony" class="reference external" rel="external noopener noreferrer" target="_blank">on Mastodon</a>, <a href="https://bsky.app/profile/symfony.com" class="reference external" rel="external noopener noreferrer" target="_blank">on Bluesky</a> and <a href="https://www.threads.net/@symfony" class="reference external" rel="external noopener noreferrer" target="_blank">on Threads</a> and share this article.</li>
<li><a href="https://feeds.feedburner.com/symfony/blog" class="reference external" rel="external noopener noreferrer" target="_blank">Subscribe to the Symfony blog RSS</a> and never miss a Symfony story again.</li>
</ul>
</div>
                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/a-week-of-symfony-1031-september-28-october-4-2026?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Javier Eguiluz ]]></dc:creator>
            <pubDate>Sun, 04 Oct 2026 09:39:00 +0200</pubDate>
            <comments>https://symfony.com/blog/a-week-of-symfony-1031-september-28-october-4-2026?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
                        <item>
            <title><![CDATA[New in Symfony 8.2: Performance Improvements]]></title>
            <link>https://symfony.com/blog/new-in-symfony-8-2-performance-improvements?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</link>
            <description>At Symfony, we&#039;re obsessed with performance, and Symfony 8.2 has plenty of
examples. Over the last few weeks, Nicolas Grekas profiled the Symfony Demo
application and a custom API project, turning every finding into a pull request.
The result is faster web…</description>
            <content:encoded><![CDATA[
                                <p>At Symfony, <strong>we're obsessed with performance</strong>, and Symfony 8.2 has plenty of
examples. Over the last few weeks, <a href="https://github.com/nicolas-grekas" class="reference external" rel="external noopener noreferrer" target="_blank">Nicolas Grekas</a> profiled the <a href="https://github.com/symfony/demo" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony Demo</a>
application and a custom API project, turning every finding into a pull request.</p>
<p>The result is <strong>faster web pages, APIs, console commands and cache builds, in
production and development</strong>.</p>
<div class="section">
<h2 id="faster-apis"><a class="headerlink" href="#faster-apis" title="Permalink to this headline">Faster APIs</a></h2>
<p>APIs that serialize and deserialize lots of objects see some of the biggest gains.
When <strong>normalizing objects</strong>, the Serializer computes each attribute's context
once, avoids copying the normalized array for each attribute and fetches the
discriminator mapping once per object instead of once per attribute. On an API
application that returns lists of 150 to 900 objects with serialization groups
and a name converter, list routes are <strong>14% to 24% faster</strong> (<a href="https://github.com/symfony/symfony/pull/66383" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66383</a>).</p>
<p>Reading a property with PropertyAccess now takes <strong>40% fewer PHP instructions</strong>,
so those list routes run another 6% to 8% fewer instructions (<a href="https://github.com/symfony/symfony/pull/66397" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66397</a>).
The <code translate="no" class="notranslate">snake_case</code> name converter also memoizes its results instead of running a
regular expression for every attribute of every object, which makes list routes
2% to 5% faster (<a href="https://github.com/symfony/symfony/pull/66384" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66384</a>).</p>
<p><strong>Denormalizing</strong> (e.g. when using <code translate="no" class="notranslate">#[MapRequestPayload]</code>) also got faster:</p>
<ul>
    <li>The property accessor is only created for classes that use
<code translate="no" class="notranslate">#[SerializedPath]</code>, instead of once per denormalized object (<a href="https://github.com/symfony/symfony/pull/66398" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66398</a>);</li>
<li>Constructor parameters are checked before calling PropertyInfo, which avoids
some lookups when denormalizing readonly DTOs. POST requests run
<strong>4% to 6% fewer PHP instructions</strong> (<a href="https://github.com/symfony/symfony/pull/66399" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66399</a>);</li>
<li>Class files are no longer read on each request to resolve the types of
constructor parameters (<a href="https://github.com/symfony/symfony/pull/66400" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66400</a>);</li>
<li>The property info of the classes mapped by the Serializer and the Validator
is now warmed up into a single cache file instead of being computed and stored
one entry at a time. POST requests are <strong>4% to 5% faster</strong> in production
(<a href="https://github.com/symfony/symfony/pull/66386" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66386</a>).</li>
</ul>
<p>PropertyInfo and TypeInfo were also optimized. Constructor docblocks are now
parsed once per class instead of once per property. Since property info isn't
cached in debug mode, this makes <strong>dev POST requests 24% to 38% faster</strong> (10 to
14 ms each) (<a href="https://github.com/symfony/symfony/pull/66382" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66382</a>). Class docblocks are also parsed once per type
context instead of five or six times (<a href="https://github.com/symfony/symfony/pull/66401" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66401</a>).</p>
<p>Other improvements:</p>
<ul>
    <li>The Validator reuses the <code translate="no" class="notranslate">IntlDateFormatter</code> used to format dates in
constraint violation messages instead of creating a new one each time
(<a href="https://github.com/symfony/symfony/pull/66396" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66396</a>);</li>
<li>The <code translate="no" class="notranslate">ReflectionExtractor</code> creates its inflector and type resolver only when
needed, so a request that serializes one object loads 10 fewer classes
(<a href="https://github.com/symfony/symfony/pull/66402" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66402</a>);</li>
<li>Exceptions are logged without turning them into <code translate="no" class="notranslate">FlattenException</code> objects
first. Logging a 422 response now takes 70 µs instead of 125 µs (<a href="https://github.com/symfony/symfony/pull/66392" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66392</a>).</li>
</ul>
<p>Finally, client errors (4xx HTTP responses) are now logged at the <code translate="no" class="notranslate">warning</code>
level instead of <code translate="no" class="notranslate">error</code> (<a href="https://github.com/symfony/symfony/pull/66391" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66391</a>). This better reflects a client mistake
and also saves work: with the default Monolog recipe (<code translate="no" class="notranslate">fingers_crossed</code> with
<code translate="no" class="notranslate">action_level: error</code>), 400, 403 and 422 responses no longer flush the request's
log buffer. A 422 response from <code translate="no" class="notranslate">#[MapRequestPayload]</code> is now <strong>3% to 4% faster</strong>.</p>
<div class="admonition admonition-note ">
    <p class="admonition-title">
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" width="24" height="24" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg>
                <span>Note</span>
    </p><p>This change modifies the level of some log messages. If you rely on them
(e.g. in alerts), check <a href="https://github.com/symfony/symfony/pull/66391" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66391</a> for the details. You can still
configure the log level per exception using <code translate="no" class="notranslate">framework.exceptions</code>
or the <code translate="no" class="notranslate">#[WithLogLevel]</code> attribute.</p>
</div>
</div>
<div class="section">
<h2 id="faster-production-requests"><a class="headerlink" href="#faster-production-requests" title="Permalink to this headline">Faster Production Requests</a></h2>
<p>The gains extend beyond APIs:</p>
<ul>
    <li>The <code translate="no" class="notranslate">PhpFilesAdapter</code> of the Cache component no longer tries to include
files that don't exist. A failed include costs about 10 µs, while checking for
the file takes 1 µs. On the Symfony Demo with a read-only cache directory and
without APCu, this saves <strong>830 µs per request</strong> (<a href="https://github.com/symfony/symfony/pull/66347" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66347</a>);</li>
<li><code translate="no" class="notranslate">ChainAdapter::get()</code> returns hits of its first adapter directly, without
creating two closures each time (<a href="https://github.com/symfony/symfony/pull/66346" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66346</a>);</li>
<li>The runtime mode is no longer resolved on web requests, where it's not needed.
This removes 8 of the 18 environment variable lookups of a production request
in the Symfony Demo (<a href="https://github.com/symfony/symfony/pull/66367" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66367</a>);</li>
<li>The HtmlSanitizer no longer parses inputs that don't contain <code translate="no" class="notranslate">&lt;</code> or <code translate="no" class="notranslate">&amp;</code>.
Sanitizing a short plain text string (very common when using the
<code translate="no" class="notranslate">sanitize_html</code> option in form fields) is now <strong>5 times cheaper</strong> and no
longer allocates 1.1 MB of memory on each call (<a href="https://github.com/symfony/symfony/pull/66389" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66389</a>).</li>
</ul>
</div>
<div class="section">
<h2 id="faster-development-environment"><a class="headerlink" href="#faster-development-environment" title="Permalink to this headline">Faster Development Environment</a></h2>
<p>You spend much of your day in the development environment, so it deserves some
attention too. The profiler's Config, Security, Request and Cache data collectors
now defer their static work (versions, bundles, role hierarchy, cURL commands,
etc.) until profiles are saved. With PHP-FPM, that happens after the response is
sent, saving up to 0.6 ms per collector per page
(<a href="https://github.com/symfony/symfony/pull/66365" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66365</a>, <a href="https://github.com/symfony/symfony/pull/66371" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66371</a>, <a href="https://github.com/symfony/symfony/pull/66372" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66372</a>, <a href="https://github.com/symfony/symfony/pull/66364" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66364</a>).</p>
<p>The Serializer data collector also aggregates nested calls as they happen,
instead of storing them all until the end. This saves 5 MB of memory on a dev
request that serializes 1,000 orders (<a href="https://github.com/symfony/symfony/pull/66390" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66390</a>).</p>
<p>If you use AssetMapper:</p>
<ul>
    <li>Serving an asset with the dev server no longer builds the profiler and Twig.
On the Symfony Demo, each asset is served in 6.3 ms instead of 7.0 ms
(<a href="https://github.com/symfony/symfony/pull/66373" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66373</a>);</li>
<li>Each cached asset is loaded once per request and from a single file, instead of
reading and unserializing two files each time it's needed. Rendering the
importmap of the Symfony Demo in dev now takes 2.4 ms instead of 4.7 ms
(<a href="https://github.com/symfony/symfony/pull/66369" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66369</a>).</li>
</ul>
</div>
<div class="section">
<h2 id="faster-cache-warmup-and-container-builds"><a class="headerlink" href="#faster-cache-warmup-and-container-builds" title="Permalink to this headline">Faster Cache Warmup and Container Builds</a></h2>
<p>Faster builds help on every deploy, when you run <code translate="no" class="notranslate">cache:clear</code> and
<code translate="no" class="notranslate">cache:warmup</code>, and in dev, whenever a config change rebuilds the container:</p>
<ul>
    <li>XLIFF translation files are first validated against a much smaller schema
that compiles 10 times faster (the full schema is still used when needed).
On the Symfony Demo, a cold <code translate="no" class="notranslate">cache:warmup</code> goes from 1.77 s to 1.57 s and a
dev request after editing a translation file goes from 82 ms to 67 ms
(<a href="https://github.com/symfony/symfony/pull/66375" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66375</a>);</li>
<li>The Twig cache warmer only compiles the form themes that your app can use,
instead of all the 13 themes included in Symfony. On the Symfony Demo, that's
10 fewer themes and a cold cache warmup that takes 2.11 s instead of 2.27 s
(<a href="https://github.com/symfony/symfony/pull/66381" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66381</a>). Templates listed twice under different names are also compiled
only once (<a href="https://github.com/symfony/symfony/pull/66370" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66370</a>);</li>
<li>Dumping the container for debug only clones the service definitions that hold
env vars (22 out of 1,344 in the Symfony Demo), instead of all of them. This
step goes from 49 ms to 14 ms (<a href="https://github.com/symfony/symfony/pull/66343" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66343</a>);</li>
<li>The <code translate="no" class="notranslate">XmlDumper</code> skips encoding plain ASCII values, which was almost 30% of
the dump time (<a href="https://github.com/symfony/symfony/pull/66379" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66379</a>);</li>
<li>The configuration trees used to generate the <code translate="no" class="notranslate">reference.php</code> and
<code translate="no" class="notranslate">schema.json</code> files are now built once instead of twice (<a href="https://github.com/symfony/symfony/pull/66378" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66378</a>).</li>
</ul>
</div>
<div class="section">
<h2 id="other-performance-improvements"><a class="headerlink" href="#other-performance-improvements" title="Permalink to this headline">Other Performance Improvements</a></h2>
<p>Symfony 8.2 also finish the response before the profiler saves its data, making
dev pages end 11 to 13 ms sooner with PHP-FPM (<a href="https://github.com/symfony/symfony/pull/66330" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66330</a>). Editing a
translation file no longer rebuilds the container either, cutting the next
request from about 790 ms to 85 ms (<a href="https://github.com/symfony/symfony/pull/66332" class="reference external" rel="external noopener noreferrer" target="_blank">PR #66332</a>).</p>
<p>This work also improved other projects: Twig traverses nodes faster (<a href="https://github.com/twigphp/Twig/pull/4976" class="reference external" rel="external noopener noreferrer" target="_blank">Twig PR #4976</a>)
and TwigComponent pre-lexes templates faster (<a href="https://github.com/symfony/ux/pull/3934" class="reference external" rel="external noopener noreferrer" target="_blank">Symfony UX PR #3934</a>). It even
reached PHP itself and <a href="https://github.com/lexbor/lexbor" class="reference external" rel="external noopener noreferrer" target="_blank">Lexbor</a>, the HTML5 parser behind PHP's <code translate="no" class="notranslate">Dom\HTMLDocument</code>:</p>
<ul>
    <li><code translate="no" class="notranslate">new ArrayIterator()</code> and <code translate="no" class="notranslate">new ArrayObject()</code>, which Twig nodes, Symfony
bags and Doctrine collections create in their <code translate="no" class="notranslate">getIterator()</code> methods, now
run about 180 fewer instructions per call (<a href="https://github.com/php/php-src/pull/23946" class="reference external" rel="external noopener noreferrer" target="_blank">PHP PR #23946</a>);</li>
<li>Lexbor no longer allocates 8 times the memory it needs for some of its internal
arrays, saving about 10 KB per parse (<a href="https://github.com/lexbor/lexbor/pull/428" class="reference external" rel="external noopener noreferrer" target="_blank">Lexbor PR #428</a>).</li>
</ul>
<p>Some other proposals are still under review:</p>
<ul>
    <li><code translate="no" class="notranslate">htmlspecialchars()</code> returns its input when there's nothing to encode, which
is the most common case in templates. On the Symfony Demo, which calls it 711
times per request, it becomes about 3.5 times cheaper (<a href="https://github.com/php/php-src/pull/23957" class="reference external" rel="external noopener noreferrer" target="_blank">PHP PR #23957</a>). Checking
for UTF-8 first when resolving the charset makes it another 40% cheaper on short
strings (<a href="https://github.com/php/php-src/pull/23961" class="reference external" rel="external noopener noreferrer" target="_blank">PHP PR #23961</a>);</li>
<li><code translate="no" class="notranslate">ArrayObject</code> and <code translate="no" class="notranslate">ArrayIterator</code> share the given arrays (copy-on-write)
instead of copying them, so a <code translate="no" class="notranslate">foreach</code> over these collections no longer
duplicates their items (<a href="https://github.com/php/php-src/pull/23945" class="reference external" rel="external noopener noreferrer" target="_blank">PHP PR #23945</a>). Creating an iterator while others
are alive (e.g. in a recursive walk of Twig nodes) is also faster (<a href="https://github.com/php/php-src/pull/23947" class="reference external" rel="external noopener noreferrer" target="_blank">PHP PR #23947</a>);</li>
<li>Lexbor preallocates less memory, so parsing a small document needs about
200 KB instead of 1 MB (<a href="https://github.com/lexbor/lexbor/pull/427" class="reference external" rel="external noopener noreferrer" target="_blank">Lexbor PR #427</a>).</li>
</ul>
</div>
<div class="section">
<h2 id="why-care-about-sub-millisecond-improvements"><a class="headerlink" href="#why-care-about-sub-millisecond-improvements" title="Permalink to this headline">Why Care About Sub-Millisecond Improvements?</a></h2>
<p>Some of the changes mentioned above save 70 microseconds per request (that's
2,000 times faster than an average human blink). Why care about those? Because
in a mature project like Symfony, you can't find one magic change that makes
everything twice as fast. That's why we keep making it faster one small
improvement at a time.</p>
<p>Upgrade to Symfony 8.2 when it's <a href="https://symfony.com/releases/8.2" class="reference external">released in November</a> to get all of this
without changing a line of your application. If profiling your own application
reveals something slow in Symfony, please tell us. We care about every microsecond.</p>
</div>
                <hr style="margin-bottom: 5px" />
                <div style="font-size: 90%">
                    <a href="https://symfony.com/sponsor">Sponsor</a> the Symfony project.
                </div>
            ]]></content:encoded>
            <guid isPermaLink="false">https://symfony.com/blog/new-in-symfony-8-2-performance-improvements?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed</guid>
            <dc:creator><![CDATA[ Javier Eguiluz ]]></dc:creator>
            <pubDate>Fri, 02 Oct 2026 09:27:00 +0200</pubDate>
            <comments>https://symfony.com/blog/new-in-symfony-8-2-performance-improvements?utm_source=Symfony%20Blog%20Feed&amp;utm_medium=feed#comments-list</comments>
        </item>
            </channel>
</rss>
