<?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: Ion Bazan</title>
    <description>The latest articles on DEV Community by Ion Bazan (@ionbazan).</description>
    <link>https://dev.to/ionbazan</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%2F609877%2F29397ca0-b0fe-4a4b-b447-04c3b7723f6a.jpeg</url>
      <title>DEV Community: Ion Bazan</title>
      <link>https://dev.to/ionbazan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ionbazan"/>
    <language>en</language>
    <item>
      <title>Turn a country code into an emoji flag (US ➡️ 🇺🇸)</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Tue, 21 May 2024 05:38:31 +0000</pubDate>
      <link>https://dev.to/ionbazan/turn-a-country-code-into-an-emoji-flag-us--360a</link>
      <guid>https://dev.to/ionbazan/turn-a-country-code-into-an-emoji-flag-us--360a</guid>
      <description>&lt;p&gt;Flag emojis are a fun and visual way to represent countries and regions. These emojis are part of the &lt;a href="https://en.wikipedia.org/wiki/Regional_indicator_symbol"&gt;Unicode standard&lt;/a&gt; and are created using a pair of regional indicator symbols.&lt;/p&gt;

&lt;p&gt;In this article, we will explore how to convert 2-letter &lt;a href="https://en.wikipedia.org/wiki/ISO_3166-1"&gt;ISO 3166-1&lt;/a&gt; country codes to flag emojis in &lt;strong&gt;Go&lt;/strong&gt;, &lt;strong&gt;PHP&lt;/strong&gt; and &lt;strong&gt;TypeScript&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Flag Emojis
&lt;/h2&gt;

&lt;p&gt;Flag emojis are composed of two Unicode characters, each representing a regional indicator symbol. For example, the flag of the United States (🇺🇸) is created by placing the Unicode points for the regional indicators "🇺" and "🇸" next to each other.&lt;/p&gt;

&lt;p&gt;These Unicode points start at &lt;a href="https://www.compart.com/en/unicode/U+1F1E6"&gt;U+1F1E6&lt;/a&gt; (regional indicator symbol letter "A") and continue to &lt;a href="https://www.compart.com/en/unicode/U+1F1FF"&gt;U+1F1FF&lt;/a&gt; (regional indicator symbol letter "Z").&lt;/p&gt;

&lt;h2&gt;
  
  
  The formula 🤓
&lt;/h2&gt;

&lt;p&gt;The formula to convert a letter to its corresponding regional indicator symbol is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unicode point = &amp;lt;ASCII code of letter&amp;gt; − 65 + 127462
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;65&lt;/code&gt; is a decimal value of letter "A"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;127462&lt;/code&gt; is a decimal value of &lt;a href="https://www.compart.com/en/unicode/U+1F1E6"&gt;&lt;code&gt;U+1F1E6&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since &lt;code&gt;127462 - 65 = 127397 = 0x1F1A5&lt;/code&gt;, we will use &lt;code&gt;0x1F1A5&lt;/code&gt; in further calculations.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conversion in Go 👨🏻‍💻
&lt;/h2&gt;

&lt;p&gt;Here is an example in Go (Golang) to convert an ISO 3166-1 country code to a flag emoji. This code snippet normalizes the input to uppercase and then converts each character to its corresponding regional indicator symbol. For simplicity, it doesn't perform any validation so you should make sure it is a valid 2-letter code first.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;countryCode&lt;/span&gt; &lt;span class="kt"&gt;string&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;var&lt;/span&gt; &lt;span class="n"&gt;flagEmoji&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;
    &lt;span class="n"&gt;countryCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;countryCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;countryCode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;flagEmoji&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteRune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;0x1F1A5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;flagEmoji&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pl"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c"&gt;// 🇵🇱&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JP"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c"&gt;// 🇯🇵&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"us"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c"&gt;// 🇺🇸&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EU"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c"&gt;// 🇪🇺&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Explanation 👨🏻‍🏫
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Normalization&lt;/strong&gt;: The input country code is converted to uppercase using &lt;code&gt;strings.ToUpper()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;String Builder&lt;/strong&gt;: A &lt;code&gt;strings.Builder&lt;/code&gt; is used to efficiently build the resulting flag emoji string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character Processing&lt;/strong&gt;: Each character of the uppercase country code is processed: &lt;code&gt;rune(char) + 0x1F1A5&lt;/code&gt;: Converts the character to its corresponding regional indicator symbol by adding &lt;code&gt;0x1F1A5&lt;/code&gt; (127397).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appending Characters&lt;/strong&gt;: The resulting regional indicator symbols are appended to the &lt;code&gt;strings.Builder&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Returning the Result&lt;/strong&gt;: The &lt;code&gt;String()&lt;/code&gt; method of &lt;code&gt;strings.Builder&lt;/code&gt; is called to get the final flag emoji string.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Conversion in PHP 🐘
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;preg_replace_callback&lt;/code&gt; allows to replace each character in a string using a custom callback:&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="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;country2flag&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;$countryCode&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="nb"&gt;preg_replace_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s1"&gt;'/./'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;fn&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;$m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x1F1A5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nb"&gt;strtoupper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$countryCode&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="k"&gt;echo&lt;/span&gt; &lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pl'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 🇵🇱&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'JP'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 🇯🇵&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'us'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 🇺🇸&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'EU'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 🇪🇺&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Conversion in TypeScript 😎
&lt;/h2&gt;

&lt;p&gt;This example uses a combination of &lt;code&gt;split&lt;/code&gt; and &lt;code&gt;join&lt;/code&gt; to process each character individually.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countryCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&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="nx"&gt;countryCode&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromCodePoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x1F1A5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 🇵🇱&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 🇯🇵&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 🇺🇸&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;country2flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EU&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 🇪🇺&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;🤗 Converting ISO 3166-1 country codes to flag emojis can be fun and straightforward in &lt;strong&gt;Go&lt;/strong&gt;, &lt;strong&gt;PHP&lt;/strong&gt; and &lt;strong&gt;TypeScript&lt;/strong&gt;! By understanding how regional indicator symbols work and using simple character manipulation, you can easily generate these emojis programmatically in any other language ✨.&lt;/p&gt;

