<?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: Alexandru Năstase</title>
    <description>The latest articles on DEV Community by Alexandru Năstase (@alexandrunastase).</description>
    <link>https://dev.to/alexandrunastase</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%2F473240%2Fd3747ce3-7613-4906-ada3-0e754d5e06ca.jpg</url>
      <title>DEV Community: Alexandru Năstase</title>
      <link>https://dev.to/alexandrunastase</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexandrunastase"/>
    <language>en</language>
    <item>
      <title>Editing Linux kernel parameters with kernelstub</title>
      <dc:creator>Alexandru Năstase</dc:creator>
      <pubDate>Thu, 14 Aug 2025 20:51:25 +0000</pubDate>
      <link>https://dev.to/alexandrunastase/editing-linux-kernel-parameters-with-kernelstub-4fle</link>
      <guid>https://dev.to/alexandrunastase/editing-linux-kernel-parameters-with-kernelstub-4fle</guid>
      <description>&lt;p&gt;I recently played the gamble of getting a very new processor for my new work laptop, the AMD Ryzen AI 9 HX 370. Even the drivers for Windows seem problematic so I expected there could be some minor hiccups for Linux as well. Luckily the only issue I encountered was one related to the GPU rendering that could be fixed temporarily by updating a kernel parameter. I'm mainly writing this to have a future reference for this kind of change and document some of the things I found out along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why kernelstub is the safer choice
&lt;/h3&gt;

&lt;p&gt;The simplest way I found to update kernel parameters is by using &lt;code&gt;kernelstub&lt;/code&gt;. I remember doing this some years ago without it and I remember the process being a lot more unclear and prone to error, and especially when it comes to this kind of sensitive things I prefer to be on the safe side.&lt;/p&gt;

&lt;p&gt;Unlike manually editing boot configurations or directly modifying EFI entries, kernelstub provides a more reliable interface that handles the complexities of modern UEFI boot systems. It automatically updates the correct boot entries and maintains consistency across different boot scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic kernelstub commands
&lt;/h3&gt;

&lt;p&gt;Before making any changes, it's always good practice to use the &lt;code&gt;--dry-run&lt;/code&gt; parameter to see what kernelstub would do without actually applying the changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kernelstub &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"parameter_name=value"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To add a kernel parameter you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kernelstub &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"parameter_name=value"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to add the AMD GPU debug mask parameter that fixed my rendering issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kernelstub &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"amdgpu.dcdebugmask=0x12"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify changes by checking the current configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kernelstub &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can directly check the boot configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo cat&lt;/span&gt; /boot/efi/loader/entries/Pop_OS-current.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To remove a kernel parameter use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kernelstub &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"parameter_name=value"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After making changes, reboot and test that your system behaves as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tested using
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pop!_OS 22.04 LTS&lt;/li&gt;
&lt;li&gt;Kernel version: 6.12.10&lt;/li&gt;
&lt;li&gt;AMD Ryzen™ AI 9 HX 370 processor&lt;/li&gt;
&lt;li&gt;kernelstub version: 3.1.4&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/isantop/kernelstub" rel="noopener noreferrer"&gt;kernelstub GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html" rel="noopener noreferrer"&gt;Kernel parameters documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.archlinux.org/title/AMDGPU" rel="noopener noreferrer"&gt;AMD GPU kernel parameters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this guide becomes outdated or if you have any issues with any of the steps, feel free to reach out.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Strategy Pattern in Symfony using attributes</title>
      <dc:creator>Alexandru Năstase</dc:creator>
      <pubDate>Mon, 04 Dec 2023 12:00:00 +0000</pubDate>
      <link>https://dev.to/alexandrunastase/the-joy-of-implementing-strategy-pattern-in-symfony-434o</link>
      <guid>https://dev.to/alexandrunastase/the-joy-of-implementing-strategy-pattern-in-symfony-434o</guid>
      <description>&lt;p&gt;One of the design patterns that I find myself most often implementing is the Strategy Design pattern. Oftentimes it helps decouple logic and allows better separation of concerns.&lt;/p&gt;

&lt;p&gt;In previous versions of Symfony, it was of course possible to implement the pattern, but there was a bit more friction involved, like the need to fiddle with yaml files. This has dissapeared meanwhile thanks to the introduction of the attributes in PHP8. Now that we have the &lt;code&gt;TaggedIterator&lt;/code&gt; and &lt;code&gt;AutoconfigureTag&lt;/code&gt; attributes at our disposal, it has never been so effortless to implement the strategy pattern using Symfony framework.&lt;/p&gt;

