<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stiven Llupa</title>
    <description>The latest articles on DEV Community by Stiven Llupa (@stivenllupa).</description>
    <link>https://dev.to/stivenllupa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3790338%2Fba1429ad-55df-4fdf-b2a7-10f1ffe097c1.jpg</url>
      <title>DEV Community: Stiven Llupa</title>
      <link>https://dev.to/stivenllupa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stivenllupa"/>
    <language>en</language>
    <item>
      <title>The Scenic Route to TYPO3 DevDays</title>
      <dc:creator>Stiven Llupa</dc:creator>
      <pubDate>Tue, 11 Aug 2026 08:16:24 +0000</pubDate>
      <link>https://dev.to/stivenllupa/the-scenic-route-to-typo3-devdays-2kba</link>
      <guid>https://dev.to/stivenllupa/the-scenic-route-to-typo3-devdays-2kba</guid>
      <description>&lt;p&gt;Maps gave me two options to the conference venue: walk alongside the highway, or cut through "the park."&lt;/p&gt;

&lt;p&gt;Naturally, I picked the park. Who wouldn't with this in its entry? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F27g6jvg85l2di9yw1yjx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F27g6jvg85l2di9yw1yjx.jpg" alt=" " width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What Maps called a park was, in fact, a forest 🌲. So there I was, conference-ready, laptop bag slung over my shoulder, nice shoes and all, strolling through actual woods like I was auditioning for a hiking ad. 🚶&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvpi3lpuczzdq2lw98e3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvpi3lpuczzdq2lw98e3.jpg" alt=" " width="760" height="1009"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further in, the path was flooded. Someone before me had improvised a bridge out of what I can only describe as twigs (they were, structurally speaking, not twigs, and I chose not to think too hard about that while crossing).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F50fe9989obtdiu7ceiy2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F50fe9989obtdiu7ceiy2.jpg" alt=" " width="760" height="1009"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, just when I was sure I'd finally reach the venue, the trees opened up onto a cornfield. A full, sprawling cornfield. I stood there for a second, looked around, and just laughed. &lt;em&gt;This is awesome&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnxonoz9e8at4ptueausl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnxonoz9e8at4ptueausl.jpg" alt=" " width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there it was: the conference center, right on the other side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F64mjzb9me4uwh4vbljgn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F64mjzb9me4uwh4vbljgn.jpg" alt=" " width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A colleague and I had been invited over from the Symfony community and TYPO3 has adopted a good chunk of Symfony components under the hood, so the overlap made sense. TYPO3 DevDays itself kept that same energy going: warm, welcoming, genuinely good vibes from start to finish. But the thing that made me think more than the forest, the bridge, or the corn.&lt;/p&gt;

&lt;p&gt;It was how many speakers, across totally different talks, kept circling back to the same idea: &lt;strong&gt;build for your users&lt;/strong&gt;. Not for the framework, not for the demo, not for what's technically impressive, but for the actual person on the other end.&lt;/p&gt;

&lt;p&gt;Now that the walk and conference has finished, I am stuck with two things. First, how crazy it was to walk through a forest to reach a tech-con 😅 and second, the importance of end user feels like it is always implied, but never really actively worked on. (&lt;em&gt;I am look at you 👀, stake-holders&lt;/em&gt; 🧑‍💼) &lt;/p&gt;

</description>
      <category>typo3</category>
      <category>symfony</category>
      <category>adventure</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Defensive Programming can be very easy with Symfony HttpClient</title>
      <dc:creator>Stiven Llupa</dc:creator>
      <pubDate>Sat, 28 Feb 2026 18:37:39 +0000</pubDate>
      <link>https://dev.to/stivenllupa/defensive-programming-can-be-very-easy-with-symfony-httpclient-25g8</link>
      <guid>https://dev.to/stivenllupa/defensive-programming-can-be-very-easy-with-symfony-httpclient-25g8</guid>
      <description>&lt;p&gt;If your app lets users submit URLs that you then fetch, for link previews, webhooks, or RSS feeds, you have a serious security problem waiting to happen.&lt;/p&gt;

&lt;p&gt;An attacker can submit something like &lt;code&gt;http://127.0.0.1/admin&lt;/code&gt; or &lt;code&gt;http://169.254.169.254&lt;/code&gt; (AWS metadata endpoint) and your server will happily fetch it. &lt;/p&gt;