&lt;p&gt;🛠️ Whether you're building a web application or a server-side script, this technique can add a fun and informative visual element to your project.&lt;/p&gt;

&lt;p&gt;☝🏻 Please note that the appearance and availability of the flag emojis might vary between systems and locale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feel free to post snippets in your favourite programming language in the comments!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article is based on the snippet I posted on GitHub Gist 3 years ago: &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>go</category>
      <category>typescript</category>
      <category>php</category>
    </item>
    <item>
      <title>💖 Write Future-Compatible PHP Code with Symfony Polyfills</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Mon, 20 May 2024 08:53:23 +0000</pubDate>
      <link>https://dev.to/ionbazan/write-future-compatible-php-code-with-symfony-polyfills-380b</link>
      <guid>https://dev.to/ionbazan/write-future-compatible-php-code-with-symfony-polyfills-380b</guid>
      <description>&lt;p&gt;If you’re like many developers, you know the frustration of being stuck on an older PHP version. Upgrading to the latest and greatest can be a daunting task, especially when you're dealing with legacy code and tight deadlines 🤬. But fear not! &lt;a href="https://github.com/symfony/polyfill"&gt;Symfony Polyfill&lt;/a&gt; is here to save the day, making your life a whole lot easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Symfony Polyfill? 🤩
&lt;/h2&gt;

&lt;p&gt;In a nutshell, &lt;a href="https://github.com/symfony/polyfill"&gt;Symfony Polyfill&lt;/a&gt; is a collection of PHP functions that replicate features introduced in newer PHP versions, allowing you to use these features even if your server is running an older version of PHP. It's like having a time machine that brings the future to your present codebase ⚡️. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Should You Care? 🤔
&lt;/h2&gt;

&lt;p&gt;You might be wondering, "Why should I bother with this polyfill thing?" Well, there are a few great reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Future Compatibility&lt;/strong&gt;: Writing code that is future-compatible means you won't have to refactor it every time you or your organization decides to upgrade PHP. This saves you countless hours of work and a lot of headaches.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gradual Migration&lt;/strong&gt;: If you or your organization is planning to upgrade PHP in the future, Symfony Polyfill allows you to start using newer features now. This makes the transition smoother when the actual upgrade happens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Community Support&lt;/strong&gt;: Symfony is a well-established framework with a strong community. By using Symfony Polyfill, you're leveraging code that is robust, well-tested, and supported by many developers worldwide.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started with Symfony Polyfill 👨🏻‍💻
&lt;/h2&gt;

&lt;p&gt;Integrating Symfony Polyfill into your project is a breeze. Let’s walk through the steps to get you up and running.&lt;/p&gt;

&lt;p&gt;First, you need to install the specific Symfony Polyfill package for the PHP version you want to polyfill. For example, to polyfill PHP 8.3 features, run the following command in your project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require symfony/polyfill-php83
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Polyfilled Functions&lt;/strong&gt;: Now you can start using functions from newer PHP versions even if your current PHP version doesn’t support them. Here’s a simple 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="c1"&gt;// Using json_validate() function introduced in PHP 8.3&lt;/span&gt;
&lt;span class="nv"&gt;$json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "John", "age": 30, "city": "New York"}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;json_validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$isValid&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'Valid JSON'&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Invalid JSON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Output: Valid JSON&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Benefits 🤓
&lt;/h2&gt;

&lt;p&gt;Imagine you’re stuck on PHP 7.4, but you really want to use some of the cool new features from PHP 8.3, like json_validate(). With Symfony Polyfill, you can start using these functions today.&lt;/p&gt;

&lt;p&gt;Here's how it can improve your application's migration process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;💄 &lt;strong&gt;Write Modern Code&lt;/strong&gt;: By using polyfills, you can start writing modern code that adheres to the latest PHP standards. This means when you finally upgrade, your codebase will already be using the latest features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✨ &lt;strong&gt;Reduce Technical Debt&lt;/strong&gt;: Gradual adoption of new features helps in reducing technical debt. Instead of one massive refactor, you can slowly introduce new PHP features into your codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📜 &lt;strong&gt;Enhanced Readability and Maintenance&lt;/strong&gt;: Modern PHP features often result in more readable and maintainable code. For example, using json_validate() is much clearer than manually writing a complex JSON validation function.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Symfony Polyfill&lt;/strong&gt; is a powerful tool that can help you write future-compatible code, making your life as a developer much easier. By integrating it into your application, you can take advantage of modern PHP features today, even if you're stuck on an older PHP version.&lt;/p&gt;

&lt;p&gt;The best part is, as soon as you migrate your application to a newer PHP version, all usages of polyfills will automatically start using the built-in function implementations provided by the PHP version itself. This makes the migration process smoother and less error-prone, as you don't have to manually refactor your code to remove polyfills.&lt;/p&gt;

&lt;p&gt;So, why wait for your organization to catch up? Start using Symfony Polyfill and future-proof your codebase now. Your future self (and your team) will thank you! 🤩&lt;/p&gt;

&lt;p&gt;📚 Feel free to dive into the &lt;a href="https://github.com/symfony/polyfill"&gt;Symfony Polyfill documentation&lt;/a&gt; to explore all the features available. &lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;PS. While using polyfills is incredibly helpful, it's important to remember that upgrading your PHP version as soon as possible is the best long-term solution. Keeping your software up-to-date ensures better performance, security, and access to the latest features.&lt;/p&gt;

</description>
      <category>php</category>
      <category>symfony</category>
      <category>legacy</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>📊 Change the order Laravel picks up queued jobs (AKA Priority Queues)</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Mon, 20 May 2024 08:17:22 +0000</pubDate>
      <link>https://dev.to/ionbazan/change-the-order-laravel-picks-up-queued-jobs-aka-priority-queues-59bc</link>
      <guid>https://dev.to/ionbazan/change-the-order-laravel-picks-up-queued-jobs-aka-priority-queues-59bc</guid>
      <description>&lt;p&gt;Have you ever wished some queued jobs would be processed way ahead others? For example, if you want your VIP client's transanctions to be completed before everyone else's, this article might help you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple approach ✨
