<?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: Victor</title>
    <description>The latest articles on DEV Community by Victor (@victorprdh).</description>
    <link>https://dev.to/victorprdh</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F906661%2F9b7ea088-5375-48a2-95aa-7892a1b8b6b3.jpeg</url>
      <title>DEV Community: Victor</title>
      <link>https://dev.to/victorprdh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/victorprdh"/>
    <language>en</language>
    <item>
      <title>Comment j’ai construit le site d’Illis Digital avec Astro</title>
      <dc:creator>Victor</dc:creator>
      <pubDate>Tue, 10 Mar 2026 10:02:06 +0000</pubDate>
      <link>https://dev.to/victorprdh/comment-jai-construit-le-site-dillis-digital-avec-astro-mmc</link>
      <guid>https://dev.to/victorprdh/comment-jai-construit-le-site-dillis-digital-avec-astro-mmc</guid>
      <description>&lt;p&gt;Pour le site de &lt;strong&gt;&lt;a href="https://illis-digital.fr" rel="noopener noreferrer"&gt;Illis Digital&lt;/a&gt;&lt;/strong&gt;, mon objectif était simple : créer un site &lt;strong&gt;rapide, moderne et facile à maintenir&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Plutôt que de partir sur un framework lourd, j’ai choisi &lt;strong&gt;&lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;Astro&lt;/a&gt;&lt;/strong&gt;, un framework qui met l’accent sur la &lt;strong&gt;performance et les sites orientés contenu&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pourquoi Astro ?
&lt;/h2&gt;

&lt;p&gt;Astro se distingue par sa philosophie : &lt;strong&gt;envoyer le moins de JavaScript possible au navigateur&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;Contrairement à beaucoup de frameworks front-end classiques, les pages sont générées en &lt;strong&gt;HTML statique par défaut&lt;/strong&gt;, et le JavaScript n’est chargé que lorsque c’est nécessaire.&lt;/p&gt;

&lt;p&gt;Les avantages sont immédiats :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;des &lt;strong&gt;pages ultra rapides&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;SEO optimisé&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;une &lt;strong&gt;complexité côté client réduite&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Astro utilise également l’architecture dite des &lt;strong&gt;“îlots”&lt;/strong&gt; : la majeure partie du site reste statique, et seuls certains composants interactifs chargent du JavaScript. Cela permet de combiner &lt;strong&gt;performance et interactivité&lt;/strong&gt; sans alourdir le site.&lt;/p&gt;




&lt;h2&gt;
  
  
  Construire le site d’Illis Digital
&lt;/h2&gt;

&lt;p&gt;Pour Illis Digital, j’ai structuré le site autour de composants réutilisables et de pages statiques générées au moment du build.  &lt;/p&gt;

&lt;p&gt;Le résultat : un site léger, moderne et prêt à évoluer, tout en restant facile à maintenir et performant sur tous les devices.&lt;/p&gt;

&lt;p&gt;Astro permet également d’intégrer facilement d’autres outils ou frameworks front-end si besoin, tout en gardant le contrôle sur les performances.&lt;/p&gt;




&lt;h2&gt;
  
  
  Illis Digital en quelques mots
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://illis-digital.fr" rel="noopener noreferrer"&gt;Illis Digital&lt;/a&gt;&lt;/strong&gt; a pour mission de créer des sites web &lt;strong&gt;modernes, rapides et efficaces&lt;/strong&gt; pour les entreprises.  &lt;/p&gt;