&lt;p&gt;In this post, we'll go through a concrete example of how to do this, in which we'll highlight the main components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case Study
&lt;/h2&gt;

&lt;p&gt;Let's suppose we're building a Payment Gateway Software that supports most major credit/debit card providers (Visa, Mastercard, and American Express).&lt;/p&gt;

&lt;p&gt;To keep things simple we will ignore lots of important elements like the credit card number, CVV, and so on and of course, there won't be any request to external entities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acceptance criteria:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a POST endpoint called &lt;code&gt;/card-payments&lt;/code&gt; that accepts the following JSON payload:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12.22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visa|mastercard|amex"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The endpoint should return a JSON response containing a &lt;code&gt;transactionId&lt;/code&gt; property that has as a prefix the name of the payment provider passed in the input and is followed by some "random" string similar to the example below:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transactionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visa_asd22kjlkoiposd"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The assumption is that other logic should be dealt for each provider so generating the transactionId should be separated for each card payment provider&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  An example implementation
&lt;/h2&gt;

&lt;p&gt;Note, that a lot of important aspects like validation, exception handling, and code structuring have not been considered in detail as the focus is on the strategy pattern itself.&lt;/p&gt;

&lt;p&gt;First we'll start out by building the &lt;code&gt;CardPaymentController&lt;/code&gt;, where we get the payload, deserialize it to a &lt;code&gt;CardPaymentDto&lt;/code&gt;, and pass it further to a &lt;code&gt;CardPaymentService&lt;/code&gt; which is responsible for finding the correct strategy and retrieving the transactionId from the strategy.&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="mf"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CardPaymentController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mf"&gt;...&lt;/span&gt;
    &lt;span class="na"&gt;#[Route('/card-payments', methods: ['POST'])]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$paymentDto&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;serializer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;CardPaymentDto&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'json'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$paymentResponse&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;cardPaymentService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handleCardPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paymentDto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paymentResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'json'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the controller is created we will implement the strategy interface:&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="na"&gt;#[AutoconfigureTag(CardPaymentStrategyInterface::class)]&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;CardPaymentStrategyInterface&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;isPaymentProviderSupported&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;$paymentProvider&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;handlePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CardPaymentDto&lt;/span&gt; &lt;span class="nv"&gt;$payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CardPaymentResponseDto&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;Note the use of the &lt;code&gt;AutoconfigureTag&lt;/code&gt; here. Usually, it's more common to use a string here as the service tag, but I prefer using the name of the interface to minimize the chance of typos.&lt;/p&gt;

&lt;p&gt;As the interface is defined we can start creating the strategy implementations:&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;VisaCardPaymentStrategy&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CardPaymentStrategyInterface&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;isPaymentProviderSupported&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;$paymentProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$paymentProvider&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nc"&gt;PaymentProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VISA&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;handlePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CardPaymentDto&lt;/span&gt; &lt;span class="nv"&gt;$payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CardPaymentResponseDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Call Visa payment provider&lt;/span&gt;
        &lt;span class="c1"&gt;// More logic&lt;/span&gt;

        &lt;span class="nv"&gt;$transactionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PaymentProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VISA&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;uniqid&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;CardPaymentResponseDto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionId&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;and similar for the other payment providers:&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;MastercardCardPaymentStrategy&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CardPaymentStrategyInterface&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;isPaymentProviderSupported&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;$paymentProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$paymentProvider&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nc"&gt;PaymentProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MASTERCARD&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;handlePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CardPaymentDto&lt;/span&gt; &lt;span class="nv"&gt;$payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CardPaymentResponseDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Call Mastercard payment provider&lt;/span&gt;
        &lt;span class="c1"&gt;// More logic&lt;/span&gt;

        &lt;span class="nv"&gt;$transactionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PaymentProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MASTERCARD&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;uniqid&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;CardPaymentResponseDto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$transactionId&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;When the supported strategies are defined we can start implementing the CardPaymentService:&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;CardPaymentService&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CardPaymentServiceInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @param iterable&amp;lt;CardPaymentStrategyInterface&amp;gt; $cardPaymentStrategies
     */&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="na"&gt;#[TaggedIterator(CardPaymentStrategyInterface::class)]&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;iterable&lt;/span&gt; &lt;span class="nv"&gt;$cardPaymentStrategies&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handleCardPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CardPaymentDto&lt;/span&gt; &lt;span class="nv"&gt;$paymentDto&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CardPaymentResponseDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$paymentStrategy&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;getStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paymentDto&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProvider&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;$paymentStrategy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handlePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paymentDto&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;getStrategy&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;$paymentProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CardPaymentStrategyInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$pickedPaymentStrategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;foreach&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;cardPaymentStrategies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$paymentStrategy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paymentStrategy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPaymentProviderSupported&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paymentProvider&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$pickedPaymentStrategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$paymentStrategy&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;if&lt;/span&gt; &lt;span class="p"&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;$pickedPaymentStrategy&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;UnsupportedPaymentStrategyException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createForPaymentProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paymentProvider&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="nv"&gt;$pickedPaymentStrategy&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;Note the &lt;code&gt;TaggedIterator&lt;/code&gt; attribute here. It allows us to collect all the classes that were auto-configured using the &lt;code&gt;CardPaymentStrategyInterface&lt;/code&gt; and have them available as an iterable.&lt;br&gt;