&lt;/h2&gt;

&lt;p&gt;If you have only a few tiers of clients, you might want to consider assigning them to a different queue so that VIP clients won't be blocked by other customers:&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\Jobs&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;Illuminate\Bus\Queueable&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;Illuminate\Contracts\Queue\ShouldQueue&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;Illuminate\Foundation\Bus\Dispatchable&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;Illuminate\Queue\InteractsWithQueue&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;Illuminate\Queue\SerializesModels&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;ProcessJob&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShouldQueue&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;Dispatchable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InteractsWithQueue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Queueable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SerializesModels&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;Customer&lt;/span&gt; &lt;span class="nv"&gt;$customer&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="nf"&gt;onQueue&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="nf"&gt;determineQueue&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Determine which queue to use based on client type.
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;determineQueue&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;$customer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;is_vip&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'vip'&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'default'&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;handle&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="c1"&gt;// Job logic&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 running separate workers for both queues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan queue:work &lt;span class="nt"&gt;--queue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default
php artisan queue:work &lt;span class="nt"&gt;--queue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ This is really easy and will work with any queue driver, like Redis, SQS, Database, etc.&lt;/p&gt;

&lt;p&gt;❌ Unfortunately, this is not really scalable if you wish to have more control over the order of queued jobs or have many different tiers of users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queue prioritization using custom queue driver 👨🏻‍💻
&lt;/h2&gt;

&lt;p&gt;If you wish to control the order of transactions in more sophisticated way, for example based on a transaction amount or any other factor, consider creating a custom queue driver.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add &lt;code&gt;priority&lt;/code&gt; column to &lt;code&gt;jobs&lt;/code&gt; table
&lt;/h3&gt;

&lt;p&gt;To start, add a &lt;code&gt;priority&lt;/code&gt; column in your &lt;code&gt;jobs&lt;/code&gt; table. You can do this by creating a migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:migration add_priority_to_jobs_table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the migration file:&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jobs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unsignedInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'priority'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Default priority is 0&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;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jobs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dropColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'priority'&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;Run the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create a Custom Queue Connector
&lt;/h3&gt;

&lt;p&gt;Create a custom queue connector that extends Laravel's database queue connector. In this custom connector, you'll override the &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pop&lt;/code&gt; methods to handle job priority:&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\Queue&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;Illuminate\Queue\DatabaseQueue&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;Illuminate\Contracts\Queue\Job&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;Illuminate\Queue\Jobs\DatabaseJob&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;Illuminate\Queue\Jobs\DatabaseJobRecord&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;PriorityDatabaseQueue&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;DatabaseQueue&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Push a new job onto the queue.
     *
     * @param  string  $queue
     * @param  string  $payload
     * @param  string|null  $queue
     * @return mixed
     */&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;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$queue&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="nv"&gt;$queue&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="nf"&gt;getQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$payload&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="nf"&gt;createPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&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;database&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;table&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;table&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;insertGetId&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'queue'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'payload'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'attempts'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'reserved'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'reserved_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'available_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nf"&gt;availableAt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'created_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nf"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'priority'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'priority'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Set the priority&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Pop the next job off of the queue with prioritization.
     *
     * @param  string|null  $queue
     * @return \Illuminate\Contracts\Queue\Job|null
     */&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;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queue&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="nv"&gt;$queue&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="nf"&gt;getQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$job&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;database&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;table&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;table&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;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'queue'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$queue&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;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'reserved'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'priority'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'desc'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Prioritize jobs based on their priority level&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'asc'&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;lockForUpdate&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;first&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="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$job&lt;/span&gt;&lt;span class="p"&gt;))&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;DatabaseJob&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;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DatabaseJobRecord&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$job&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create a Custom Connector Class
&lt;/h3&gt;

&lt;p&gt;Create a custom connector class to register the custom queue connector:&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\Queue\Connectors&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;Illuminate\Queue\Connectors\DatabaseConnector&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;App\Queue\PriorityDatabaseQueue&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;PriorityDatabaseConnector&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;DatabaseConnector&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;connect&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;$config&lt;/span&gt;&lt;span class="p"&gt;)&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;PriorityDatabaseQueue&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;connections&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'connection'&lt;/span&gt;&lt;span class="p"&gt;]&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="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'table'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'queue'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'retry_after'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;60&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;
  
  
  4. Register the Custom Connector
&lt;/h3&gt;

&lt;p&gt;Register your custom connector in a service provider.&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;Illuminate\Support\ServiceProvider&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;App\Queue\Connectors\PriorityDatabaseConnector&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;AppServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceProvider&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;register&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;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;resolving&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'queue'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addConnector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'prioritydatabase'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&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;PriorityDatabaseConnector&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;app&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'db'&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From now on, using a &lt;code&gt;prioritydatabase&lt;/code&gt; driver will use our custom logic to push and fetch jobs to the queue based on their priority.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Configure Queue Connection
&lt;/h3&gt;

&lt;p&gt;Update your &lt;code&gt;config/queue.php&lt;/code&gt; to use the new driver:&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="s1"&gt;'connections'&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;'prioritydatabase'&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;'driver'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'prioritydatabase'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'table'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'jobs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'queue'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'priority'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'retry_after'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;60&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;
  
  
  6. Set Job Priority When Dispatching Jobs
&lt;/h3&gt;

&lt;p&gt;When dispatching jobs, set the priority level. You can do this by adding a &lt;code&gt;$priority&lt;/code&gt; field to the job's payload.&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;SomeJob&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShouldQueue&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;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&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="c1"&gt;// Job logic&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Dispatching the job with priority&lt;/span&gt;
&lt;span class="nv"&gt;$job&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;SomeJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Priority 10&lt;/span&gt;
&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$job&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;onQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'priority'&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;onConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'prioritydatabase'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these steps, you will have a priority queue setup in Laravel where jobs are stored with a &lt;code&gt;priority&lt;/code&gt; column in the &lt;code&gt;jobs&lt;/code&gt; table. The custom queue connector ensures that jobs are popped from the queue based on their priority, allowing higher priority jobs to be processed first.&lt;/p&gt;