&lt;p&gt;Le web devient de plus en plus complexe, mais les utilisateurs attendent toujours :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;un site &lt;strong&gt;rapide&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;une &lt;strong&gt;navigation fluide&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;une &lt;strong&gt;expérience utilisateur optimale&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C’est exactement ce que permet Astro, et c’est pour ça que ce projet a été un vrai plaisir à construire.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>agence</category>
      <category>siteweb</category>
    </item>
    <item>
      <title>Demeter's Law in PHP: Principle, Examples, and Best Practices</title>
      <dc:creator>Victor</dc:creator>
      <pubDate>Mon, 03 Nov 2025 07:51:15 +0000</pubDate>
      <link>https://dev.to/victorprdh/demeters-law-in-php-principle-examples-and-best-practices-4adh</link>
      <guid>https://dev.to/victorprdh/demeters-law-in-php-principle-examples-and-best-practices-4adh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;📝 This article is an English translation of the original French version available here: &lt;a href="https://victor-prdh.com/blog/03-loi-de-demeter.md/" rel="noopener noreferrer"&gt;https://victor-prdh.com/blog/03-loi-de-demeter.md/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Demeter's Law in PHP: Writing Code That Talks Less… but Better
&lt;/h2&gt;

&lt;p&gt;In software development, we often hear about &lt;strong&gt;best practices&lt;/strong&gt;: decoupling, separation of concerns, SOLID principles… But there is one, sometimes overlooked, that deserves our attention: &lt;strong&gt;Demeter's Law&lt;/strong&gt;. Also known as the &lt;em&gt;principle of least knowledge&lt;/em&gt;, it helps write more robust, readable, and maintainable code.&lt;/p&gt;

&lt;p&gt;In this article, we will see what it entails, why it is useful, and how to apply it practically in your PHP and Symfony projects.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Demeter's Law?
&lt;/h2&gt;

&lt;p&gt;Formulated in the late 1980s at MIT, Demeter's Law is based on a simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“An object should only talk to its immediate friends, not to the friends of its friends.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, a class should limit its knowledge of the system. It should only interact with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;itself (its own methods),
&lt;/li&gt;
&lt;li&gt;its direct attributes,
&lt;/li&gt;
&lt;li&gt;its method parameters,
&lt;/li&gt;
&lt;li&gt;the objects it creates,
&lt;/li&gt;
&lt;li&gt;and possibly global objects (like singletons, though these should be avoided).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to prevent code from being too dependent on the internal structure of other objects.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example of Demeter Law Violation
&lt;/h2&gt;

&lt;p&gt;Here’s a common example:&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="nv"&gt;$city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCustomer&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;getAddress&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;getCity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, to get the city of a customer, the &lt;code&gt;Order&lt;/code&gt; object must expose its &lt;code&gt;Customer&lt;/code&gt;, which exposes its &lt;code&gt;Address&lt;/code&gt;, which exposes its &lt;code&gt;City&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is what we call the &lt;strong&gt;train wreck pattern&lt;/strong&gt;: a long chain of calls showing that we know far too much about the internal structure of the object.&lt;/p&gt;




&lt;h2&gt;
  
  
  Corrected Example
&lt;/h2&gt;

&lt;p&gt;A better approach is to delegate responsibility to the appropriate objects:&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;Order&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;Customer&lt;/span&gt; &lt;span class="nv"&gt;$customer&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;getCustomerCity&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;customer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCity&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;Then, usage 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="nv"&gt;$city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCustomerCity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, the &lt;code&gt;Order&lt;/code&gt; object becomes &lt;strong&gt;responsible for how the information is accessed&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
If the internal structure of &lt;code&gt;Customer&lt;/code&gt; changes tomorrow (for example, if the address is no longer directly linked to the &lt;code&gt;Customer&lt;/code&gt; object), the calling code will not be impacted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Benefits
&lt;/h2&gt;

&lt;p&gt;Respecting Demeter's Law brings several immediate benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Robustness&lt;/strong&gt;: internal changes do not affect calling code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulation&lt;/strong&gt;: objects hide their internal details.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability&lt;/strong&gt;: fewer chained calls, code expresses directly what we want.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: it's easier to test a single method than to simulate a long object chain.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Demeter's Law is a simple but powerful rule: &lt;em&gt;“only talk to your close friends.”&lt;/em&gt;&lt;br&gt;&lt;br&gt;
By avoiding excessive chained calls and delegating responsibilities to the right objects, you get code that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clearer,
&lt;/li&gt;
&lt;li&gt;more robust,
&lt;/li&gt;
&lt;li&gt;easier to maintain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take a moment to review your code: how many successive &lt;code&gt;-&amp;gt;&lt;/code&gt; calls do you find?&lt;br&gt;&lt;br&gt;
It might be a sign that it's time to apply Demeter's Law.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about you?
&lt;/h2&gt;