Here we simply find the correct strategy and call it using the &lt;code&gt;PaymentDto&lt;/code&gt; and return the result of the picked strategy, which should contain the transactionId.&lt;/p&gt;

&lt;p&gt;Make sure that service autoconfiguration is enabled in order for this setup work properly.&lt;/p&gt;

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

&lt;p&gt;Applying the strategy pattern is really straightforward using the latest versions of Symfony and PHP (Symfony 6.4 and PHP 8.2 in the given example). &lt;/p&gt;

&lt;p&gt;Apart from keeping the code much more decoupled, it offers the benefit of keeping the code open to extension but closed to modifications. So for example, if we were to add other payment providers, we wouldn't need to touch any of the existing logic thus avoiding the risk of breaking anything there.&lt;/p&gt;

&lt;p&gt;To see the entire implementation feel free to check out the &lt;a href="https://github.com/alexandrunastase/blog-appendix/tree/main/strategy-pattern"&gt;git repository&lt;/a&gt;. &lt;br&gt;
Additionally from the code shown above, the repository contains a docker-compose setup and some basic tests that you can play around with.&lt;/p&gt;




&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://symfony.com/doc/6.4/service_container/tags.html"&gt;https://symfony.com/doc/6.4/service_container/tags.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://symfony.com/doc/current/service_container.html#the-autoconfigure-option"&gt;https://symfony.com/doc/current/service_container.html#the-autoconfigure-option&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Cross-posted from my blog: &lt;a href="https://alexandrunastase.com/posts/the-joy-of-implementing-strategy-pattern-in-symfony"&gt;The joy of implementing strategy pattern in Symfony&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>tech</category>
      <category>symfony</category>
      <category>strategy</category>
      <category>php</category>
    </item>
    <item>
      <title>The Developer's Guide to Updating npm Packages</title>
      <dc:creator>Alexandru Năstase</dc:creator>
      <pubDate>Fri, 24 Feb 2023 06:46:22 +0000</pubDate>
      <link>https://dev.to/alexandrunastase/how-to-upgrade-npm-packages-2l0g</link>
      <guid>https://dev.to/alexandrunastase/how-to-upgrade-npm-packages-2l0g</guid>
      <description>&lt;h2&gt;
  
  
  TLDR: How to upgrade npm packages?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The simplest way is to install &lt;code&gt;npm-check-updates&lt;/code&gt;, run &lt;code&gt;npx ncu&lt;/code&gt;, followed by &lt;code&gt;npx ncu -u&lt;/code&gt; to update the package.json followed by &lt;code&gt;npm install&lt;/code&gt; to update packages in package.lock and node_modules.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Vanilla npm approach
&lt;/h2&gt;

&lt;p&gt;npm comes with the tools to upgrade your packages out of the box. When running &lt;code&gt;npm outdated&lt;/code&gt; you can get a list of packages that have available updates:&lt;/p&gt;

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