&lt;p&gt;That's called a &lt;strong&gt;S&lt;/strong&gt;erver-&lt;strong&gt;S&lt;/strong&gt;ide &lt;strong&gt;R&lt;/strong&gt;equest &lt;strong&gt;F&lt;/strong&gt;orgery attack, or &lt;strong&gt;SSRF&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Symfony has a built-in solution: &lt;a href="https://github.com/symfony/symfony/blob/8.1/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php" rel="noopener noreferrer"&gt;NoPrivateNetworkHttpClient&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LinkPreviewController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;HttpClientInterface&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="na"&gt;#[Route('/api/preview', methods: ['POST'])]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPayload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'url'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LinkPreviewController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;HttpClientInterface&lt;/span&gt; &lt;span class="nv"&gt;$safeClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;HttpClientInterface&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;safeClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NoPrivateNetworkHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nv"&gt;$client&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Route('/api/preview', methods: ['POST'])]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPayload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'url'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;safeClient&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a decorator, so you just wrap your existing client &amp;amp; no other changes needed. Follow the &lt;a href="https://symfony.com/doc/current/http_client.html#ssrf-server-side-request-forgery-handling" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to set your specific IPs or IP ranges that you want to disallow.&lt;/p&gt;

&lt;p&gt;If you fetch user-submitted URLs and you're not using this, you should be.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtube.com/shorts/V3qjRbszjW8" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Watch in on YouTube&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>php</category>
      <category>symfony</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Country codes and regional differences</title>
      <dc:creator>Stiven Llupa</dc:creator>
      <pubDate>Sat, 28 Feb 2026 09:38:49 +0000</pubDate>
      <link>https://dev.to/stivenllupa/country-codes-and-regional-differences-5fmh</link>
      <guid>https://dev.to/stivenllupa/country-codes-and-regional-differences-5fmh</guid>
      <description>&lt;p&gt;Here's a little-known Symfony trick for apps that need to support Kosovo as a country.&lt;/p&gt;

&lt;p&gt;Kosovo uses the code &lt;code&gt;XK&lt;/code&gt;, but that's not an official ISO 3166 code. It is what is called a &lt;strong&gt;user-assigned&lt;/strong&gt; code, meaning Symfony Intl component doesn't include it by default.&lt;/p&gt;

&lt;p&gt;So when you call &lt;code&gt;Countries::getNames()&lt;/code&gt; from the Symfony Intl component, Kosovo simply won't appear.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Intl\Countries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$countries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Countries&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getNames&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$countries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'XK'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="nc"&gt;Countries&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'XK'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Throws MissingResourceException&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix? Just set this environment variable in your .env file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env&lt;/span&gt;

&lt;span class="nv"&gt;SYMFONY_INTL_WITH_USER_ASSIGNED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Symfony will now also recognize &lt;code&gt;XK&lt;/code&gt;, &lt;code&gt;XKK&lt;/code&gt;, and numeric code &lt;code&gt;983&lt;/code&gt; for Kosovo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Intl\Countries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Countries&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'XK'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 'Kosovo'&lt;/span&gt;

&lt;span class="nc"&gt;Countries&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getAlpha2Code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'XKK'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// XK&lt;/span&gt;
&lt;span class="nc"&gt;Countries&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getAlpha3Code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'XK'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// XKK  &lt;/span&gt;
&lt;span class="nc"&gt;Countries&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getNumericCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'XK'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 983&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A one-liner that saves you from building a workaround. Super useful if you're building apps for any region that needs user-assigned country codes.&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>php</category>
      <category>icu</category>
      <category>dx</category>
    </item>
    <item>
      <title>Stop writing the same regex for #[Route]</title>
      <dc:creator>Stiven Llupa</dc:creator>
      <pubDate>Fri, 27 Feb 2026 18:08:10 +0000</pubDate>
      <link>https://dev.to/stivenllupa/stop-writing-the-same-regex-for-route-o2c</link>
      <guid>https://dev.to/stivenllupa/stop-writing-the-same-regex-for-route-o2c</guid>
      <description>&lt;p&gt;Did you know Symfony ships with a built-in class full of pre-defined route requirement patterns?&lt;/p&gt;

&lt;p&gt;It's called &lt;a href="https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/Routing/Requirement/Requirement.php" rel="noopener noreferrer"&gt;Requirement&lt;/a&gt;, and it lives in &lt;code&gt;Symfony\Component\Routing\Requirement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of writing your own regex for common route parameters like UUIDs, slugs, date formats, or locale codes, you &lt;em&gt;can&lt;/em&gt; just reference a constant.&lt;/p&gt;

&lt;p&gt;So instead of this mess in your route attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users/{id}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'[0-9a-f]{8}-[0-9a-f]{4}-'&lt;/span&gt;
          &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'[0-9a-f]{4}-[0-9a-f]{4}-'&lt;/span&gt;
          &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'[0-9a-f]{12}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users/{id}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Requirement&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog/{slug}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'slug'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'[a-z0-9]+(?:-[a-z0-9]+)*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$slug&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog/{slug}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'slug'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Requirement&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ASCII_SLUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$slug&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It includes constants for all UUID formats, common date, ASCII slugs, and your usual suspects.&lt;/p&gt;

&lt;p&gt;Stop rewriting the same regex. Symfony already did it for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtube.com/shorts/OatqlyRgNSg" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Watch it on YouTube&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>php</category>
      <category>symfony</category>
      <category>dx</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