&lt;p&gt;Share your experience or tips with me on &lt;a href="https://www.linkedin.com/in/victor-prdh/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; — happy to chat!&lt;/p&gt;

</description>
      <category>php</category>
      <category>cleancode</category>
      <category>poo</category>
      <category>programming</category>
    </item>
    <item>
      <title>Traits in PHP – a powerful yet underused tool?</title>
      <dc:creator>Victor</dc:creator>
      <pubDate>Wed, 21 May 2025 09:07:32 +0000</pubDate>
      <link>https://dev.to/victorprdh/traits-in-php-a-powerful-yet-underused-tool-7k6</link>
      <guid>https://dev.to/victorprdh/traits-in-php-a-powerful-yet-underused-tool-7k6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;📝 This article is an English translation of the original French version available here: &lt;a href="https://victor-prdh.com/blog/02-traits-avec-php/" rel="noopener noreferrer"&gt;https://victor-prdh.com/blog/02-traits-avec-php/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PHP does not support multiple inheritance. To work around this limitation, Traits were introduced in PHP 5.4. They allow injecting methods into several classes without using class inheritance.&lt;/p&gt;

&lt;p&gt;When misused, they can harm readability and maintainability. When mastered, they are a great tool to structure shared code. Here's an overview of use cases, best practices, and common pitfalls.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why Traits?
&lt;/h2&gt;

&lt;p&gt;In PHP, a class can only inherit from one parent class. Traits allow factoring reusable behavior into multiple different classes.&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;trait&lt;/span&gt; &lt;span class="nc"&gt;LoggerTrait&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;log&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;$message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[LOG] &lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&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;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ServiceA&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;LoggerTrait&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ServiceB&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;LoggerTrait&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;h2&gt;
  
  
  2. Practical use cases
&lt;/h2&gt;

&lt;p&gt;Traits are useful for encapsulating cross-cutting behaviors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared logger&lt;/strong&gt;&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;trait&lt;/span&gt; &lt;span class="nc"&gt;LoggerTrait&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;log&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;$message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d H:i:s'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;" - &lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&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;&lt;strong&gt;Soft delete&lt;/strong&gt;&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;trait&lt;/span&gt; &lt;span class="nc"&gt;SoftDeleteTrait&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nc"&gt;\DateTime&lt;/span&gt; &lt;span class="nv"&gt;$deletedAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;delete&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&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;deletedAt&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;\DateTime&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;isDeleted&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;deletedAt&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&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;h2&gt;
  
  
  3. Best practices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;One Trait = one responsibility&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Avoid catch-all Traits. Each Trait should have a clear and focused purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicit method names&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Clear names help avoid collisions. Prefer &lt;code&gt;handleForm()&lt;/code&gt; over &lt;code&gt;handle()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No hidden dependencies&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A Trait should not assume the existence of properties or methods unless clearly defined or injected.&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="c1"&gt;// Bad&lt;/span&gt;
&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;BrokenTrait&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;doSomething&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&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;repository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// hidden dependency&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Good&lt;/span&gt;
&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;WellDefinedTrait&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;RepositoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$repository&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;setRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;RepositoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$repo&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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;repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$repo&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;doSomething&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&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;repository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&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;h2&gt;
  
  
  4. Pitfalls to avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Method name collisions&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If two Traits define the same method, you must resolve the conflict explicitly.&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;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sayHello&lt;/span&gt; &lt;span class="k"&gt;insteadof&lt;/span&gt; &lt;span class="nc"&gt;A&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;&lt;strong&gt;Overuse&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Too many Traits in a single class can reduce clarity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;False abstraction&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Traits are not a replacement for solid object-oriented design. If you need polymorphism or hierarchy, prefer interfaces or abstract classes.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Alternatives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Interface + abstract class: more restrictive but often clearer.&lt;/li&gt;