&lt;p&gt;We can update individual packages by running &lt;code&gt;npm update {package-name}&lt;/code&gt;. Let's try it for the last package on the list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm update sass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we run &lt;code&gt;npm outdated&lt;/code&gt; again we can (as seen in the image below) that the package was indeed updated. One thing to note is that while &lt;code&gt;package.lock&lt;/code&gt; was updated &lt;code&gt;package.json&lt;/code&gt; remains untouched.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzbw3arbapm5fef8kxh2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzbw3arbapm5fef8kxh2.png" alt="npm outdated after upgrade" width="732" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we could do the same for all the packages and if you have a production-critical application, you probably want to pay close attention to the packages that you upgrade and the implications that an upgrade could have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrades using npm-check-updates
&lt;/h2&gt;

&lt;p&gt;Another option, that I find slightly more convenient, especially for more low-risk projects is using the &lt;code&gt;npm-check-updates&lt;/code&gt; package. To install it simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g npm-check-updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After it's installed we can check for updates by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx ncu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to &lt;code&gt;npm outdated&lt;/code&gt; this gives us a list of all available updates:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpsvvc7nna9m9v6ggz5uc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpsvvc7nna9m9v6ggz5uc.png" alt="npm-check-updates list of updates" width="650" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to update one single package we can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx ncu &lt;span class="nt"&gt;-uf&lt;/span&gt; sass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;followed by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we run &lt;code&gt;npx ncu&lt;/code&gt; again we see the &lt;code&gt;sass&lt;/code&gt; package was updated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2peme2eas764vigqq2fh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2peme2eas764vigqq2fh.png" alt="npm-check-updates list after sass update" width="681" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is nice about the npm-check-updates package is that we can also update all of the packages if we choose so by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx ncu -u
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;followed again by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we run &lt;code&gt;npx ncu&lt;/code&gt; again we get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7t7wgapds6nglq99axl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7t7wgapds6nglq99axl.png" alt="npm-check-updates list after all updates" width="535" height="88"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now both &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package.lock&lt;/code&gt; were updated, so this makes it clearer what version of the packages we have without the need to look into the &lt;code&gt;package.lock&lt;/code&gt; file.&lt;/p&gt;

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

&lt;p&gt;If you want to easily upgrade all your packages you can use the &lt;code&gt;npm-check-updates&lt;/code&gt; npm package with the commands shown above, otherwise, you can also use npm's built-in commands &lt;code&gt;npm outdated&lt;/code&gt; and &lt;code&gt;npm update&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/npm-check-updates" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/npm-check-updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/cli/v7/commands" rel="noopener noreferrer"&gt;https://docs.npmjs.com/cli/v7/commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Cross-posted from my blog: &lt;a href="https://alexandrunastase.com/posts/how-to-update-npm-packages" rel="noopener noreferrer"&gt;How to upgrade npm packages&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What's the meaning of .PHONY in a Makefile?</title>
      <dc:creator>Alexandru Năstase</dc:creator>
      <pubDate>Thu, 02 Feb 2023 15:40:51 +0000</pubDate>
      <link>https://dev.to/alexandrunastase/whats-the-meaning-of-phony-in-a-makefile-406k</link>
      <guid>https://dev.to/alexandrunastase/whats-the-meaning-of-phony-in-a-makefile-406k</guid>
      <description>&lt;h2&gt;
  
  
  TLDR: What does .PHONY actually do?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;.PHONY is used to mark a target as phony. That means a target that doesn't take into consideration for execution any file that matches its name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's say we have a target called &lt;code&gt;clear-cache&lt;/code&gt;, which removes the cache of an application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;clear-cache&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; cache/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which results in the following command:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6e5sy1lyb4xx20q1swa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6e5sy1lyb4xx20q1swa.png" alt="command line result 1" width="409" height="42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cache removal cli command will be run fine most of the time, but let's check what happens if we &lt;strong&gt;add a file with the same name as the target&lt;/strong&gt; at the same level as the Makefile&lt;/p&gt;

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

&lt;p&gt;Now when running make clear-cache again we get:&lt;/p&gt;

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

&lt;p&gt;The Makefile says basically that it has the target file already and doesn't need&lt;br&gt;
to execute&lt;/p&gt;