&lt;p&gt;Feel free to customize the way you pop the jobs based on your needs.&lt;/p&gt;

&lt;p&gt;✅ More control over the job processing order.&lt;br&gt;
❌ Changing the queue driver requires major refactor to adapt the popping logic. Not all drivers might be supported.&lt;/p&gt;

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

&lt;p&gt;🕵🏻‍♂️ Digging deep in Laravel queue connectors could be fun and it's interesting to learn how it works internally so that we are able to customize it to our needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;While the DB driver is easy to understand and customize, I strongly suggest not to use database driver in production&lt;/strong&gt;. If you wish to maintain scalability and avoid lock issues, I recommend creating a similar connector based on Redis with &lt;code&gt;ZADD&lt;/code&gt; and &lt;code&gt;ZRANGE/ZREM&lt;/code&gt; to handle similar logic instead.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>queue</category>
      <category>php</category>
    </item>
    <item>
      <title>📫 How to set up custom email domain with iCloud and Cloudflare</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Mon, 20 May 2024 05:15:48 +0000</pubDate>
      <link>https://dev.to/ionbazan/how-to-set-up-custom-email-domain-with-icloud-and-cloudflare-2al4</link>
      <guid>https://dev.to/ionbazan/how-to-set-up-custom-email-domain-with-icloud-and-cloudflare-2al4</guid>
      <description>&lt;p&gt;As a part of your digital identity, you may want to use a custom domain for your personal email address. In this article I'll show you how to easily set up email receiving and sending without breaking a bank.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do I need a custom email domain in the first place?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Most importantly a custom domain keeps you independent from any particular email vendor (e.g. Gmail, Yahoo, etc). You keep your address as long as you keep your domain active and configure your MX records accordingly. Switching to a new vendor is a matter of importing existing emails and changing DNS records.&lt;/li&gt;
&lt;li&gt;Let's be honest, it just looks cool to have an email address like &lt;a href="mailto:firtsname@lastname.com"&gt;firtsname@lastname.com&lt;/a&gt; instead of &lt;a href="mailto:username@gmail.com"&gt;username@gmail.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you are running a small business, it looks more professional and consistent to use your own domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  OK, how do I do this?
&lt;/h2&gt;

&lt;p&gt;The simplest way to go is to use iCloud+ as it &lt;a href="https://support.apple.com/en-us/108047" rel="noopener noreferrer"&gt;starts at $0.99&lt;/a&gt; but you might be already paying for this if you keep your backups there.&lt;/p&gt;

&lt;p&gt;Let's go!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Register your domain 🌎
&lt;/h3&gt;

&lt;p&gt;First things first, you'll need to register a domain if you haven't already. You can do this through any domain registrar like &lt;a href="https://www.godaddy.com/" rel="noopener noreferrer"&gt;GoDaddy&lt;/a&gt;, &lt;a href="https://porkbun.com/" rel="noopener noreferrer"&gt;Porkbun&lt;/a&gt;, or even &lt;a href="https://cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Add the domain to iCloud ☁️
&lt;/h3&gt;

&lt;p&gt;Log in to your iCloud account and choose &lt;a href="https://www.icloud.com/icloudplus/" rel="noopener noreferrer"&gt;Custom Email Domain&lt;/a&gt; from the Quick Access menu on top:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fcocc0o4lsfo5tepolgno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fcocc0o4lsfo5tepolgno.png" alt="Adding custom email domain in iCloud"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can choose to &lt;strong&gt;Add a domain you own&lt;/strong&gt; or &lt;strong&gt;Buy a new domain&lt;/strong&gt; if you haven't done it yet in the first step.&lt;/p&gt;

&lt;p&gt;I suggest using &lt;strong&gt;You and other people&lt;/strong&gt; in the next step to allow your family members to use the same domain for their email addresses. Sharing is caring 🤗.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fijwaqrnzxw6vzn3gf0kp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fijwaqrnzxw6vzn3gf0kp.png" alt="Choosing people to share the domain with"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;View&lt;/strong&gt; in &lt;strong&gt;Update your domain’s records&lt;/strong&gt; section to get your DNS settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fee8v50i5tz4n68ecq4kk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fee8v50i5tz4n68ecq4kk.png" alt="DNS records list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Update your DNS records 🛠️
&lt;/h3&gt;

&lt;p&gt;✨ Copy-paste them exactly into your registrar's DNS records dashboard. If you are using Cloudflare, make sure to select &lt;strong&gt;DNS Only&lt;/strong&gt; in &lt;strong&gt;Proxy status&lt;/strong&gt; for the record to work correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ftp8tbltv0e8q6lyd14oi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ftp8tbltv0e8q6lyd14oi.png" alt="Cloudflare DNS settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Finish iCloud setup ✅
&lt;/h3&gt;

&lt;p&gt;After adding all necessary DNS records, give it at least a few minutes (up to 72 hours) to propagate and click &lt;strong&gt;Finish setup&lt;/strong&gt; on the last page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Frdllogigncbgaflitilw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Frdllogigncbgaflitilw.png" alt="Finish setup step"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once done, you will be able to use your custom email address to send and receive emails straight from your iPhone and Mac.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Start receiving (and sending) your emails 💌
&lt;/h3&gt;

&lt;p&gt;To test your changes, try sending an email from your existing email address to the new custom address. If everything went good, you should be able to receive it on your iPhone. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F8x0p09znveh9b4e16woc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8x0p09znveh9b4e16woc.png" alt="Receiving an email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you received it, try replying back to make sure sending works well too.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I don't use Apple products?
&lt;/h2&gt;