&lt;li&gt;Composition: delegate responsibilities to other objects.&lt;/li&gt;
&lt;li&gt;Dedicated services: in Symfony, injecting a service is often cleaner.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Traits are a useful tool to structure shared code—if used with moderation and discipline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep them focused.&lt;/li&gt;
&lt;li&gt;Avoid hidden dependencies.&lt;/li&gt;
&lt;li&gt;Prefer composition when Traits become too heavy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Well used, Traits simplify. Misused, they complicate.&lt;/strong&gt; It's your call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about you?
&lt;/h2&gt;

&lt;p&gt;Were you familiar with Traits in PHP?&lt;br&gt;&lt;br&gt;
Share your experience or tips with me on &lt;a href="https://www.linkedin.com/in/victor-prdh/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; — happy to chat!&lt;/p&gt;

</description>
      <category>php</category>
      <category>cleancode</category>
      <category>poo</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Victor</dc:creator>
      <pubDate>Mon, 19 May 2025 10:06:36 +0000</pubDate>
      <link>https://dev.to/victorprdh/-2hf6</link>
      <guid>https://dev.to/victorprdh/-2hf6</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/victorprdh/boosting-performance-with-symfony-httpclient-and-parallel-requests-14g7" class="crayons-story__hidden-navigation-link"&gt;Boosting Performance with Symfony HttpClient and Parallel Requests&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/victorprdh" class="crayons-avatar  crayons-avatar--l  "&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F906661%2F9b7ea088-5375-48a2-95aa-7892a1b8b6b3.jpeg" alt="victorprdh profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/victorprdh" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Victor
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Victor
                
              
              &lt;div id="story-author-preview-content-2480427" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/victorprdh" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F906661%2F9b7ea088-5375-48a2-95aa-7892a1b8b6b3.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Victor&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/victorprdh/boosting-performance-with-symfony-httpclient-and-parallel-requests-14g7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 12 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/victorprdh/boosting-performance-with-symfony-httpclient-and-parallel-requests-14g7" id="article-link-2480427"&gt;
          Boosting Performance with Symfony HttpClient and Parallel Requests
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/symfony"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;symfony&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/php"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;php&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/victorprdh/boosting-performance-with-symfony-httpclient-and-parallel-requests-14g7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/victorprdh/boosting-performance-with-symfony-httpclient-and-parallel-requests-14g7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>symfony</category>
      <category>php</category>
      <category>performance</category>
    </item>
    <item>
      <title>Boosting Performance with Symfony HttpClient and Parallel Requests</title>
      <dc:creator>Victor</dc:creator>
      <pubDate>Mon, 12 May 2025 14:52:05 +0000</pubDate>
      <link>https://dev.to/victorprdh/boosting-performance-with-symfony-httpclient-and-parallel-requests-14g7</link>
      <guid>https://dev.to/victorprdh/boosting-performance-with-symfony-httpclient-and-parallel-requests-14g7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;📝 This article is an English translation of the original French version available here: &lt;a href="https://victor-prdh.com/blog/01-requete-asynchrone-symfony/" rel="noopener noreferrer"&gt;https://victor-prdh.com/blog/01-requete-asynchrone-symfony/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When developing a Symfony application that communicates with multiple APIs, it's tempting to send requests one after another. However, this approach can quickly become a bottleneck.&lt;/p&gt;

&lt;p&gt;Fortunately, Symfony’s &lt;code&gt;HttpClient&lt;/code&gt; component makes it easy to manage &lt;strong&gt;multiple parallel requests&lt;/strong&gt; — without threads, promises, or workers.&lt;/p&gt;