&lt;p&gt;This default behavior is not what we expect in this case and we want to override it. This is when the &lt;strong&gt;.PHONY&lt;/strong&gt; directive comes to the rescue. Let's update our example to use it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;clear-cache&lt;/span&gt;
&lt;span class="nl"&gt;clear-cache&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; cache/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After marking the target as phony, the command behaves as expected&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6e5sy1lyb4xx20q1swa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6e5sy1lyb4xx20q1swa.png" alt="command line result 4" width="409" height="42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pro tip: Another way to mark the targets as phony is to have them all in place list rather than above each of them like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;clear-cache&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; cache/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nl"&gt;clear-build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; build/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;clear-cache clear-build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;In order to override the default behavior in Makefile and use some targets like command runners you can use .PHONY.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html" rel="noopener noreferrer"&gt;GNU Make Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cross-posted from my blog : &lt;a href="https://alexandrunastase.com/posts/meaning-of-phony-in-a-makefile" rel="noopener noreferrer"&gt;What's the meaning of .PHONY in a Makefile&lt;/a&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>cryptocurrency</category>
      <category>blockchain</category>
      <category>offers</category>
    </item>
    <item>
      <title>Building a simple PHP dockerized environment</title>
      <dc:creator>Alexandru Năstase</dc:creator>
      <pubDate>Mon, 09 May 2022 07:02:55 +0000</pubDate>
      <link>https://dev.to/alexandrunastase/building-a-simple-php-dockerized-environment-296k</link>
      <guid>https://dev.to/alexandrunastase/building-a-simple-php-dockerized-environment-296k</guid>
      <description>&lt;p&gt;Unlike other ecosystems like .NET or Java in which containerizing an application for local development might seem more like a burden than a feature when it comes to PHP this is a necessity as well as a welcome bonus of mirroring the production environment very closely. &lt;/p&gt;

&lt;p&gt;Some applications might require a PHP extension that is not present on the local system or there might be some specific php.ini configuration that is set on the production server, which is considered as part of the infrastructure rather than the application itself but can cause problems because of the inconsistency (I had this happen to me several years ago). Using Docker can solve these types of problems and has also the added benefit of being a really good way to develop applications, an argument for this being the good support for remote debugging in IDEs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;I will go through setting up the entire stack, that is PHP 8.1 with fpm, nginx and, mysql as the database and at the end, we will do basic Symfony installation to test everything together.&lt;/p&gt;

&lt;p&gt;If you don't just want to check out the repo with the entire setup you can find it on &lt;a href="https://github.com/alexandrunastase/docker-php-devbox"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up docker-compose configuration
&lt;/h3&gt;

&lt;p&gt;There are two files that tell docker-compose what to spin up. The first is docker-compose.yml and the other is docker-compose.override.yml. The override file is responsible for exposing the host using the hostname &lt;code&gt;dockerhost&lt;/code&gt;. This is useful for both debugging and for referencing other containers more easily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.5'

services:
  devbox:
    container_name: devbox-nginx
    build:
      context: ./docker/nginx
      dockerfile: Dockerfile
    ports:
      - "9001:80"
    volumes:
      - .:/app:cached
    restart: unless-stopped
    depends_on:
      - devbox-service

  devbox-service:
    container_name: devbox-service
    build:
      context: .
    volumes:
      - .:/app:cached
      - ./docker/service/php.ini:/usr/local/etc/php/conf.d/99-app.ini
      - ./docker/service/www.conf:/usr/local/etc/php-fpm.d/www.conf
    restart: unless-stopped
    environment:
      XDEBUG_CONFIG: ${XDEBUG_CONFIG}
      APP_ENV: ${APP_ENV}
      APP_DEBUG: ${APP_DEBUG}
      APP_SECRET: ${APP_SECRET}
    env_file:
      - .env
      - .env.local
    depends_on:
      - mysql

  mysql:
    image: mysql:8.0
    container_name: devbox-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
    ports:
      - "3308:3306"
    volumes:
      - database-volume:/var/lib/mysql

volumes:
  database-volume:
    driver: "local"

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding the Dockerfiles
&lt;/h3&gt;

&lt;p&gt;There are two Dockerfiles used. One for php-fpm and the other for nginx. The one for the app itself is the php-fpm one and it's found in the root of the project and the other one is found in docker/nginx/Dockerfile. The nginx Dockerfile just copies the nginx configuration defined in default.conf into the container. The nginx configuration is quite apart from the fact that the name of the service defined in docker-compose was specified &lt;/p&gt;

&lt;p&gt;Dockerfile for nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM nginx:stable

COPY default.conf /etc/nginx/conf.d/default.conf

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

&lt;/div&gt;



&lt;p&gt;Dockefile for php-fpm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM php:8.1-fpm-alpine