&lt;p&gt;You can try using other email providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.zoho.com/" rel="noopener noreferrer"&gt;ZohoMail&lt;/a&gt; - $1/mo&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.fastmail.com/" rel="noopener noreferrer"&gt;Fastmail&lt;/a&gt; - $3/mo,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://proton.me/" rel="noopener noreferrer"&gt;ProtonMail&lt;/a&gt; - €3.99/mo,&lt;/li&gt;
&lt;li&gt;Many many others...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that even if you don't own any Apple product, it could still make sense to get iCloud+ as you can access your emails and files via browser and this option seems to be one of the most affordable and easiest to set up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I want it completely free?
&lt;/h2&gt;

&lt;p&gt;If you don't need to send emails from your custom domain, you can opt in for &lt;a href="https://developers.cloudflare.com/email-routing/" rel="noopener noreferrer"&gt;Cloudflare Email Routing&lt;/a&gt; to redirect incoming emails to your existing personal email account (GMail, Yahoo, etc). You won't be able to use this address to send emails, but you can still reply to them with your personal address.&lt;/p&gt;

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

&lt;p&gt;🚀 That was quick, right? Let me know in the comments if you like it and feel free to share any other services you use to host your emails.&lt;/p&gt;

</description>
      <category>email</category>
      <category>hosting</category>
      <category>domain</category>
      <category>productivity</category>
    </item>
    <item>
      <title>📚 How to see what changed in Composer files</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Fri, 17 May 2024 18:35:35 +0000</pubDate>
      <link>https://dev.to/ionbazan/how-to-see-what-changed-in-composer-files-1ih6</link>
      <guid>https://dev.to/ionbazan/how-to-see-what-changed-in-composer-files-1ih6</guid>
      <description>&lt;p&gt;When reviewing a Pull Request that touched &lt;code&gt;composer.json&lt;/code&gt; and &lt;code&gt;composer.lock&lt;/code&gt; files you might notice that the diffs are usually pretty huge and it's almost impossible to tell what exactly happened there - which packages got added, updated, downgraded or removed? Nobody knows.&lt;/p&gt;

&lt;p&gt;That's because &lt;a href="https://getcomposer.org/" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; stores information about all packages that should be installed in &lt;code&gt;composer.lock&lt;/code&gt; together with some of their metadata. This helps to manage the dependencies efficiently and browse most information offline but there is currently no built-in way to compare these files when changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to live with that?
&lt;/h2&gt;

&lt;p&gt;Don't worry, I got you. Simply install &lt;a href="https://github.com/IonBazan/composer-diff" rel="noopener noreferrer"&gt;Composer-Diff&lt;/a&gt; plugin which allows you to easily compare any two versions of your &lt;code&gt;composer.lock&lt;/code&gt; files:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

composer global req ion-bazan/composer-diff


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To run it in your repository:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

composer diff &lt;span class="c"&gt;# Displays packages changed in current git tree compared with HEAD&lt;/span&gt;
composer diff &lt;span class="nt"&gt;--help&lt;/span&gt; &lt;span class="c"&gt;# Display detailed usage instructions&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By default, it compares current filesystem version with your last committed changes (to use it locally just before committing your new changes):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ft5z1vb5uvimeg7gvw606.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ft5z1vb5uvimeg7gvw606.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It produces a colourful, tabulated markdown output which can be copy-pasted into your PR description for reference 🤩&lt;/p&gt;

&lt;p&gt;Besides of generating diff for your current filesystem changes, you can compare any 2 git refs or local copies of files using &lt;code&gt;--base&lt;/code&gt; and &lt;code&gt;--target&lt;/code&gt; options or arguments:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

composer diff master &lt;span class="c"&gt;# Compare current composer.lock with the one on master branch&lt;/span&gt;
composer diff master:composer.lock develop:composer.lock &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="c"&gt;# Compare master and develop branches, including platform dependencies&lt;/span&gt;
composer diff &lt;span class="nt"&gt;--no-dev&lt;/span&gt; &lt;span class="c"&gt;# ignore dev dependencies&lt;/span&gt;
composer diff &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="c"&gt;# include platform dependencies&lt;/span&gt;
composer diff &lt;span class="nt"&gt;-f&lt;/span&gt; json &lt;span class="c"&gt;# Output as JSON instead of table&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Did I mention it works with all PHP versions from 5.3 all the way till 8.4+?&lt;/p&gt;

&lt;h2&gt;
  
  
  OK but I'm lazy
&lt;/h2&gt;

&lt;p&gt;Me too! That's why I made things even easier with GitHub Actions - I'm adding &lt;a href="https://github.com/marketplace/actions/composer-diff" rel="noopener noreferrer"&gt;Composer Diff Action&lt;/a&gt; to all my projects to enjoy an automated report in every PR.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fqkobdtaxdh1izy2u71fh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fqkobdtaxdh1izy2u71fh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another day, another useful automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  OK but I don't like you
&lt;/h2&gt;

&lt;p&gt;No problem, you can check out a few other tools instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://packagist.org/packages/jbzoo/composer-diff" rel="noopener noreferrer"&gt;jbzoo/composer-diff&lt;/a&gt; - requires PHP 7.2+, no composer plugin support&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://packagist.org/packages/josefglatz/composer-diff-plugin" rel="noopener noreferrer"&gt;josefglatz/composer-diff-plugin&lt;/a&gt; - works only right after install/update&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://packagist.org/packages/davidrjonas/composer-lock-diff" rel="noopener noreferrer"&gt;davidrjonas/composer-lock-diff&lt;/a&gt; - does not work as composer plugin&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>composer</category>
      <category>php</category>
      <category>github</category>
      <category>dependencies</category>
    </item>
    <item>
      <title>⚙️ Laravel Queues: Rate-Limiting jobs</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Fri, 17 May 2024 17:58:10 +0000</pubDate>
      <link>https://dev.to/ionbazan/laravel-queues-rate-limiting-jobs-14m3</link>
      <guid>https://dev.to/ionbazan/laravel-queues-rate-limiting-jobs-14m3</guid>
      <description>&lt;p&gt;Hi guys, today I'd like to talk a bit about rate-limiting &lt;a href="https://laravel.com/docs/queues"&gt;Laravel queued jobs&lt;/a&gt; 👨🏻‍💻.&lt;/p&gt;