&lt;p&gt;In this article, I’ll show you how to take advantage of this feature to improve performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Classic Problem: Sequential API Calls
&lt;/h2&gt;

&lt;p&gt;Let’s take a simple example. You need to query 5 APIs to retrieve and merge data. Most developers would instinctively write something like this:&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="nv"&gt;$results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$urls&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;)&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;$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="nv"&gt;$results&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&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;toArray&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;This code works, but it’s &lt;strong&gt;slow&lt;/strong&gt;: each request waits for the previous one to complete before starting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: &lt;code&gt;stream()&lt;/code&gt; for Concurrent Requests
&lt;/h2&gt;

&lt;p&gt;Symfony provides a more powerful API with the &lt;code&gt;stream()&lt;/code&gt; method. It allows you to fire off all requests at once and process responses as soon as they’re ready — avoiding unnecessary blocking.&lt;/p&gt;

&lt;p&gt;Here’s how:&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="nv"&gt;$responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$urls&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$responses&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Read responses as they come in&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$responses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&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="nv"&gt;$chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chunk&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isLast&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&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;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// Process the result&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;This code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;sends all requests in parallel&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;processes each response as soon as it’s complete&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;significantly reduces total execution time&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Performance Gains
&lt;/h2&gt;

&lt;p&gt;Gains depend on your target APIs, but in many cases, you can &lt;strong&gt;cut total response time by a factor of 2 to 10&lt;/strong&gt;, especially when APIs take 300 to 500 ms to respond individually.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use This Method
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;stream()&lt;/code&gt; whenever you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple independent API calls to make&lt;/li&gt;
&lt;li&gt;simple response processing logic&lt;/li&gt;
&lt;li&gt;slow or numerous third-party APIs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;Symfony HttpClient allows you to write simple, readable, and &lt;strong&gt;asynchronous code&lt;/strong&gt; without adding unnecessary technical complexity.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;stream()&lt;/code&gt; method is &lt;strong&gt;a powerful tool&lt;/strong&gt; to add to your toolbox for any API-driven Symfony project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Go Further
&lt;/h2&gt;

&lt;p&gt;To explore the full capabilities of &lt;code&gt;HttpClient&lt;/code&gt; and &lt;code&gt;stream()&lt;/code&gt;, check out the &lt;a href="https://symfony.com/doc/current/http_client.html" rel="noopener noreferrer"&gt;official Symfony documentation&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About You?
&lt;/h2&gt;

&lt;p&gt;Have you already used &lt;code&gt;stream()&lt;/code&gt; in your Symfony projects?&lt;br&gt;&lt;br&gt;
Share your feedback or tips with me on &lt;a href="https://www.linkedin.com/in/victor-prdh/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; — I’d love to chat!&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>php</category>
      <category>performance</category>
    </item>
    <item>
      <title>Adding ReCaptha to Symfony</title>
      <dc:creator>Victor</dc:creator>
      <pubDate>Wed, 24 Aug 2022 19:03:36 +0000</pubDate>
      <link>https://dev.to/victorprdh/adding-recaptha-to-symfony-2m60</link>
      <guid>https://dev.to/victorprdh/adding-recaptha-to-symfony-2m60</guid>
      <description>&lt;h2&gt;
  
  
  Why ReCaptcha are required today ?
&lt;/h2&gt;

&lt;p&gt;With all these bots who are spamming the web, having a recaptcha to protecting your contact or sign-up section. It's pretty simple to set-up, nearly 5 minutes when you know the steps, for this tutorial we gonna say 15 minutes max !&lt;/p&gt;

&lt;h3&gt;
  
  
  Sign up to Google Console
&lt;/h3&gt;