LABEL maintainer="alexandrunastase@github"
LABEL description="Devbox Docker image"

# User build args
ARG APP_ENV="prod"
ARG APP_DEBUG="0"
ARG APP_LOG="php://stdout"

# Environment variables
ENV APP_ENV=${APP_ENV}
ENV APP_DEBUG=${APP_DEBUG}
ENV APP_LOG=${APP_LOG}

ENV XDEBUG_CONFIG=""
ENV COMPOSER_NO_INTERACTION=1

# Add PHP user
ARG PHP_USER_ID=1000
ARG PHP_GROUP_ID=1000
RUN set -x \
    &amp;amp;&amp;amp; addgroup -g $PHP_GROUP_ID -S php \
    &amp;amp;&amp;amp; adduser -u $PHP_USER_ID -D -S -G php php

# Install dependencies
RUN set -ex \
    &amp;amp;&amp;amp; docker-php-source extract \
    &amp;amp;&amp;amp; apk add --update --no-cache \
    ${PHPIZE_DEPS} \
    curl \
    # Runtime deps
    icu-dev icu-libs \
    libzip-dev zlib-dev \
    libxml2-dev \
    oniguruma-dev \
    &amp;amp;&amp;amp; pecl install xdebug \
    &amp;amp;&amp;amp; docker-php-ext-install intl opcache pdo_mysql zip bcmath mbstring sockets pcntl soap sockets ctype &amp;gt; /dev/null \
    &amp;amp;&amp;amp; docker-php-ext-enable intl opcache pdo_mysql zip bcmath mbstring sockets pcntl soap sockets ctype \
    &amp;amp;&amp;amp; apk del ${PHPIZE_DEPS} \
    &amp;amp;&amp;amp; docker-php-source delete

# Copy configuration files
COPY ./docker/service/www.conf /usr/local/etc/php-fpm.d/www.conf
COPY ./docker/service/php.ini $PHP_INI_DIR/conf.d/99-app.ini
COPY ./docker/service/xdebug.ini $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini

# Install composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

COPY --chown=php . /app

WORKDIR /app

USER php

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating the Makefile
&lt;/h3&gt;

&lt;p&gt;I find a Makefile a useful addition to any docker-compose setup, as it makes it much easier to access the common commands without needing to remember how a container was named or needed to search to the shell history.&lt;/p&gt;

&lt;p&gt;Note: When editing Makefiles make sure to always use tabs instead of spaces especially when indenting commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.PHONY: run
run:
    @if [ ! -e ".env.local" ]; then\
        cp .env .env.local; \
    fi
    @docker-compose up -d
    @echo "Service is running on http://localhost:9001"

.PHONY: install
install:
    @docker-compose exec --user="php" -T devbox-service composer install

.PHONY: stop
stop:
    @docker-compose stop

.PHONY: enter
enter:
    @docker-compose exec --user="php" devbox-service /bin/sh

.PHONY: enter-as-root
enter-as-root:
    @docker-compose exec --user="root" devbox-service /bin/sh

.PHONY: test
test:
    @docker-compose exec --user="php" -T devbox-service /bin/sh -c 'APP_ENV="test" ./bin/phpunit --testdox'

.PHONY: destroy
destroy:
    @docker-compose down --rmi local

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Symfony and testing everything
&lt;/h3&gt;

&lt;p&gt;To test the entire setup we can setup a Symfony application. You can find instructions to do so here: &lt;a href="https://symfony.com/doc/current/setup.html"&gt;https://symfony.com/doc/current/setup.html&lt;/a&gt; . I went with the LTS version which is 5.4 at the time of the writing.&lt;/p&gt;

&lt;p&gt;Note: I also updated the composer file to make sure the database is created. You can skip this if you have another way to make that happen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up xDebug
&lt;/h3&gt;

&lt;p&gt;Debugging can be enabled by uncommenting the contents of the file ./docker/service/xdebug.ini&lt;/p&gt;

&lt;p&gt;These are the steps to configure xDebug on PHPStorm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;code&gt;PHP Remote Debugging&lt;/code&gt; as CLI interpreter. Make sure local interpreter is removed&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;Docker Compose&lt;/code&gt; as the configuration type and &lt;code&gt;devbox-service&lt;/code&gt; as the service&lt;/li&gt;
&lt;li&gt;Lifecycle should be &lt;code&gt;Connect to existing container&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Working demo
&lt;/h3&gt;