&lt;p&gt;This might be a common scenario, where we want to make sure jobs are not processed too fast in order to not overload other system resources.&lt;/p&gt;

&lt;p&gt;🤔 In one of my projects there was a case where certain type of jobs had to be processed at specific rate as they had to call a 3rd party API which was rate-limited.&lt;/p&gt;

&lt;p&gt;Let's explore different approaches we could take to solve this problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  1️⃣ Using Laravel's Built-in Rate Limiting
&lt;/h2&gt;

&lt;p&gt;Laravel provides a &lt;a href="https://laravel.com/docs/queues#job-middleware"&gt;built-in rate limiting feature&lt;/a&gt; that you can use to limit the rate at which jobs are processed.&lt;br&gt;
You can define rate limiters using the &lt;code&gt;RateLimiter::for()&lt;/code&gt; method and apply them to your jobs using middleware or directly within your job classes.&lt;br&gt;
Rate limiters can be configured based on various criteria such as the number of attempts per minute, per user, or per resource.&lt;/p&gt;

&lt;p&gt;Simply add this to your job class:&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="cd"&gt;/**
     * The rate limiting middleware for the job.
     */&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;middleware&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Illuminate\Queue\Middleware\RateLimitedWithRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'process-job'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Example: 10 jobs per minute&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;Pros: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy peasy to use and works out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not for every use case: it marks jobs as failed and drops them if the limiter doesn't have enough quota to process the job at the moment. &lt;/li&gt;
&lt;li&gt;This might be useful if the action is triggered too often by an impatient user so some jobs will be dropped but won't work in scenarios where each job must eventually be processed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2️⃣ Custom Rate Limiting Middleware
&lt;/h2&gt;

&lt;p&gt;If Laravel's built-in rate limiting does not meet your requirements, you can implement custom rate limiting logic within your application thanks to Job Middlewares.&lt;br&gt;
Instead of putting the job back to the queue and decreasing &lt;code&gt;$maxAttempts&lt;/code&gt;, you could make the job wait a bit before proceeding to processing it.&lt;/p&gt;

&lt;p&gt;Pros: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quite simple to implement and reusable - you could put it in a trait and use it across several jobs.
Cons: &lt;/li&gt;
&lt;li&gt;It involve quite a lot of custom logic and is relatively difficult to test. &lt;/li&gt;
&lt;li&gt;Time spent waiting for a quota from rate limiting would count towards the job execution time which not always might be desired.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3️⃣ Create a custom Queue Worker
&lt;/h2&gt;

&lt;p&gt;If you are not satisfied with above solutions an you'd like to fetch the job from the queue only when there is quota available in your rate limiter logic, the easiest way to do so is to create a custom Queue Worker:&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\Queue&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;Illuminate\Queue\Worker&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;Illuminate\Queue\WorkerOptions&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;RateLimitedWorker&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Pop the next job off of the queue with rate limiting.
     *
     * @param  string|null  $connectionName
     * @param  string|null  $queue
     * @param  \Illuminate\Queue\WorkerOptions  $options
     * @return \Illuminate\Contracts\Queue\Job|null
     */&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;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$connectionName&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="nv"&gt;$queue&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="kt"&gt;WorkerOptions&lt;/span&gt; &lt;span class="nv"&gt;$options&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="c1"&gt;// Implement rate limiting logic here before popping the job&lt;/span&gt;
        &lt;span class="c1"&gt;// For example, use Laravel's rate limiting feature or any custom logic&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$connectionName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Registering this worker as default application queue worker in your &lt;code&gt;AppServiceProvider&lt;/code&gt; will apply this logic to all queues and connections - you can conditionally run the custom logic on certain queues then:&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'queue.worker'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&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;RateLimitedWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'queue'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
        &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'events'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
        &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'queue.failer'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
        &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'cache.store'&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;The simplest way to rate-limit such jobs is using a &lt;code&gt;sleep()&lt;/code&gt; and calculating the number of processes vs allowed limit. More elegant solution would be to use Laravel's &lt;a href="https://laravel.com/docs/rate-limiting"&gt;&lt;code&gt;RateLimit&lt;/code&gt;&lt;/a&gt; component. Just make sure you always take into account that there might be many concurrent workers running at any point of time, so use some kind of distributed lock for that. Cheers!&lt;/p&gt;

&lt;p&gt;❌ That's a lot of code...&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quite easy to implement ✨&lt;/li&gt;
&lt;li&gt;Jobs will only be picked up when there is quota available to process them 👍🏻&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overriding/extending framework's internal classes might cause problems when upgrading - make sure you got this behaviour covered by tests&lt;/li&gt;
&lt;li&gt;Not so elegant solution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4️⃣ Use &lt;code&gt;Queue::popUsing()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If you don't want to extend framework's classes, you might want to use composition over inheritance to customize the way your app picks up the jobs from the queue:&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;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;popUsing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Implement rate limiting logic here before popping the job&lt;/span&gt;
    &lt;span class="c1"&gt;// For example, use Laravel's rate limiting feature or any custom logic&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$connection&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;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queue&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 put this code in one of your service providers and enjoy avoiding nasty inheritance. Well, that didn't sound right.&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Elegant,easy to implement and quite flexible solution, without polluting the app with framework internals too much&lt;/li&gt;
&lt;li&gt;Jobs will only be picked up when there is quota to process them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quite difficult to test it other than manually running it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  😎 Summary
&lt;/h2&gt;

&lt;p&gt;Each option offers flexibility and customization to suit different use cases and requirements. Depending on your specific needs, you can choose the approach that best fits your application architecture and rate limiting requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤓☝🏻 Actually...
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In my case, none of them were good enough.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's because I looked at it from the wrong angle - the fact that the 3rd party API has some limits shouldn't be the queue's concern but should rather be handled in the SDK or the client class that connects to it and solved there. You might one day call this API directly from a request or CLI and you'd have to rewrite the whole thing all over again.&lt;/p&gt;