&lt;p&gt;If you want to integrate a ReCaptcha to your website, you need to ask google give you token for be able to use their service. It's very simple and no verifications are required. Just go to &lt;a href="https://www.google.com/recaptcha/admin" rel="noopener noreferrer"&gt;the ReCaptcha console&lt;/a&gt; and fill your informations.&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.amazonaws.com%2Fuploads%2Farticles%2Fl1o78pnzh2bgm9bgol0p.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fl1o78pnzh2bgm9bgol0p.png" alt="ReCaptcha console example" width="800" height="661"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in this example, i added a name, choosed the ReCaptcha V2 and added my domain name. The little trick is i added &lt;code&gt;localhost&lt;/code&gt; too. With this domain added on the console i will be able to test it on my local server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coding time
&lt;/h3&gt;

&lt;p&gt;Now go to your symfony project. The first step is to require the recaptcha-bundle with:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer require victor-prdh/recaptcha-bundle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  With Symfony flex
&lt;/h4&gt;

&lt;p&gt;You can quickly configure this bundle by using symfony/flex:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;answer &lt;strong&gt;no&lt;/strong&gt; for &lt;code&gt;google/recaptcha&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;answer &lt;strong&gt;yes&lt;/strong&gt; for &lt;code&gt;victor-prdh/recaptcha-bundle&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If everything is good, you must have the bundle registred in the &lt;em&gt;"bundles.php"&lt;/em&gt; file of your config folder (&lt;em&gt;"config/bundles.php"&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;//config/bunldes.php
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="mf"&gt;...&lt;/span&gt;
    &lt;span class="nc"&gt;VictorPrdh\RecaptchaBundle\RecaptchaBundle&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'all'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&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;Just add it if you dont see this line.&lt;/p&gt;

&lt;p&gt;You can directly go to Usage section&lt;/p&gt;

&lt;h4&gt;
  
  
  Without Symfony flex
&lt;/h4&gt;

&lt;p&gt;If you don't want / you can't  use the flex recipe you can create a &lt;em&gt;"recaptcha.yaml"&lt;/em&gt; file in your config folder (&lt;em&gt;"config/packages/recaptcha.yaml"&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config/packages/recaptcha.yaml&lt;/span&gt;
&lt;span class="na"&gt;recaptcha&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;google_site_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%env(GOOGLE_RECAPTCHA_SITE_KEY)%'&lt;/span&gt;
  &lt;span class="na"&gt;google_secret_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%env(GOOGLE_RECAPTCHA_SECRET_KEY)%'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you created this config file, you can go in your &lt;em&gt;".env"&lt;/em&gt; file and add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;###&amp;gt; victor-prdh/recaptcha ###
# https://www.google.com/recaptcha/admin  &amp;lt;--- get keys here
GOOGLE_RECAPTCHA_SITE_KEY='your site key'
GOOGLE_RECAPTCHA_SECRET_KEY='your secret key'
###&amp;lt; victor-prdh/recaptcha ###
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's time for update the bundle, if you don't do it, your keys will not be used by the bundle.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer update victor-prdh/recaptcha-bundle&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Integration in Symfony Form
&lt;/h3&gt;

&lt;p&gt;You have now a &lt;em&gt;"ReCaptchaType"&lt;/em&gt; class available for all your forms. You can use it in your FormBuilder like a &lt;em&gt;"TextType&lt;/em&gt;" or &lt;em&gt;"PasswordType"&lt;/em&gt;:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Form&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;VictorPrdh\RecaptchaBundle\Form\ReCaptchaType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskType&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractType&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;buildForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;FormBuilderInterface&lt;/span&gt; &lt;span class="nv"&gt;$builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$builder&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"recaptcha"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ReCaptchaType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&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;h3&gt;
  
  
  Display error on your Twig view
&lt;/h3&gt;

&lt;p&gt;Once you create the form, you render it as usual with Symfony. You can show it in your twig file like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;

    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;form.recaptcha&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; 
    &lt;span class="c"&gt;{# must be the same name of this put on the FormBuilder #}&lt;/span&gt;

    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form_errors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;form.recaptcha&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="c"&gt;{# That will display the error of the captcha to user #}&lt;/span&gt;

&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voilà ! You have your ReCapthca verification set-up on your symfony project !&lt;/p&gt;

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