&lt;p&gt;In the docker-compose the port &lt;strong&gt;9001&lt;/strong&gt; is mapped for the localhost so you can check everything is working after running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; make run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to se tup the containers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; make install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to install all the composer packages.&lt;/p&gt;

&lt;p&gt;There is one endpoint defined called &lt;code&gt;http://localhost:9001/healthz&lt;/code&gt; which should return a 200 status code&lt;/p&gt;

&lt;p&gt;In order to run the tests, you can use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; make test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and for running other ad-hoc commands like requiring another composer package you can do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; make enter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tested using
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu 21.10&lt;/li&gt;
&lt;li&gt;docker version : 20.10.14&lt;/li&gt;
&lt;li&gt;docker-compose version : 1.29.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;cross-posted from my blog: &lt;a href="https://alexandrunastase.com/posts/building-a-simple-php-dockerized-environment"&gt;Building a simple php dockerized environment&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>devops</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to install .NET core SDK with ASP.NET on Manjaro Linux</title>
      <dc:creator>Alexandru Năstase</dc:creator>
      <pubDate>Sat, 26 Sep 2020 07:18:11 +0000</pubDate>
      <link>https://dev.to/alexandrunastase/how-to-install-net-core-sdk-with-asp-net-on-manjaro-linux-1m34</link>
      <guid>https://dev.to/alexandrunastase/how-to-install-net-core-sdk-with-asp-net-on-manjaro-linux-1m34</guid>
      <description>&lt;p&gt;I recently switched from Fedora to Manjaro as my main Linux distribution and since I use .NET core from time to time I wanted to install it. It turns out that since at the time of this writing, it's not  &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/install/linux"&gt;officially supported&lt;/a&gt;, as it was the case with Fedora, there was a bit more trial and error involved in the process. &lt;/p&gt;

&lt;p&gt;My first attempt was to try to install it using  &lt;a href="https://snapcraft.io/dotnet-sdk"&gt;snap&lt;/a&gt;, since it mentions Manjaro in the supported list. I had some issues when I installed it like this, among which the biggest was that the official C# extension in VS Code, OmniSharp, was not working. &lt;/p&gt;

&lt;p&gt;The good news is that there are official Arch Linux packages with the .NET Core SDK now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps to install
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Install dotnet-sdk with asp.net runtime:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo pacman -S dotnet-sdk aspnet-runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In order to have the needed environment variables and the dotnet root in PATH, create a&lt;code&gt;/etc/profile.d/dotnet.sh&lt;/code&gt; file with the following contents:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export DOTNET_ROOT=/usr/share/dotnet
export MSBuildSDKsPath=$DOTNET_ROOT/sdk/$(${DOTNET_ROOT}/dotnet --version)/Sdks
export PATH=${PATH}:${DOTNET_ROOT}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;strong&gt;After this step, a reboot or re-login is required.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Depending on what shell you use, append to the &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt; configuration files the following:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Adds dotnet tools to the PATH variable
export PATH="$PATH:/home/[[USER_NAME]]/.dotnet/tools"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This allows tools like &lt;code&gt;dotnet watch&lt;/code&gt; or &lt;code&gt;dotnet ef&lt;/code&gt; to be available globally&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Although some people suggest also adding &lt;code&gt;DOTNET_CLI_TELEMETRY_OPTOUT=1&lt;/code&gt;, I would advice against it for now, given the fact the Arch Linux is not officially supported and Microsoft might also take into account the usage statistics when prioritizing bug fixes or support for certain Linux distributions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Tested using :
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Manjaro version: 20.1&lt;/li&gt;
&lt;li&gt;Kernel version: 5.8.6-1-MANJARO&lt;/li&gt;
&lt;li&gt;dotnet version: 3.1.107&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Links:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt; &lt;a href="https://gist.github.com/waynebloss/55aa06b13a3f647c45b57caa31397089"&gt;Manjaro dotnet setup &lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.archlinux.org/index.php/.NET_Core"&gt;Arch Linux .NET Core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kelvinmai/how-to-install-dotnet-core-in-manjaro-linux-590a"&gt;How to install dotnet core in Manjaro Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this guide becomes outdated or if you have any issues with the any steps feel free PM me on  &lt;a href="https://twitter.com/AlexNastase01"&gt;Twitter&lt;/a&gt; .&lt;/p&gt;

</description>
      <category>linux</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