&lt;p&gt;One way to achieve it is to use &lt;a href="https://github.com/spatie/guzzle-rate-limiter-middleware"&gt;Guzzle Rate Limiter Middleware&lt;/a&gt; which waits for the quota to replenish before calling the API another time. &lt;br&gt;
Simply plug it wherever you are hitting the external API and boom, job done! 🤘🏻&lt;/p&gt;

&lt;p&gt;See you again soon!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>queue</category>
    </item>
    <item>
      <title>Free tools every developer should know 🌝</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Fri, 17 May 2024 11:22:32 +0000</pubDate>
      <link>https://dev.to/ionbazan/free-tools-every-developer-should-know-4l02</link>
      <guid>https://dev.to/ionbazan/free-tools-every-developer-should-know-4l02</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;In today's tech-driven world, where subscription-based models reign supreme, the term "freemium" has become commonplace, offering tantalizing glimpses of what could be with just a simple upgrade. Yet, amidst this trend, there's a plethora of services that not only enhance our daily lives but also support our work endeavors.&lt;/p&gt;

&lt;p&gt;Today, I'm excited to share my go-to list of tools and services that have been super helpful for me!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Git repositories + CI/CD: GitHub or GitLab - $0 ✨&lt;br&gt;
Static site hosting: Vercel - $0 ✨&lt;br&gt;
Domain registrar: Cloudflare - $10.18 for .dev domain&lt;br&gt;
DNS and CDN: Cloudflare - $0 ✨&lt;br&gt;
AI completion: ChatGPT + GitHub Copilot - $0 ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Some of us probably still remember when GitHub used to charge for private repositories and many seeked alternatives at BitBucket or GitLab instead. &lt;a href="https://github.blog/2019-01-07-new-year-new-github/"&gt;Since 2019&lt;/a&gt;, GitHub offers unlimited private repositories for all developers! This makes it easier to work on some small personal or commercial projects. &lt;/p&gt;

&lt;p&gt;What you are getting for free?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlimited personal/private repositories &lt;/li&gt;
&lt;li&gt;2000 CI/CD minutes per month&lt;/li&gt;
&lt;li&gt;500 MB packages storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paid plan starts at $4/mo, adding advanced code review tools, and enhanced security features.&lt;/p&gt;

&lt;p&gt;You can always upgrade if you need more but it's quite a generous gift for everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://about.gitlab.com/"&gt;GitLab&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;While personally I prefer GitHub, GitLab mentioned above offers unmatched CI/CD and CVS features and it's all for free and open source! I honestly fell in love with the capabilities of their CI/CD and Docker image hosting a while ago.&lt;/p&gt;

&lt;p&gt;Premium plan starts at $29/mo which might be quite pricey comparing to GH.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Vercel is a fantastic platform for deploying web projects seamlessly. It offers a simple and intuitive interface, automatic deployments, and integration with popular version control systems like GitHub and GitLab. I'm using it to host my personal website at &lt;a href="https://bazan.dev"&gt;https://bazan.dev&lt;/a&gt; and it rocks 🚀!&lt;/p&gt;

&lt;p&gt;Free tier includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlimited personal projects&lt;/li&gt;
&lt;li&gt;Automatic deployments&lt;/li&gt;
&lt;li&gt;Preview deployments for feature branches and PRs&lt;/li&gt;
&lt;li&gt;Custom domain support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paid plan starts at $20/mo, offering advanced features like analytics and team collaboration tools (personally I don't need them).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;While Cloudflare for business is quite expensive, their free tier allows you to add basic CDN and firewall functionality to your website.&lt;/p&gt;

&lt;p&gt;For $0 you are getting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Content Delivery Network (CDN): Speeds up website loading times by caching static content on Cloudflare's servers distributed worldwide.&lt;/li&gt;
&lt;li&gt;DDoS Protection: Protects websites from Distributed Denial of Service (DDoS) attacks, helping ensure uptime and availability.&lt;/li&gt;
&lt;li&gt;SSL/TLS Encryption: Provides HTTPS encryption for secure data transmission between website visitors and servers.&lt;/li&gt;
&lt;li&gt;Web Application Firewall (WAF): Guards against common web application vulnerabilities and malicious traffic.&lt;/li&gt;
&lt;li&gt;Analytics: Basic analytics and insights into website traffic and performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, Cloudflare offers domains at very competitive prices (my .dev costed me only $10.18 per year).&lt;/p&gt;

&lt;p&gt;Paid plan starts at $20/mo with many more features.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chatgpt.com"&gt;ChatGPT&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;ChatGPT by OpenAI is an AI-powered chatbot that can assist developers in various ways, such as debugging code, generating code snippets, and providing explanations for complex concepts.&lt;/p&gt;

&lt;p&gt;Free plan offers a limited number of queries per month but should be enough for personal use.&lt;/p&gt;

&lt;p&gt;Paid plan starts at $20/mo and offers access to newer models and faster response times.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/features/copilot"&gt;GitHub Copilot&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Another AI tool, providing AI code completion directly in the IDE of your choice. Amazing pair-programming partner, which helps with repetitive tasks and typos. 🪄&lt;/p&gt;

&lt;p&gt;While it's not actually a free subscription ($10/mo), there are many ways to get it for free if you are student, teacher or open-source project maintainer!&lt;/p&gt;

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

&lt;p&gt;The availability of free and affordable services empowers developers to choose the right tools without breaking the bank. Whether you're looking for version control, cloud hosting, or collaboration tools, there's a service out there to meet your needs. Exploring and leveraging these resources can significantly enhance your development process and productivity.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tools</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Efficiently resolving composer.lock merge conflicts</title>
      <dc:creator>Ion Bazan</dc:creator>
      <pubDate>Wed, 07 Apr 2021 08:32:26 +0000</pubDate>
      <link>https://dev.to/ionbazan/efficiently-resolving-composer-lock-merge-conflicts-1peb</link>
      <guid>https://dev.to/ionbazan/efficiently-resolving-composer-lock-merge-conflicts-1peb</guid>
      <description>&lt;h1&gt;
  
  
  Efficiently resolving composer.lock git merge conflicts
&lt;/h1&gt;

&lt;p&gt;When working in a team on a PHP project using Composer, you have probably encountered a problem when multiple people added, removed or updated some packages in &lt;code&gt;composer.json&lt;/code&gt; and &lt;code&gt;composer.lock&lt;/code&gt; on &lt;code&gt;main&lt;/code&gt; branch and GIT welcomed you with this message in the morning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Auto-merging composer.lock
CONFLICT (content): Merge conflict in composer.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resolving such conflict is not a straightforward operation due to the structure of the file which contains all locked dependencies information and a content hash.&lt;/p&gt;

&lt;p&gt;In this article I will show you few methods to resolve such conflict and make your life a bit easier.&lt;/p&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout --theirs composer.lock
composer update php # the "php" is important here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  What not to do?
&lt;/h1&gt;

&lt;p&gt;I’ve seen people doing &lt;code&gt;git checkout --ours composer.lock&lt;/code&gt; and pushing the changes… Since it’s overwriting all others’ changes with yours, it’s basically an equivalent of force-pushing changes to &lt;code&gt;main&lt;/code&gt; branch — never do that!&lt;/p&gt;

&lt;p&gt;Another bad (but not as destructive) idea would be to remove &lt;code&gt;composer.lock&lt;/code&gt; file and recreate it using &lt;code&gt;composer update&lt;/code&gt;. This might seem like a good idea if you don’t really care about your locked versions and trust your version constraints and tests 100%. In real life, this will most likely introduce some unexpected changes into your feature branch and unnecessarily increase the diff.&lt;/p&gt;

&lt;h1&gt;
  
  
  Method 1: The fast &amp;amp; simple [my favorite!]
&lt;/h1&gt;

&lt;p&gt;This method is suitable for most common scenarios, when some packages were added or updated in &lt;code&gt;main&lt;/code&gt; branch and you are trying to merge it into your feature branch with some other packages added. Assuming there are no dependency conflicts, you are good to go with this solution after merging the &lt;code&gt;composer.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;First, accept the changes from base (&lt;code&gt;main&lt;/code&gt;) branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout --theirs composer.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, trigger an update of the packages you added or removed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer update php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note that you may pass any installed (or even not installed) package name to the update command for it to work but passing &lt;code&gt;php&lt;/code&gt; will only touch the packages you just added or removed, without unnecessarily updating any extra packages to keep your changes clean.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/26FPnsRww5DbqoPuM/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/26FPnsRww5DbqoPuM/giphy.gif" width="423" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;li&gt;Simple&lt;/li&gt;
&lt;li&gt;Universal — you can use same commands, no matter what packages you add or remove&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Packages you added on your feature branch will be updated to most recent version matching the constraints (usually it should not be an issue)&lt;/li&gt;
&lt;li&gt;Any package updates (via &lt;code&gt;composer update&lt;/code&gt;) from your feature branch will be gone — you should re-run the update afterwards if needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Method 2: Redoing your changes
&lt;/h1&gt;

&lt;p&gt;This method is described in the &lt;a href="https://getcomposer.org/doc/articles/resolving-merge-conflicts.md"&gt;official Composer documentation&lt;/a&gt;. In some cases, when there might be some conflicting packages, it might be better to redo you package additions/removals on top of most recent changes from &lt;code&gt;main&lt;/code&gt; branch — similarly as applying changes during a rebase.&lt;/p&gt;

&lt;p&gt;First, accept the changes from base (&lt;code&gt;main&lt;/code&gt;) branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout --theirs composer.lock composer.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, add all the packages you added or removed in your feature branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require package/a:^1.2
composer require package/b:^2.0
composer remove package/c
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you’re done, make sure your &lt;code&gt;composer.json&lt;/code&gt; and &lt;code&gt;composer.lock&lt;/code&gt; files are valid using &lt;code&gt;composer validate&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reports conflicting dependencies as you add each of your packages&lt;/li&gt;
&lt;li&gt;Quite fast&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need to remember which packages you added or removed in your feature branch&lt;/li&gt;
&lt;li&gt;Repeating these actions on each merge might be tedious and error-prone&lt;/li&gt;
&lt;li&gt;Packages you added on your feature branch will be updated to most recent version matching the constraints (usually it should not be an issue)&lt;/li&gt;
&lt;li&gt;Any package updates (via &lt;code&gt;composer update&lt;/code&gt;) from your feature branch will be gone — you should re-run the update afterwards if needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Method 3: Using external tool
&lt;/h1&gt;

&lt;p&gt;Since above methods will not preserve the locked versions on packages that have been added on your feature branch, you may use an external tool such as &lt;a href="https://github.com/balbuf/composer-git-merge-driver"&gt;Composer Git Merge Driver&lt;/a&gt; that automates this process, keeping your locked versions and minimizing the diff produced. Please refer to the &lt;a href="https://github.com/balbuf/composer-git-merge-driver"&gt;official repository&lt;/a&gt; for installation and usage instructions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/NmerZ36iBkmKk/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/NmerZ36iBkmKk/giphy.gif" width="245" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Works magically — in most cases you will not even notice the conflict&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Installation might be a bit too complicated to enforce it in the team&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Additional notes
&lt;/h1&gt;

&lt;p&gt;Please keep in mind that using Method 1 or 2 will discard the information about the exact package version added in your feature branch. This is because &lt;code&gt;composer&lt;/code&gt; will lock the newest available version matching your constraints at the time of merge. If your package was constrained as &lt;code&gt;^1.0&lt;/code&gt; and locked at &lt;code&gt;1.1.0&lt;/code&gt; , it might be updated to &lt;code&gt;1.2.0&lt;/code&gt; while performing these steps. Most of the time it should not produce any side effects, especially if your version constraints are valid.&lt;/p&gt;

</description>
      <category>php</category>
      <category>composer</category>
      <category>git</category>
      <category>conflict</category>
    </item>
  </channel>
</rss>
