<?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: Sam</title>
    <description>The latest articles on DEV Community by Sam (@mizouzie).</description>
    <link>https://dev.to/mizouzie</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%2F919440%2F029650d8-d045-4e61-ad7f-2b9e1cb1d6a3.png</url>
      <title>DEV Community: Sam</title>
      <link>https://dev.to/mizouzie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mizouzie"/>
    <language>en</language>
    <item>
      <title>Code Block Click Copy</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Tue, 09 Dec 2025 20:51:41 +0000</pubDate>
      <link>https://dev.to/mizouzie/code-block-click-copy-1bke</link>
      <guid>https://dev.to/mizouzie/code-block-click-copy-1bke</guid>
      <description>&lt;p&gt;I'm a back-end leaning full stack developer, so after a whole day of combing through and fixing someone else's JavaScript code all day at work, there was no better way to blow off some steam while I sat waiting for my kid to finish his Taekwondo lesson than to read through and re-write my latest addition to this site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding copy to clipboard functionality to code blocks
&lt;/h2&gt;

&lt;p&gt;The latest addition I refer to was adding little "copy to clipboard" buttons in the corners of my example code blocks throughout this site. I always find them helpful when they're available on documentation or tutorial sites, so I'd spent a couple of hours last night  adding the necessary stylesheets for pretty code blocks and then going through the Hugo forums seeing how others had tackled this. I was grateful to stumble across a discussion in which someone had kindly provided a whole example repo/branch so I pulled it down and cherry-picked the parts that made it all tick, created a &lt;code&gt;package.json&lt;/code&gt; file and ran &lt;code&gt;npm ci&lt;/code&gt;. Boom! We had a cool little copy icon in the corner of every code block.&lt;/p&gt;

&lt;p&gt;Excitedly I pushed all my changes, which triggered the deployment workflows, and a minute later it was live and I was going through all my old articles marvelling at the copy-pasta-ness of it all. But... the pages felt that tiny bit slower to load. They had lost that &lt;em&gt;snap&lt;/em&gt; that had been the whole reason I was so enamored with Hugo built static sites in the first place. So before going to bed, I had a closer look at the actual contents of the &lt;code&gt;package.json&lt;/code&gt; and was reminded of why the JavaScript ecosystem gets so much stick all the time. No less than &lt;strong&gt;four&lt;/strong&gt; libraries were "required" to render these tiny icons and copy stuff to the user's clipboard. That's bonkers. So I did some [over]due diligence and learned about the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API" rel="noopener noreferrer"&gt;Clipboard API&lt;/a&gt; which had full support in most browsers since ages ago. Why wasn't I just using that?&lt;/p&gt;

&lt;p&gt;Let's just use that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Clipboard.js in a Hugo site
&lt;/h2&gt;

&lt;p&gt;I would certainly not have been able to write this all from scratch, even with a solid understanding of the API, but I didn't have to. I already had &lt;a href="https://discourse.gohugo.io/t/how-to-add-a-copy-to-clipboard-button-to-code-blocks/49633/4?u=mizouzie" rel="noopener noreferrer"&gt;what was shown here&lt;/a&gt; as a starting point, so it was simple to break down the steps of what needed to be done. We'll break down the function that does the heavy lifting &lt;code&gt;addCopyToClipboardButtons(containerClass, buttonClass = 'copy-button')&lt;/code&gt; here:&lt;/p&gt;

&lt;p&gt;i. Create and add the button to each of the code block 'containers'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;containerClass&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buttonClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faCopyRegular&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button&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;ii. Create the clipboard object, the most of which is handled by the main dependency&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clipboard&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;ClipboardJS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;buttonClass&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trigger&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="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&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;iii. Handle a successful copy operation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;copy&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faCheck&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearSelection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;iconChangeTimeout&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;iv. Handle an error during a copy operation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ClipboardJS Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faBomb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Assuming you have a cross or 'times' icon&lt;/span&gt;

    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;iconChangeTimeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's actually quite elegant as it is, the only gripe I really had with it is that it requires loading a whole bunch of stuff that likely unused. So based on this, we can quite easily swap out the parts that matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy to clipboard buttons in Hugo with vanilla JavaScript
&lt;/h2&gt;

&lt;p&gt;Step 1 of the above breakdown is actually perfect as it is. There is nothing other than native JS and we end up with some useful bits we can come back to later.&lt;/p&gt;

&lt;p&gt;Step 2 is where we can start to swap out the library for the native API. I had them side by side as I was working out the bugs so we'll give it a "new" name for now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newClipboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, our main difference between the ClipboardJS implementation and the native API is that the former is very similar to jquery and offers an &lt;code&gt;on()&lt;/code&gt; method to deal with either a success or failed operation, while the latter is more aligned with the &lt;code&gt;fetch()&lt;/code&gt; API which has &lt;code&gt;then()&lt;/code&gt; and &lt;code&gt;catch()&lt;/code&gt; methods for dealing with the successfully resolved promise or the failure to do so. This means, that unlike our steps 3 and 4 above being totally separated, we can write a more "try/catch" (hooray for PHP) style chain of instructions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;buttonClass&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;newClipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faCheck&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;iconChangeTimeout&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;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error copying to clipboard:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faBomb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;iconChangeTimeout&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;This actually reads quite nicely already for describing what it is doing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grab our containers&lt;/li&gt;
&lt;li&gt;For each of them;

&lt;ol&gt;
&lt;li&gt;Find the button&lt;/li&gt;
&lt;li&gt;Add a click event listener in which we;

&lt;ol&gt;
&lt;li&gt;Capture the next element sibling's text content (Our demonstration code)&lt;/li&gt;
&lt;li&gt;Write that text to the operating system's clipboard&lt;/li&gt;
&lt;li&gt;Then do nice things like show the user something has happened by swapping the icon to a check mark&lt;/li&gt;
&lt;li&gt;If there was an error, show a bomb icon instead and write the error to the console&lt;/li&gt;
&lt;li&gt;After a set amount of time, swap the icon back to the clipboard icon&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Now that it's converted, we can see how simple this action really is. That means that there is room for improvement! Did you notice how we've got a couple of places where we're repeating actions or redeclaring the same thing? By moving one of the &lt;code&gt;const&lt;/code&gt; declarations up a scope level, it becomes accessible everywhere it is required, and we also seem to be doing two &lt;em&gt;nested&lt;/em&gt; forEach loops of the same things. In the end I thought this was a nice enough level of squished to retain it's readability and still work just as we want it to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./icons.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addCopyToClipboardButtons&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iconChangeTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.highlight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;copy-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faCopyRegular&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faCheck&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;iconChangeTimeout&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;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error copying to clipboard:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;faBomb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalIcon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;iconChangeTimeout&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addCopyToClipboardButtons&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's very likely that there are further optimisations that could be made. The &lt;code&gt;setTimeout()&lt;/code&gt;s could probably go on one line, for instance, but as I said, I was waiting for a Taekwondo lesson to finish, and at this point, it did, so that's as far as I went.&lt;/p&gt;

&lt;p&gt;Once I got home I went and did my favourite thing to do and went through my files and hit &lt;strong&gt;delete&lt;/strong&gt; on package.json, package-lock.json and all of node_modules and even got to go back into my .github/workflows/*.yaml files and remove the entire JS build step 🎉. And then I took the great feeling that gave me and came straight into a new markdown file and started writing out this here post.&lt;/p&gt;

&lt;p&gt;Seeing how simple yet powerful modern JavaScript can be does make me appreciate this strange little language at times. And when it is put together with something as fast and elegant as a nice static website? Forget about it. So Go Hugo some sites and see what else can be wrangled!&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Tum | Modo | Postea</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Tue, 09 Dec 2025 20:38:40 +0000</pubDate>
      <link>https://dev.to/mizouzie/tum-modo-postea-5dlo</link>
      <guid>https://dev.to/mizouzie/tum-modo-postea-5dlo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;tūm&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;(pronounced /tuːm/)&lt;/em&gt; — “then,” “at that moment”; here, a glance back at what once was and the moments that shaped the beginning.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;mŏdō&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;(pronounced /ˈmɔ.doː/)&lt;/em&gt; — “just now,” “only now”; a grounding in the present, the point of clarity from which everything is assessed.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;postĕā&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;(pronounced /ˈpɔs.tɛ.aː/)&lt;/em&gt; — “afterward,” “later on”; a forward-looking view toward what may unfold from this moment onward.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Given that I've re-kindled my interest in this little blog of mine, and that it's almost Christmas, it seems a fitting time to get a bit Charles Dickens and have a look at my past, present and future. Part of the reason I have picked this thing back up is that I finally feel settled in the job I've been at for a few years and actually have a bit of time now because I'm not constantly trying to catch up with everyone. Not that having been in a catch up loop was a bad thing, it was nothing short of a huge opportunity to learn a &lt;strong&gt;tonne&lt;/strong&gt; and really add some serious strings to my web developer bow. I think it's going to be a very worthwhile exercise to look back at where I was when I started out, honestly assess where I'm at currently and then see what avenues I think Id like to go down in the not too distant future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then
&lt;/h2&gt;

&lt;p&gt;Back in November 2023, I took my first flight back to the UK &lt;em&gt;for work&lt;/em&gt; to attend my initial training for a job at Fusions PIM ltd. I had already been working in web development and with Laravel for a couple of years, so wasn't totally green. My CV at the time listed core skills like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Laravel (2 years experience)

&lt;ul&gt;
&lt;li&gt;Built customer requested features into an existing project&lt;/li&gt;
&lt;li&gt;Built a CRM and knowledge base for a subscription based retail company from scratch&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Docker

&lt;ul&gt;
&lt;li&gt;Comfortable working in development containers&lt;/li&gt;
&lt;li&gt;Hosting dockerised web applications on bare servers&lt;/li&gt;
&lt;li&gt;Using containers to "try out" different elements of tech stacks&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open Source

&lt;ul&gt;
&lt;li&gt;Started and managed a small web crawler project aimed at offering beginners an opportunity to try out OSS&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In fairness, I'd not made a bad start considering my first experience with any of this world was when I did &lt;a href="https://github.com/MizouziE/birdboard" rel="noopener noreferrer"&gt;my first Laracasts tutorial&lt;/a&gt; in 2021. But my actual real world experience, and impact on the actual industry would not have even registered as negligible. Looking back I'm a little astonished that this long established company took a punt on me, but I'm very glad they did.&lt;/p&gt;

&lt;p&gt;What I lacked in experience I tried my best to make up for with soft skills like clear communication, not being afraid to look a bit daft by asking a silly question and apart from that just trying really hard to up my levels constantly. I'd been lucky before where I had worked in that I had a huge amount of freedom to manage myself and my workload, and that did not change when I arrived here, even though the company technically &lt;em&gt;had&lt;/em&gt; to be more "organised" to allow for customer transparency and coordination. So I'd work on what I needed to work on, I could literally ask any one of my new colleagues for advice or help as and when I needed it and I still had time to just read and read and read. The reason this reading experience was so valuable was that the codebase I as now working in had been around since long before I'd learned even a single function of PHP. Some of the classes had syntax from years ago. A true legacy monster. Even though a great deal of it had been already converted into a Laravel app, there were still plenty of old quirks that were too fundamental to the business to risk chopping and changing them, so they were just as they were. It was kind of like being locked in a time-rift, but that had more benefits than I realised at the time.&lt;/p&gt;

&lt;p&gt;Some context of the conversion in progress;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application had already had a very similar structure to that of a Laravel app from the start&lt;/li&gt;
&lt;li&gt;Many of the Symfony components that Laravel is built on top of were already being used&lt;/li&gt;
&lt;li&gt;The parts that differed most in the application were to do with more old fashioned security concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Now
&lt;/h2&gt;

&lt;p&gt;Skip ahead a few years and that same mysterious and enormous PHP application that was half-of-yesteryear has been converted almost 100% to a modern Laravel app, through the efforts of colleagues old and new and of myself. The main takeaway I had from being a part of this conversion was that I had to gain a deeper understanding of the Laravel framework because the parts that were left to convert were the more challenging ones, which makes sense as they'd have been bonkers to have not started the conversion before I got there with anything other than the easier parts. I think the areas I got my teeth into the most were Eloquent and Commands, but I definitely was routing around in almost all areas of the framework codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eloquent
&lt;/h3&gt;

&lt;p&gt;A lot of the older parts of the codebase I was working on used proper old school PHP syntax of &lt;code&gt;$sql = 'SELECT * FROM `some_table` WHERE `x` = 'y';&lt;/code&gt; so I got lots of practice reading and understanding SQL, the re-writing to get the same results using eloquent queries. Not only that, much of the application was to do with search filtering based on model relationships so I had to make sure I really understood how relations could be properly defined and used for querying. Over the years I was doing this, eloquent methods for querying relationships were improving week on week and I was constantly being presented with ways to improve what we had, both for performance &lt;strong&gt;and&lt;/strong&gt; for developer experience.&lt;/p&gt;

&lt;p&gt;The main thing I love about eloquent is how well it reads, especially around relations. A lot of the time there's no need to &lt;em&gt;think&lt;/em&gt; too hard about what is happening because the methods, like &lt;code&gt;withWhereHas('relation', fn ($query) =&amp;gt; $query-&amp;gt;condition())&lt;/code&gt;, tell you exactly what the result is going to contain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Commands
&lt;/h3&gt;

&lt;p&gt;My appreciation for Symfony knows no bounds because I've really been in the &lt;a href="https://symfony.com/doc/current/console.html" rel="noopener noreferrer"&gt;trenches of the docs&lt;/a&gt; for &lt;em&gt;just&lt;/em&gt; the console and it's pretty awesome when you consider how fundamentally simple it's been kept. In my humble opinion, Laravel has obscured &lt;em&gt;some&lt;/em&gt; of the simplicity in the parts they've borrowed, for instance when you combine the testing helpers &lt;code&gt;$this-&amp;gt;artisan(Command::class)-&amp;gt;expectsTable([...])&lt;/code&gt;, which makes a huge assumption that you've defined the table styling, with a command output table in which you've not defined the style for you'll be momentarily stumped why your tests are failing before figuring out that the default style for tables in Laravel is not the same as the default style for tables in Symfony 🫤 &lt;/p&gt;

&lt;p&gt;Apart from the small quirks, the capabilities of commands is fantastic and it even inspired some thoughts in me that lead me into the speculative part of this assessment that will be explored a little later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall
&lt;/h3&gt;

&lt;p&gt;Having spent this time writing code, as well as reading and reviewing a lot of code of high quality, my style and even thought process when solving problems has improved a great deal. I am happy with where I'm at currently, but can certainly see the edges of my own scope for improvement and will continue to chase after it. I've kept up with practicing outside of work with things like &lt;a href="//www.codewars.com"&gt;CodeWars&lt;/a&gt; and tried to maintain my interest in languages outside of my 9 to 5 use of PHP and SQL, mostly bash and Golang but also recently delving into C++. Also, because I've recently reached this comfort level I've picked up this small side project and hope to be able to maintain writing again, as it definitely did contribute to me developing my own understanding back when I started out.&lt;/p&gt;

&lt;p&gt;Contributing to open source projects has become a more regular thing recently, which has boosted my confidence somewhat as well as been a great opportunity to see how different, well established projects work and some experiences resulted in positive changes in my day to day work.&lt;/p&gt;

&lt;p&gt;Having reached this level has afforded me more time to pursue other old hobbies like reading too, which has been great for me personally and has inspired a new dimension of this very personal website that I'm quite excited to get launched soon (Look out for a &lt;a href="///../tldr"&gt;tl;dr&lt;/a&gt; section up in the navigation!).&lt;/p&gt;

&lt;h2&gt;
  
  
  After
&lt;/h2&gt;

&lt;p&gt;So seeing as I think that I managed to reach the "next level" that I'd envisaged when starting out at my current position, what comes next?&lt;/p&gt;

&lt;p&gt;I have had experience of working under some great development managers, and I think that I should (and will) aim for not their position, but their mentality. I believe the next major improvement that I can make is being able to think X steps ahead and in a big picture sense, regardless of how cliché that sounds. I mean, things &lt;em&gt;become&lt;/em&gt; cliché when they're tried and true, no?&lt;/p&gt;

&lt;p&gt;What I mean is that I hope to improve my decision making when facing a problem, or writing a feature. I have gained a decent amount of experience and should be able to leverage that into foresight, while still building and reinforcing that experience. I have seen first hand how all decisions (in a architectural sense) are about trade-offs as there's never a truly 100% correct solution, just a best-fit one, or even two. I want to be able to weigh up the pros and cons with confidence and then execute plans based on those decisions. I even have a few examples of this type already in my sights, so I want to be sure that I am pursuing them with a level head and not for the sake of wanting to "establish" myself or anything selfish like that.&lt;/p&gt;

&lt;p&gt;Another thing I hope to develop in myself is to keep focused on what matters in a business sense. I've been guilty of spending too much time writing things "the right way" when the actual business value of the thing I'm writing is small. At the end of the day, we build tools to solve business problems. When we solve the problem, we gain value, and making the code clever, or pretty doesn't actually make as huge of a difference as we feel like we're making while doing it. A &lt;a href="https://www.youtube.com/watch?v=RfRp6CwKoVU" rel="noopener noreferrer"&gt;great video explaining this&lt;/a&gt; from 2025 Laracon EU by John Drexler, which my team and I were actually in attendance for, sums it up perfectly and even though my teammates and I constantly refer back to it, I know for a fact that I can still implement the mentality much better than I do now. By doing this more strictly I will greatly improve my value as a developer.&lt;/p&gt;

&lt;p&gt;So after that brief look backward, inwards and forwards, I think I am mostly grateful for the opportunities I have been presented and I am actually pleased with what I have managed to achieve with them, which definitely does not align with how I felt back then 😅&lt;/p&gt;

&lt;p&gt;I could probably be a little easier on myself, because having struggled with things did not mean I was as dumb as I felt!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>development</category>
      <category>career</category>
      <category>laravel</category>
    </item>
    <item>
      <title>I Tried Working at 30,000ft</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Thu, 31 Aug 2023 10:00:00 +0000</pubDate>
      <link>https://dev.to/mizouzie/i-tried-working-at-30000ft-3dem</link>
      <guid>https://dev.to/mizouzie/i-tried-working-at-30000ft-3dem</guid>
      <description>&lt;h2&gt;
  
  
  How I thought it would go
&lt;/h2&gt;

&lt;p&gt;I had always seen people working on their laptops in airports and on aeroplanes, so it was an easy assumption to make that I too would be able to do so. I have two projects on-going and definite &lt;em&gt;next steps&lt;/em&gt; that need to be done for each. Fairly monotonous tasks that I should be comfortable with and can just get on with.&lt;/p&gt;

&lt;p&gt;Normally, when working at home I only get about 2.5 hours in the day when I am 100% left alone and can focus fully on a task. This golden hour is great, but I'd love to know how productive I could be given the opportunity of a longer window of focus. Stuck in a seat on a plane, without having to entertain my 6 year old son for at least 3 hours with the potential of an additional hour either end of waiting around. Sounds like a great chance to find out!&lt;/p&gt;

&lt;p&gt;I usually work on remote development servers so that was something to consider. There's no WiFi at 30,000ft in economy class. But, as I said, my tasks were not anything new to me, so as long as I had my repository saved locally I should probably be ok. I've written hundreds of tests in the last few months alone, and I need to write some for a fresh project so they'll be super basic. Should be a blast. Alternatively I've got some HTML to steal from a template email and incorporate into some usable components for another project. Low level stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparations
&lt;/h2&gt;

&lt;p&gt;So my main concern was that most of my current work is remote, so first thing to do was to &lt;code&gt;git clone&lt;/code&gt; everything I intended to work on into a local directory. Simple enough.&lt;/p&gt;

&lt;p&gt;The projects are Laravel applications, so I made sure to set up my &lt;code&gt;.env&lt;/code&gt; and run &lt;code&gt;composer install &amp;amp;&amp;amp; npm install&lt;/code&gt; so that all my dependencies were available. Luckily I had an inkling to be extra cautious and tried to run my migrations to make sure the MySQL database was all ok. I say luckily because I didn't actually have MySQL or MariaDB installed!&lt;/p&gt;

&lt;p&gt;So I went about installing MariaDB as I had always just used docker for my databases when working locally before moving over to a remote development server. For some reason I have gone off of Docker lately so prefer to just run MariaDB (the OSS and friendly version of MySQL) on my machine. I did write about running databases in Docker before &lt;a href="https://www.mizouzie.dev/articles/why-use-docker-for-databases-and-how" rel="noopener noreferrer"&gt;which you can read by clicking here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I made sure to have my laptop battery, phone battery and headphones battery all fully charged and even made sure to have some good old fashioned mp3s saved on my phone so I could still listen to music without streaming.&lt;/p&gt;

&lt;p&gt;For the project that I need to convert some HTML to components, I made sure to save a copy of the HTML from the page where you can preview the email. Even went s far as to check that I could see it all properly when serving just my single stolen page. And it worked just right immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it really went
&lt;/h2&gt;

&lt;p&gt;Safe to say nothing went like I imagined...&lt;/p&gt;

&lt;h3&gt;
  
  
  Project #1
&lt;/h3&gt;

&lt;p&gt;This is a work project, fresh Laravel app that I spent the previous few days designing and laying out the models and database structure for. I had to start some basic tests as I'd kept everything fairly loose while figuring out what kind of relationships the models all needed between them. Now that I was more settled, it was time to write the tests to ensure that further changes don't break things.&lt;/p&gt;

&lt;p&gt;So I write my first test, easy enough. Goes green after not too many errors. Second test the same. Then I want to refactor early to avoid repeating myself in populating the database with data and an authenticated user. I'd done this before I'm sure, what I believe I need is:&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;__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;User&lt;/span&gt; &lt;span class="nv"&gt;$user&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;Client&lt;/span&gt; &lt;span class="nv"&gt;$clients&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;setup&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&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;create&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;clients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&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;create&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;But it turned out that this isn't what I needed. I am somehow passing a string to the typed variable... as I sit here now, still on the plane I cannot put my finger on how I am doing this wrong, but I know that if I had an internet connection right now all I need to is check a repo I worked on a week or two ago (on the remote server) and I'll see immediately how I wrote the &lt;strong&gt;actual needed thing&lt;/strong&gt; rather than this terrible recollection/representation of it.&lt;/p&gt;

&lt;p&gt;I know it's possible to run a &lt;code&gt;setup()&lt;/code&gt; method to run what ever seeding you want or create a user that will be &lt;em&gt;reusable&lt;/em&gt; between tests. I know because I did it recently. It's very frustrating that I can't recall it right now.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Edit, the following day: I found what my problem was in the docs. I should have used &lt;code&gt;setUp()&lt;/code&gt; with an uppercase "U" and also called &lt;code&gt;parent::setUp()&lt;/code&gt; within my method. I found it at the bottom of &lt;a href="https://laravel.com/docs/10.x/testing#creating-tests" rel="noopener noreferrer"&gt;this section about testing&lt;/a&gt;. What I actually needed was the following:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&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;Collection&lt;/span&gt; &lt;span class="nv"&gt;$clients&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;setUp&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;setUp&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&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;create&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;clients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&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;create&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;I could just repeat myself for the moment and come back to refactor later having referred to the docs or even my older code. So let me write some tests using the &lt;code&gt;$this-&amp;gt;actingAs($user)&lt;/code&gt; to make sure I wasn't getting redirected to a login route. Oh, there is no login route. I had only installed Breeze, Laravel's quick and easy solution to out-of-the-box auth, on a branch that got scrapped after a front end re-design. Great... No matter, even though I cannot quickly download and install Breeze again without internet, I can just &lt;code&gt;git cherry-pick&lt;/code&gt; the commit from the abandoned branch on which I had previous installed it. As it is mostly new files and my current &lt;code&gt;routes/web.php&lt;/code&gt; file is untouched, then the changes brought shouldn't break anything.&lt;/p&gt;

&lt;p&gt;I impressed myself that I managed to do this without Googling anything, if I'm honest. It worked. The thing I did not anticipate was all the changes to tailwind that would require another &lt;code&gt;npm install&lt;/code&gt;... damn it. My front end was now broken and I could not run &lt;code&gt;npm run dev&lt;/code&gt; without it crashing. I had a hacky way of circumventing this that involved commenting out some lines in the &lt;code&gt;postcss.config.js&lt;/code&gt; file but it was ugly, and I even tried just abandoning the &lt;code&gt;middleware('auth')&lt;/code&gt; on the routes altogether to just write some tests but I was pissing in the wind at this point. Move on Sam.&lt;/p&gt;

&lt;p&gt;Never mind, I have a backup for this situation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project #2
&lt;/h3&gt;

&lt;p&gt;This is  a project I'm working on for a friend that is a partly automated email sending app. I have already written all the guts of it and it sends what we want and collects email addresses etc and that's all great. Now it just needs the front end polish, which I typically hate, but He made a template using MailChimp email builder and all I had to do was sift through it and pick out the various parts and styling that we wanted in our email.&lt;/p&gt;

&lt;p&gt;I had glanced at the HTML when I copied it and it looked ok-ish. But on closer inspection it was a straight up mess. Toxic even. Style attributes in almost all HTML tags. The whole thing was one big table with forced layout sizes. Not only that, the entire &lt;code&gt;&amp;lt;body&amp;gt;...&amp;lt;/body&amp;gt;&lt;/code&gt; was written on  a single line and even with my autoformatter, I could not get it into a sensible layout, so picking out bits and editing others was a horrendous amount of side scrolling.&lt;/p&gt;

&lt;p&gt;Oh and did I mention that the kid sitting in the seat in front of me was some kind of jack-in-the-box? Every time he jumped, my thumb would accidentally swipe over the tracking pad and loose the place I had just painstakingly scrolled to. I tried working with the laptop on my actual lap, as the name may suggest is easy to do so, but it's a poxy little 14" screen so it was very uncomfortable. Did not help that the style of plane seat arrangement was inline with a tin of sardines. No legroom whatsoever       .&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;p&gt;So absolutely nothing that I planned to get done got done. Zero for two. Instead of letting myself get mad about it, I decided to write this so that I could at least gain &lt;em&gt;something&lt;/em&gt; from this experience. The main lessons I learned were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developing a Laravel 10 application without an internet connection is tough if you've not got all your packages inline beforehand.&lt;/li&gt;
&lt;li&gt;Even doing tasks that had been done repeatedly before can sometimes need the littlest bit of help from some reference, be it documentation or an old project.&lt;/li&gt;
&lt;li&gt;Before doing things totally offline, doing a dry-run is probably a good idea to catch the trivial hurdles.&lt;/li&gt;
&lt;li&gt;HTML generated from "builder" style tools can be clunky and follow anti-patterns.&lt;/li&gt;
&lt;li&gt;I am better at git than I used to be. (Maybe because I messed it up so many times!)&lt;/li&gt;
&lt;li&gt;Cheap flights do not have a comfortable amount of room to think in.&lt;/li&gt;
&lt;li&gt;It's better to write content than code in my case, because I am still too dependent on documentation.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>travel</category>
      <category>remote</category>
      <category>writing</category>
    </item>
    <item>
      <title>MySQL Database Migration to a Remote Server from a .gz mysqldump file</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Wed, 30 Aug 2023 07:25:00 +0000</pubDate>
      <link>https://dev.to/mizouzie/mysql-database-migration-to-a-remote-server-from-a-gz-mysqldump-file-33ia</link>
      <guid>https://dev.to/mizouzie/mysql-database-migration-to-a-remote-server-from-a-gz-mysqldump-file-33ia</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I had a task a few months back of discovering the cause of a bug in a production environment that just was not presenting itself in development, mostly due to the creators and users of the application having ever so slightly differing ideas about how the app should be used. This meant that in all of our testing while making the application, we never saw the bug that was being reported. The solution for this was to take a copy of the production database and use that in development to try and replicate the reported issue.&lt;/p&gt;

&lt;p&gt;The application was a CMS (Content Management System) that had a few extra niceties that introduced a little more complex database structuring, so that could be one reason it was hard for the development team to preempt this problem. All the same, the tech lead went ahead and made a mysqldump file &lt;code&gt;blogs.sql.gz&lt;/code&gt; and promptly forwarded it to me to get to work with figuring things out. All our development work is done on a dedicated development remote server, and I had the file on my local machine so I'd need to extract and upload the file to the remote server, which was something  I had not previously done.&lt;/p&gt;

&lt;p&gt;I will cover the steps I went through in order to discover how exactly how to get the database created and populated with the desired data. It was a journey of discover for me as I was making use of tools that I was familiar with as well as new (to me) tools and therefore had some steps that may not be deemed &lt;em&gt;necessary&lt;/em&gt;, but I will include them as they taught me something and my goal is to share those lessons.&lt;/p&gt;

&lt;p&gt;I had a few specific problems which I will explain in more detail further down, which caused a few of the extra steps I took so there is more to learn here than just uploading data. As well as just documenting my thought process for my own benefit, I hope to offer some guidance to other junior developers in ways to approach the type of problems that cost us a lot of time when we are starting out.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;I went through steps that allowed me to read the dump file, attempted to pipe that to the remote server, read the error messages and made whatever changes I needed and repeated until I had what I needed and eventually uploaded the data so I could have an exact copy of production on my development environment.&lt;/p&gt;

&lt;p&gt;Skip down to Final working Command to see the command I ended up with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case
&lt;/h3&gt;

&lt;p&gt;In the case I am presenting here we have;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a zipped mysqldump file (.gz) located in &lt;code&gt;./Downloads/blogs.sql.gz&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the file contains a number of &lt;code&gt;mysqldump: [Warning]/Error...&lt;/code&gt; lines (due to being made with/without a password)&lt;/li&gt;
&lt;li&gt;a remote server to which we have ssh access, denoted by &lt;code&gt;&amp;lt;user&amp;gt;@&amp;lt;hostname&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;mysql installed on said server&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Particular problems we face
&lt;/h4&gt;

&lt;p&gt;The first stumbling block was the warnings that do not parse normally when uploading a mysqldump file. Their presence breaks the stream and so nothing after them will be read. I ended up solving this problem in more than one way as you will see by the end. My first "solution" introduced new problems that became apparent later on.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other uses
&lt;/h4&gt;

&lt;p&gt;There is no reason I see that the working knowledge highlighted in the rest of this article cannot be beneficial to other use cases where, for example, a mysql dump file devoid of any warnings needs to be uploaded. I will break down each part of any commands we examine, so you can decide which you need to apply for your case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subjects we will cover
&lt;/h3&gt;

&lt;p&gt;A number of tools will be covered, so I will introduce them briefly here and explain their specific uses and additional flags when appropriate.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gzip&lt;/td&gt;
&lt;td&gt;compress or expand files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tail&lt;/td&gt;
&lt;td&gt;output the last part of files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;head&lt;/td&gt;
&lt;td&gt;output the first part of files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ssh&lt;/td&gt;
&lt;td&gt;OpenSSH remote login client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mysql&lt;/td&gt;
&lt;td&gt;a simple SQL shell that supports interactive use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sed&lt;/td&gt;
&lt;td&gt;stream editor for filtering and transforming text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\&lt;/td&gt;
&lt;td&gt;(pipe)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;You can see the whole raw interaction I had by clicking &lt;a href="https://www.mizouzie.dev/mysqldump-steps" rel="noopener noreferrer"&gt;here&lt;/a&gt; and see the MySQL set up by clicking &lt;a href="https://www.mizouzie.dev/mysql-setup" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create the database
&lt;/h3&gt;

&lt;p&gt;The first step is to use &lt;code&gt;ssh&lt;/code&gt; to access the development server and be able to make changes using the &lt;code&gt;mysql&lt;/code&gt; shell to add a new database that we will populate from the dump file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@Mizouzie:~&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will get us in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;:&lt;span class="nv"&gt;$ &lt;/span&gt;mysql
Welcome to the MariaDB monitor.  Commands end with &lt;span class="p"&gt;;&lt;/span&gt; or &lt;span class="se"&gt;\g&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Your MariaDB connection &lt;span class="nb"&gt;id &lt;/span&gt;is 15401
Server version: 10.6.12-MariaDB-1:10.6.12+maria~deb11 mariadb.org binary distribution

Copyright &lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt; 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type &lt;span class="s1"&gt;'help;'&lt;/span&gt; or &lt;span class="s1"&gt;'\h'&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;help. Type &lt;span class="s1"&gt;'\c'&lt;/span&gt; to clear the current input statement.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now on the development server, use the &lt;code&gt;mysql&lt;/code&gt; command to open the shell client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;MariaDB &lt;span class="o"&gt;[(&lt;/span&gt;none&lt;span class="o"&gt;)]&amp;gt;&lt;/span&gt; show databases&lt;span class="p"&gt;;&lt;/span&gt;
+-----------------------+
| Database              |
+-----------------------+
| information_schema    |
| content_generator     |
| example_laravel       |
| next_con_gen          |
+-----------------------+
4 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.001 sec&lt;span class="o"&gt;)&lt;/span&gt;

MariaDB &lt;span class="o"&gt;[(&lt;/span&gt;none&lt;span class="o"&gt;)]&amp;gt;&lt;/span&gt; create database example_laravel_dummy
    -&amp;gt; &lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 1 row affected &lt;span class="o"&gt;(&lt;/span&gt;0.000 sec&lt;span class="o"&gt;)&lt;/span&gt;

MariaDB &lt;span class="o"&gt;[(&lt;/span&gt;none&lt;span class="o"&gt;)]&amp;gt;&lt;/span&gt; show databases&lt;span class="p"&gt;;&lt;/span&gt;
+--------------------------+
| Database                 |
+--------------------------+
| information_schema       |
| content_generator        |
| example_laravel          |
| example_laravel_dummy    |
| next_con_gen             |
+--------------------------+
5 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.001 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;show databases;&lt;/code&gt; to check existing databases In this case our development DB is &lt;strong&gt;example_laravel&lt;/strong&gt; so we will create a dummy version &lt;strong&gt;example_laravel_dummy&lt;/strong&gt; which we'll use later. Use &lt;code&gt;show databases;&lt;/code&gt; once more to confirm it was created.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Try to import directly
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql -u sam -p example_laravel_dummy"&lt;/span&gt; &amp;lt; ./Downloads/blogs.sql.gz 
Enter password: ERROR 1045 &lt;span class="o"&gt;(&lt;/span&gt;28000&lt;span class="o"&gt;)&lt;/span&gt;: Access denied &lt;span class="k"&gt;for &lt;/span&gt;user &lt;span class="s1"&gt;'sam'&lt;/span&gt;@&lt;span class="s1"&gt;'localhost'&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;using password: YES&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are using &lt;code&gt;ssh&lt;/code&gt; and feeding a command into it by passing a string between quotation marks. Effectively we are running &lt;code&gt;mysql -u sam -p example_laravel_dummy&lt;/code&gt; &lt;strong&gt;on&lt;/strong&gt; the remote server but &lt;strong&gt;from&lt;/strong&gt; our local machine.&lt;/p&gt;

&lt;p&gt;I should not have used the &lt;code&gt;-p&lt;/code&gt; flag for a password, so let's omit that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql -u sam example_laravel_dummy"&lt;/span&gt; &amp;lt; ./Downloads/blogs.sql.gz 
ERROR: ASCII &lt;span class="s1"&gt;'\0'&lt;/span&gt; appeared &lt;span class="k"&gt;in &lt;/span&gt;the statement, but this is not allowed unless option &lt;span class="nt"&gt;--binary-mode&lt;/span&gt; is enabled and mysql is run &lt;span class="k"&gt;in &lt;/span&gt;non-interactive mode. Set &lt;span class="nt"&gt;--binary-mode&lt;/span&gt; to 1 &lt;span class="k"&gt;if &lt;/span&gt;ASCII &lt;span class="s1"&gt;'\0'&lt;/span&gt; is expected. Query: Sd&lt;span class="s1"&gt;'.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the file format is a problem as we have not extracted it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql -u sam example_laravel_dummy"&lt;/span&gt; &amp;lt; &lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-dk&lt;/span&gt; ./Downloads/blogs.sql.gz 
bash: &lt;span class="nb"&gt;gzip&lt;/span&gt;: No such file or directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to install &lt;code&gt;gzip&lt;/code&gt;, so go ahead and do that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql example_laravel_dummy"&lt;/span&gt;
ERROR 1064 &lt;span class="o"&gt;(&lt;/span&gt;42000&lt;span class="o"&gt;)&lt;/span&gt; at line 1: You have an error &lt;span class="k"&gt;in &lt;/span&gt;your SQL syntax&lt;span class="p"&gt;;&lt;/span&gt; check the manual that corresponds to your MariaDB server version &lt;span class="k"&gt;for &lt;/span&gt;the right syntax to use near &lt;span class="s1"&gt;'mysqldump: [Warning] Using a password on the command line interface can be in...'&lt;/span&gt; at line 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two flags used &lt;code&gt;-c&lt;/code&gt; &amp;amp; &lt;code&gt;-d&lt;/code&gt; with &lt;code&gt;gzip&lt;/code&gt; will write the output on to standard output and decompress which is what allows us the then pipe that output into our following &lt;code&gt;ssh&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Also note that we have inverted the command to run &lt;code&gt;gzip&lt;/code&gt; first so that we pipe the output of that into the &lt;code&gt;ssh&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Our new error indicates a syntax error in the SQL statement we wish to run via the &lt;code&gt;mysql&lt;/code&gt; command. That brings us to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Read the mysqldump file
&lt;/h3&gt;

&lt;p&gt;In order to see why and where we have this issue, we can use the &lt;code&gt;head&lt;/code&gt; command to read the first 10 lines of the file after unzipping it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | &lt;span class="nb"&gt;head
&lt;/span&gt;mysqldump: &lt;span class="o"&gt;[&lt;/span&gt;Warning] Using a password on the &lt;span class="nb"&gt;command &lt;/span&gt;line interface can be insecure.
&lt;span class="nt"&gt;--&lt;/span&gt; MySQL dump 10.13  Distrib 8.0.33, &lt;span class="k"&gt;for &lt;/span&gt;Linux &lt;span class="o"&gt;(&lt;/span&gt;aarch64&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; Host: localhost    Database: blogs
&lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;------------------------------------------------------&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; Server version   8.0.33

/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @OLD_CHARACTER_SET_CLIENT&lt;span class="o"&gt;=&lt;/span&gt;@@CHARACTER_SET_CLIENT &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @OLD_CHARACTER_SET_RESULTS&lt;span class="o"&gt;=&lt;/span&gt;@@CHARACTER_SET_RESULTS &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @OLD_COLLATION_CONNECTION&lt;span class="o"&gt;=&lt;/span&gt;@@COLLATION_CONNECTION &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see by this output that the line beginning with &lt;code&gt;mysqldump: [Warning]&lt;/code&gt; is problematic and not recognised as proper SQL syntax. Furthermore, the following lines are commented out so they could also be omitted.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Skip first 7 lines
&lt;/h3&gt;

&lt;p&gt;So as our first 7 lines contain bad syntax and useless information, let's send the same output but without the first 7 lines. Similar to &lt;code&gt;head&lt;/code&gt;, we can use &lt;code&gt;tail&lt;/code&gt; to send everything after a specified line number by making use of the &lt;code&gt;-n&lt;/code&gt; flag with a positive (+) integer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; +7 | ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql example_laravel_dummy"&lt;/span&gt;
ERROR 1064 &lt;span class="o"&gt;(&lt;/span&gt;42000&lt;span class="o"&gt;)&lt;/span&gt; at line 12: You have an error &lt;span class="k"&gt;in &lt;/span&gt;your SQL syntax&lt;span class="p"&gt;;&lt;/span&gt; check the manual that corresponds to your MariaDB server version &lt;span class="k"&gt;for &lt;/span&gt;the right syntax to use near &lt;span class="s1"&gt;'mysqldump: Error: '&lt;/span&gt;Access denied&lt;span class="p"&gt;;&lt;/span&gt; you need &lt;span class="o"&gt;(&lt;/span&gt;at least one of&lt;span class="o"&gt;)&lt;/span&gt; the PROCESS priv...&lt;span class="s1"&gt;' at line 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New error, but similar to the one we came across before. This means we must delve a little deeper down the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Read further down the file
&lt;/h3&gt;

&lt;p&gt;We can use a &lt;code&gt;-n&lt;/code&gt; flag on head to specify the number of lines shown. Without this flag it defaults to 10, so we will use a higher number to see more than before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 25
mysqldump: &lt;span class="o"&gt;[&lt;/span&gt;Warning] Using a password on the &lt;span class="nb"&gt;command &lt;/span&gt;line interface can be insecure.
&lt;span class="nt"&gt;--&lt;/span&gt; MySQL dump 10.13  Distrib 8.0.33, &lt;span class="k"&gt;for &lt;/span&gt;Linux &lt;span class="o"&gt;(&lt;/span&gt;aarch64&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; Host: localhost    Database: blogs
&lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;------------------------------------------------------&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; Server version   8.0.33

/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @OLD_CHARACTER_SET_CLIENT&lt;span class="o"&gt;=&lt;/span&gt;@@CHARACTER_SET_CLIENT &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @OLD_CHARACTER_SET_RESULTS&lt;span class="o"&gt;=&lt;/span&gt;@@CHARACTER_SET_RESULTS &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @OLD_COLLATION_CONNECTION&lt;span class="o"&gt;=&lt;/span&gt;@@COLLATION_CONNECTION &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;50503 SET NAMES UTF8 &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40103 SET @OLD_TIME_ZONE&lt;span class="o"&gt;=&lt;/span&gt;@@TIME_ZONE &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40103 SET &lt;span class="nv"&gt;TIME_ZONE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'+00:00'&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40014 SET @OLD_UNIQUE_CHECKS&lt;span class="o"&gt;=&lt;/span&gt;@@UNIQUE_CHECKS, &lt;span class="nv"&gt;UNIQUE_CHECKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40014 SET @OLD_FOREIGN_KEY_CHECKS&lt;span class="o"&gt;=&lt;/span&gt;@@FOREIGN_KEY_CHECKS, &lt;span class="nv"&gt;FOREIGN_KEY_CHECKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @OLD_SQL_MODE&lt;span class="o"&gt;=&lt;/span&gt;@@SQL_MODE, &lt;span class="nv"&gt;SQL_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'NO_AUTO_VALUE_ON_ZERO'&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40111 SET @OLD_SQL_NOTES&lt;span class="o"&gt;=&lt;/span&gt;@@SQL_NOTES, &lt;span class="nv"&gt;SQL_NOTES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
mysqldump: Error: &lt;span class="s1"&gt;'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation'&lt;/span&gt; when trying to dump tablespaces

&lt;span class="nt"&gt;--&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; Table structure &lt;span class="k"&gt;for &lt;/span&gt;table &lt;span class="sb"&gt;`&lt;/span&gt;activity_log&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt;

DROP TABLE IF EXISTS &lt;span class="sb"&gt;`&lt;/span&gt;activity_log&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;40101 SET @saved_cs_client     &lt;span class="o"&gt;=&lt;/span&gt; @@character_set_client &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this output we see that there is another error message that breaks syntax rules. This one follows after a number of settings that may be safe to assume are ok by default, so we will try to use &lt;code&gt;tail&lt;/code&gt; like before but from even further down the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; +24 | ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql example_laravel_dummy"&lt;/span&gt;
ERROR 1005 &lt;span class="o"&gt;(&lt;/span&gt;HY000&lt;span class="o"&gt;)&lt;/span&gt; at line 96: Can&lt;span class="s1"&gt;'t create table `example_laravel_dummy`.`article_background_image` (errno: 150 "Foreign key constraint is incorrectly formed")
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we see that this will not work because we omitted something important. Namely the line &lt;code&gt;/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Set important server variables
&lt;/h3&gt;

&lt;p&gt;We can try to set the missing server variable and keep our current way of feeding the SQL statement by using &lt;code&gt;--init command=[command]&lt;/code&gt; after &lt;code&gt;mysql&lt;/code&gt;. We will use that to disable the foreign key checks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; +24 | ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql --init-command=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;SET SESSION FOREIGN_KEY_CHECKS=0;&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; example_laravel_dummy"&lt;/span&gt;
ERROR 1231 &lt;span class="o"&gt;(&lt;/span&gt;42000&lt;span class="o"&gt;)&lt;/span&gt; at line 2261: Variable &lt;span class="s1"&gt;'time_zone'&lt;/span&gt; can&lt;span class="s1"&gt;'t be set to the value of '&lt;/span&gt;NULL&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have yet a different error, but it's cause is very similar to the last error we encountered. It is down to omitting those seemingly "safe to omit" server variables from the start of the mysqldump file. We need another approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. That's what she &lt;code&gt;sed&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sed&lt;/code&gt; now makes itself useful to us as we can use it with it's regexp matching ability to &lt;em&gt;remove&lt;/em&gt; certain lines from the file stream as they are being streamed. What I mean is, we will just drop out the lines starting with the &lt;code&gt;mysqldump:&lt;/code&gt; that are causing us headache.&lt;/p&gt;

&lt;p&gt;We achieve this by putting 'mysqldump:' in a regexp that deletes any line starting with it as follows; &lt;code&gt;'/mysqldump:/d'&lt;/code&gt;. It's the lowercase 'd' that does the business.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'/mysqldump:/d'&lt;/span&gt; | ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql --init-command=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;SET SESSION FOREIGN_KEY_CHECKS=0;&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; example_laravel_dummy"&lt;/span&gt;
sam@MizouziE:~&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And look at that, &lt;strong&gt;no error&lt;/strong&gt;! That means it worked.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is one thing not entirely necessary here, though. If you spot it shoot me a DM on twitter &lt;a href="https://twitter.com/mizouzie" rel="noopener noreferrer"&gt;@mizouzie&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  8. Final check to make sure
&lt;/h3&gt;

&lt;p&gt;Now all that is left to do is check on our mysql instance on the remote server if everything is as we expect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
MariaDB &lt;span class="o"&gt;[&lt;/span&gt;example_laravel_dummy]&amp;gt; show tables&lt;span class="p"&gt;;&lt;/span&gt;
+------------------------------------+
| Tables_in_example_laravel_dummy |
+------------------------------------+
| activity_log                       |
| article_article                    |
| article_author                     |
| article_background_image           |
| article_category                   |
| article_revisions                  |
| article_site                       |
| article_slugs                      |
| articles                           |
| author_revisions                   |
| author_slugs                       |
| authors                            |
| background_images                  |
| background_images_revisions        |
| blocks                             |
| categories                         |
| category_revisions                 |
| category_site                      |
| category_slugs                     |
| failed_jobs                        |
| features                           |
| fileables                          |
| files                              |
| imports                            |
| linked_images                      |
| links                              |
| mediables                          |
| medias                             |
| menu_revisions                     |
| menus                              |
| migrations                         |
| password_resets                    |
| provider_revisions                 |
| provider_slugs                     |
| providers                          |
| ratings                            |
| redirects                          |
| related                            |
| setting_translations               |
| settings                           |
| site_revisions                     |
| site_user                          |
| sites                              |
| slider_revisions                   |
| sliders                            |
| string_translation_revisions       |
| string_translations                |
| tagged                             |
| tags                               |
| twill_password_resets              |
| twill_users                        |
| &lt;span class="nb"&gt;users&lt;/span&gt;                              |
+------------------------------------+
52 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.001 sec&lt;span class="o"&gt;)&lt;/span&gt;

MariaDB &lt;span class="o"&gt;[&lt;/span&gt;example_laravel_dummy]&amp;gt; ^DBye
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice, we have all our tables and then we exit with &lt;code&gt;Ctrl + D&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final working command
&lt;/h2&gt;

&lt;p&gt;After all our experimenting we got what we wanted, so our final command to do what we want looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam@MizouziE:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; ./Downloads/blogs.sql.gz | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'/mysqldump:/d'&lt;/span&gt; | ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql example_laravel_dummy"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So for any other use case, or just a a breakdown of each part, we had something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;user&amp;gt;@&amp;lt;localhost&amp;gt;:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-cd&lt;/span&gt; &amp;lt;location/of/mysqldump.sql.gz&amp;gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'/&amp;lt;beginning of line to remove&amp;gt;/d'&lt;/span&gt; | ssh &amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"mysql &amp;lt;name_of_database&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the command does this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unzip the file&lt;/li&gt;
&lt;li&gt;Pipe the stream of the file output through &lt;code&gt;sed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Filter out undesired lines with &lt;code&gt;sed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pipe the result of that to &lt;code&gt;ssh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;ssh&lt;/code&gt; execute the &lt;code&gt;mysql&lt;/code&gt; command and feed the piped stream to a named database&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This all works because the zipped mysqldump file is essentially one big SQL statement that can recreate all tables and insert all data that was in the database it was taken from. They tend to be quite large files, hence the need to zip them.&lt;/p&gt;

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

&lt;p&gt;This was a series of steps that ended up giving the desired results. There were probably a number of different ways to arrive at the same conclusion, or even ways to arrive at a different conclusion that gave the same result. That is the cool thing about working in this field, we have a multitude of tools that can do small parts of a solution to a problem. It is up to us to do exercises like this to learn how to combine them into something that gives a result. That is what we software engineers get paid for. Practice problems like this, you'll learn loads!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mysql</category>
      <category>tutorial</category>
      <category>database</category>
    </item>
    <item>
      <title>Send SMTP Mail from Hetzner Server with Firewall</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Mon, 28 Aug 2023 22:56:39 +0000</pubDate>
      <link>https://dev.to/mizouzie/send-smtp-mail-from-hetzner-server-with-firewall-p7p</link>
      <guid>https://dev.to/mizouzie/send-smtp-mail-from-hetzner-server-with-firewall-p7p</guid>
      <description>&lt;h2&gt;
  
  
  The Error - stream_socket_client unable to connect (connection timed out)
&lt;/h2&gt;

&lt;p&gt;After building a cool little app using Laravel which makes use of the fantastic (and seemingly dead simple) &lt;code&gt;symfony/mailer&lt;/code&gt; and you want to send a simple email via SMTP directly from the app by setting up the necessary &lt;code&gt;.env&lt;/code&gt; variables you will undoubtedly test it out on a local/dev environment and will hopefully see that it works very well. Now the fun part of deploying it to a production server using Hetzner's great cloud services. Everything is set; apache/nginx, ssl, workers, the lot and the moment of truth arrives and you go through the actions to trigger an email being sent to your email address of choice.&lt;/p&gt;

&lt;p&gt;Click send.&lt;/p&gt;

&lt;p&gt;Wait.&lt;/p&gt;

&lt;p&gt;Wait some more.&lt;/p&gt;

&lt;p&gt;Refresh inbox...&lt;/p&gt;

&lt;p&gt;Start to wonder...&lt;/p&gt;

&lt;p&gt;Why didn't it send?&lt;/p&gt;

&lt;p&gt;After checking you set everything correctly you finally check the logs and see something like the above image. But why?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reason
&lt;/h2&gt;

&lt;p&gt;It is a timeout error on a standard PHP function &lt;code&gt;stream_socket_client()&lt;/code&gt; which aims to create the secure socket between your application and the mail server so that you may start to send emails via your email server's SMTP connection. It is an unusual error to encounter as it's more common to just work or return a "connection refused" error, but in our case it just times out. There is not a great deal of feedback or evidence to point to why this is happening, but long story short, our request never even makes it out of our server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hetzner Firewall
&lt;/h3&gt;

&lt;p&gt;If you are like me, you wanted to save some CPU %s by utilizing the great firewall offered for free as a part of your Hetzner cloud account and have set up the firewall with various rules for incoming traffic and left it blank for outgoing traffic, which, according to the display window means that there are no restrictions whatsoever. In theory, that means that all outbound requests should be 100% unrestricted.&lt;/p&gt;

&lt;p&gt;There is something we are not seeing here though.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hetzner Documentation, or lack thereof
&lt;/h3&gt;

&lt;p&gt;There is apparently no (or very little) mention of the fact that Hetzner &lt;strong&gt;automatically block&lt;/strong&gt; outbound ports &lt;strong&gt;25&lt;/strong&gt; &amp;amp; &lt;strong&gt;465&lt;/strong&gt;. &lt;a href="https://blog.hqcodeshop.fi/archives/553-Hetzner-outgoing-mail-SMTP-blocked-on-TCP25.html" rel="noopener noreferrer"&gt;Find more details by clicking here&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  TL;DR
&lt;/h4&gt;

&lt;p&gt;Hetzner are savvy to scammers building spam email servers and just making people miserable by assaulting their inboxes until the IP is blocked so they do not allow any outbound traffic on these ports typically used for SMTP mail connections. Smart. But annoying they don't really tell you until you delve into the support section of their site and notice they have a dropdown option for addressing this very specific problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;So once you have found the super specific technical support like the below by clicking on your account icon in the top right and selecting &lt;code&gt;Support&lt;/code&gt; from the dropdown menu:&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%2F70f7fglcuc6bqzkuc164.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%2F70f7fglcuc6bqzkuc164.png" alt="Hetzner Technical Support - Mail not possible" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will then notice that there is a small mention of how you must send a request to have the ports unblocked and that is it. That is the solution. Send them a request via this dialogue box and after a short wait you'll be able to send mail from your Laravel app hosted on a Hetzner server just like how you can in a local environment. Fantastic.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>laravel</category>
      <category>php</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How to test protected functions with PHPUnit in your Laravel app</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Sat, 13 May 2023 21:05:02 +0000</pubDate>
      <link>https://dev.to/mizouzie/how-to-test-protected-functions-with-phpunit-in-your-laravel-app-3lfj</link>
      <guid>https://dev.to/mizouzie/how-to-test-protected-functions-with-phpunit-in-your-laravel-app-3lfj</guid>
      <description>&lt;p&gt;An essential part of developing an app is testing your code. My preferred method of testing my Laravel code is using PHPUnit and this is how I use reflection to test those 'harder to reach' protected and private methods inside classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typical places this arises
&lt;/h2&gt;

&lt;p&gt;Building an application in PHP with Laravel means that we can call on a great number of classes to do various parts of the overall process we wish to achieve. For the purposes of this example (and where I first came across this issue) we will look at writing tests for a Job Class. A job class is one which will be sent some data and then process that data in the background via a worker so that the application is free to continue processing other commands.&lt;/p&gt;

&lt;p&gt;A job class will often contain methods and variables that are;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;public&lt;/li&gt;
&lt;li&gt;private&lt;/li&gt;
&lt;li&gt;protected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can imagine, public methods are easy enough to test against as they are "exposed" to the outside of the class instance. It gets a little more difficult to gain access to these private and protected methods for testing, as they are intended to be called only by other methods within the class instance. They'll be things like getters and setters so that a handle() function does not get clogged up with logic for retrieving it's necessary data.&lt;/p&gt;

&lt;p&gt;When trying to run a test against such a class with private and protected methods, we will run into errors that look like the following two examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error: Call to private Some\ExampleClass::__construct() from scope Tests\Feature\Some\ExampleClassTest
&lt;/h2&gt;

&lt;p&gt;What this error message is telling us is that we are trying to invoke a __construct() method inside the &lt;code&gt;Some\ExampleClass&lt;/code&gt;, which is not allowed from the scope of our test that may look something like the following:&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;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Some&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;ExampleClassTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @test */&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;my_job_does_something&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Some\ExampleClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Make some assertions&lt;/span&gt;
        &lt;span class="mf"&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;Just in that single line, we have already encountered the problem. If we look at the example class itself, we'll see what trips us up:&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="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleClass&lt;/span&gt;
&lt;span class="p"&gt;{&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;__construct&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;readonly&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$input&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="mf"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our attention should be drawn to the &lt;code&gt;private function&lt;/code&gt; part. That constructor called on initiation &lt;strong&gt;CANNOT&lt;/strong&gt; be called from outside of the namespace &lt;code&gt;Some&lt;/code&gt;, we are trying to call it from &lt;code&gt;Tests\Feature\Some\ExampleClassTest&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error: Call to protected method Some\ExampleClass::exampleMethod() from scope Tests\Feature\Some\ExampleClassTest
&lt;/h2&gt;

&lt;p&gt;This error is very similar to the above, just in this case we may have a &lt;code&gt;public function __construct()&lt;/code&gt; so our class may be instantiated from outside, but our helper functions cannot be invoked outside of the &lt;code&gt;handle()&lt;/code&gt; method. If we use the same example as above, we can get one step further before hitting a wall:&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;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Some&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;ExampleClassTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @test */&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;my_job_does_something&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Some\ExampleClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$job&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;exampleMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Make some assertions like...&lt;/span&gt;
        &lt;span class="c1"&gt;// $result-&amp;gt;assertEquals('expected', $result);&lt;/span&gt;
        &lt;span class="mf"&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;So the class is created with no problem, but we want to test methods that are called from &lt;em&gt;within&lt;/em&gt; the &lt;code&gt;handle()&lt;/code&gt; method so we can be certain that the data being handled is the correct data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution: ReflectionClass
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Available in; PHP 5, PHP 7, PHP 8&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Reflection API in PHP is a way to retrieve any and all information from a class during runtime. The way we can use it in this case is to effectively make an instantiated "copy" of the real class we wish to test, "grab" the method we wish to test from the &lt;em&gt;reflection&lt;/em&gt; of the class, and then tweak it ever so slightly to make the private function public so that we may use it from outside of the class which in this case, is from out test.&lt;/p&gt;

&lt;p&gt;Sounds simple enough...&lt;/p&gt;

&lt;h3&gt;
  
  
  new ReflectionClass($exampleClass)
&lt;/h3&gt;

&lt;p&gt;This first step is to create the reflection class on which we can make our needed modifications. There is actually a small &lt;strong&gt;pre&lt;/strong&gt;-first step to take and that is to make a &lt;code&gt;new&lt;/code&gt; instance of the class we wish to reflect and save it to a variable which we &lt;em&gt;then&lt;/em&gt; use in our call to create a &lt;code&gt;new ReflecionClass()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
        &lt;span class="nv"&gt;$exampleClass&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;ExampleClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$reflection&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;ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exampleClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we have something to work with that is a little more malleable and we can decide next what we want from this reflection. Based on the previous examples of errors, let's look at getting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;__construct()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;or some named method like &lt;code&gt;exampleMethod()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  getConstructor()
&lt;/h3&gt;

&lt;p&gt;To get the constructor (public &lt;em&gt;or&lt;/em&gt; private) so that we can feed it with whatever values we need to test against, we have this handy function which may be used as such to set the &lt;code&gt;__construct()&lt;/code&gt; of the class as a useable variable:&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;$exampleClass&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;ExampleClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$reflection&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;ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exampleClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$constructor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflection&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getConstructor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  getMethod()
&lt;/h3&gt;

&lt;p&gt;To get the protected method that we wish to test against we have this method that can be used in a very similar way to the above:&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;$exampleClass&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;ExampleClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$reflection&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;ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exampleClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflection&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exampleMethod'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  setAccessible()
&lt;/h3&gt;

&lt;p&gt;With both the the &lt;code&gt;get&lt;/code&gt; helpers shown, all we are doing is saving the methods &lt;strong&gt;as they are&lt;/strong&gt; to a variable. They haven't yet been unlocked for us to use as we please, but this is where this method steps in and shows the real benefit of this whole process. As easily as this, we can change the methods accessibility so that future calls to it from our non-matching namespace do not set off any errors.&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;$exampleClass&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;ExampleClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$reflection&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;ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exampleClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflection&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exampleMethod'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAccessible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  invokeArgs()
&lt;/h3&gt;

&lt;p&gt;Now that we have a useable version of the protected/private method we wish to test the output of, we can call upon that method using this function which also feeds the method the needed parameters (arguments). Similarly to the &lt;code&gt;setAccessible()&lt;/code&gt; we chain it on and it expects two arguments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The object to invoke upon. (null can be used here in the case of static methods)&lt;/li&gt;
&lt;li&gt;An array of arguments that the method to be invoked expects.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
        &lt;span class="nv"&gt;$exampleClass&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;ExampleClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$reflection&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;ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exampleClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflection&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exampleMethod'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAccessible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;invokeArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exampleClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$arg2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="c1"&gt;// Make assertions against the resulting output like...&lt;/span&gt;
        &lt;span class="c1"&gt;// $this-&amp;gt;assertEquals('expected result', $result);&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run your tests
&lt;/h2&gt;

&lt;p&gt;That's it! After just a few extra lines of code, you are now able to make assertions in your PHPUnit test suites against otherwise inaccessible functions and you can sleep a little easier tonight knowing that the deepest trenches of your application are fully covered and there will not be any unwelcome bugs!&lt;/p&gt;

&lt;p&gt;... at least not from the parts you wrote proper tests for.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>laravel</category>
      <category>testing</category>
    </item>
    <item>
      <title>How to fix Undefined type 'Spatie\Permission\Models\' . 'Permission' | 'Role' | 'HasRoles'</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Thu, 13 Apr 2023 21:53:41 +0000</pubDate>
      <link>https://dev.to/mizouzie/undefined-type-spatiepermissionmodels-permission-role-hasroles-5bee</link>
      <guid>https://dev.to/mizouzie/undefined-type-spatiepermissionmodels-permission-role-hasroles-5bee</guid>
      <description>&lt;p&gt;VSCode with intelephense throws a strange and hard to debug error when using the spatie/laravel-permissions package even when you follow the docs to the letter. Here is how to fix it.&lt;/p&gt;

&lt;p&gt;I was very frustrated for more than a few minutes with this after installing the great &lt;a href="https://spatie.be/docs/laravel-permission/v5/introduction" rel="noopener noreferrer"&gt;Spatie package for permissions&lt;/a&gt; in a project I am working on that requires teams, roles and permissions. Click the link above to check out the documentation and you'll see immediately the appeal it has for any Laravel developer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sidenote: These guys really do churn out an ever growing collection of the most helpful packages that will save you hours of thinking and development, so if you don't know about them... &lt;strong&gt;get to know!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Error
&lt;/h3&gt;

&lt;p&gt;The error itself is the VSCode extension &lt;a href="https://intelephense.com/" rel="noopener noreferrer"&gt;Intelephense&lt;/a&gt;, that is usually very helpful when writing PHP in VSCode, telling you that there is an error with an &lt;code&gt;Undefined type ...&lt;/code&gt; after you have followed the steps &lt;a href="https://spatie.be/docs/laravel-permission/v5/installation-laravel" rel="noopener noreferrer"&gt;outlined here in detail&lt;/a&gt; to install the permissions package on your Laravel app.&lt;/p&gt;

&lt;p&gt;We have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Used composer to pull in the package&lt;/li&gt;
&lt;li&gt;Manually registered the service provider&lt;/li&gt;
&lt;li&gt;Published migration and configuration files&lt;/li&gt;
&lt;li&gt;Adjusted to allow for teams&lt;/li&gt;
&lt;li&gt;Cleared the configuration cache&lt;/li&gt;
&lt;li&gt;Run the migrations&lt;/li&gt;
&lt;li&gt;Added the trait to out &lt;code&gt;User&lt;/code&gt; model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;And BOOM!&lt;/strong&gt;... error.&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%2F8spb6w1uspnfgep008qj.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%2F8spb6w1uspnfgep008qj.png" alt="Y THO" width="600" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tried &lt;code&gt;composer dump-autoload&lt;/code&gt;, &lt;code&gt;./artisan config:clear&lt;/code&gt; (again), &lt;code&gt;./artisan config:optimize&lt;/code&gt;, all to no avail. Double checked I had followed all the steps... I had. So??&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;The short answer is, there is no reason. But here is the solution. Just reload the window.&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="nc"&gt;Ctrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Shift&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;P&lt;/span&gt; &lt;span class="c1"&gt;// To open the editor commands&lt;/span&gt;

&lt;span class="c1"&gt;// then type in or scroll down and select...&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;Developer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;Reload&lt;/span&gt; &lt;span class="nc"&gt;Window&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a simple as that. How annoying.&lt;/p&gt;

&lt;h3&gt;
  
  
  Credit
&lt;/h3&gt;

&lt;p&gt;I need to shoutout &lt;a href="https://github.com/akshayknz" rel="noopener noreferrer"&gt;Akshay K Nair&lt;/a&gt; for replying somewhere deep in a github issue and pointing me to this. I just hope that someone else finds this a lot easier than I did!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>laravel</category>
      <category>php</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Space is the Place: Reasons to explore Twitter Spaces</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Tue, 28 Mar 2023 23:00:13 +0000</pubDate>
      <link>https://dev.to/mizouzie/space-is-the-place-reasons-to-explore-twitter-spaces-4pjn</link>
      <guid>https://dev.to/mizouzie/space-is-the-place-reasons-to-explore-twitter-spaces-4pjn</guid>
      <description>&lt;p&gt;Space! The Final Frontier... but what if it is the beginning? Twitter spaces are a great way to meet and trade ideas with people from across the globe from the comfort of your sofa!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Spaces?
&lt;/h2&gt;

&lt;p&gt;Since the end of 2020, Twitter Spaces have been a feature of the social media platform, and while they've seen great popularity in some cases, some Tweeple may still not be making the most of the multitude of opportunities they can present.&lt;/p&gt;

&lt;p&gt;The easiest way to describe them is to liken them to a hybrid of a public speaking forum at an international airport lounge in the guise of a podcast.&lt;/p&gt;

&lt;h3&gt;
  
  
  How they work
&lt;/h3&gt;

&lt;p&gt;A Space requires only one participant to exist, the &lt;em&gt;Host&lt;/em&gt;, but the real magic happens when the host is joined by others in the form of &lt;em&gt;Speakers&lt;/em&gt; and &lt;em&gt;Listeners&lt;/em&gt;. The Space is given a title by the host that launched it and that will generally give an idea of the type of conversation that will be held between the host and speakers. The title is also what is displayed along with the names of the host and speakers in the &lt;code&gt;Spaces&lt;/code&gt; section of Twitter so that potential participants can choose from the list of ongoing and upcoming talks.&lt;/p&gt;

&lt;h4&gt;
  
  
  Listening
&lt;/h4&gt;

&lt;p&gt;To listen, any user only needs to tap on a Space that tickles their fancy. This will open up a slightly larger tab showing more details of the Space and the current speakers and listener count. There you tap the &lt;code&gt;Start Listening&lt;/code&gt; button to enter the Space and start streaming the audio from the room on your device.&lt;/p&gt;

&lt;p&gt;A listener is not restricted to zero input either. They have to ability to show animated emojis over their avatar should they wish to react to what they are hearing. It will show up for all users in the space, regardless of position.&lt;/p&gt;

&lt;h4&gt;
  
  
  Speaking
&lt;/h4&gt;

&lt;p&gt;To speak, a user that is already a participant in the Space can tap on the microphone icon in the bottom left corner to &lt;code&gt;Request to Speak&lt;/code&gt;. This will send a notification to the Host/Co-hosts who will then be able to allow or deny your request to "join the stage". Once on stage, the microphone icon becomes the control to toggle your device microphone on and off so that you can actually speak in the Space and be heard by all.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is a good idea to make use of the &lt;code&gt;raised hand&lt;/code&gt; emoji in the reactions panel when you are a speaker and await your turn to speak, normally granted by the host of the Space.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Hosting
&lt;/h4&gt;

&lt;p&gt;To host is to be the user that launched the Space in the first place. As host you pick the title, assign co-host and speaker status and generally oversee proceedings. Different people have different styles, so I would definitely recommend mixing it up a bit in other people's Spaces to get a feel for how to manage a Space well (or not so well).&lt;/p&gt;

&lt;p&gt;At the end of the day, you're the boss in your own Space, so do what you see fit to keep the conversation flowing and let the value flow from exchanges between all participants.&lt;/p&gt;

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

&lt;p&gt;Humans are social creatures and we thrive from interacting with one another. The benefits of getting involved in conversations with other people are endless, but here I will try to give you the &lt;strong&gt;best&lt;/strong&gt; reasons that I think you should grab the mic soon if you haven't already.&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%2F4c8u7gyuy0ysnfwgta2a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4c8u7gyuy0ysnfwgta2a.jpg" alt="Grab the mic!" width="600" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning
&lt;/h3&gt;

&lt;p&gt;My &lt;strong&gt;number 1&lt;/strong&gt; takeaway from the numerous Spaces that I have attended was learning. I learned a lot. I tend to get involved with Tech-Twitter Spaces and I have to say that my software development acumen has improved for it. Sitting back and soaking up knowledge by just eavesdropping on the convo between individuals held in high regard in their field alone has been like attending a mini university, but also getting involved and seizing the opportunity to actually &lt;strong&gt;ask&lt;/strong&gt; those people questions that are relevant to my situation has been of unimaginable value.&lt;/p&gt;

&lt;h4&gt;
  
  
  Variety of Thought
&lt;/h4&gt;

&lt;p&gt;My personal favourite feeling is when I think I know something, and then someone shows me a new angle on it and I feel like I've had the blinders taken off. Entering Spaces gives you the opportunity to meet people that share some huge similarities to yourself that also come from totally different walks of life. Exposure to new perspectives is what truly drives a deeper understanding, no matter the subject.&lt;/p&gt;

&lt;h4&gt;
  
  
  Building Ideas
&lt;/h4&gt;

&lt;p&gt;A healthy, back-and-forth style conversation that builds on the similarities and differences of view on a topic can lead to amazing realisations for both those &lt;strong&gt;in&lt;/strong&gt; the conversation and even those just listening. The way conversations can flow from one topic and sub-topic to another leads to connections being made that any one individual might not make by themselves.&lt;/p&gt;

&lt;p&gt;I love this because I am the type to &lt;em&gt;obsess&lt;/em&gt; over something when I want to learn it and listening to knowledgeable people discuss an idea has often exposed every conceivable corner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Speaking Practice
&lt;/h3&gt;

&lt;p&gt;Many of us wish to advance our career also. That's very normal. A lot of higher stations require some form of team management and that means you need to be proficient in speaking to more than a few people at once.&lt;/p&gt;

&lt;p&gt;That is daunting. More so if you have never done it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conquering Fears
&lt;/h4&gt;

&lt;p&gt;Spaces more often than not are actually &lt;strong&gt;Safe Spaces&lt;/strong&gt;, run by compassionate people.&lt;/p&gt;

&lt;p&gt;Think about it. The people organising and speaking on these are giving up their time to give back to a community in some way. Each of these people have been a beginner at something at some point, they know how it can feel. I have always, &lt;em&gt;always&lt;/em&gt;, &lt;strong&gt;always&lt;/strong&gt; only ever seen hosts and co-hosts giving encouragement, time and (not a pun) space for a first time speaker to come onto the stage and address the audience in the room.&lt;/p&gt;

&lt;h4&gt;
  
  
  Immediate Feedback
&lt;/h4&gt;

&lt;p&gt;If you are lucky enough to join one of the Spaces actually geared toward getting first-timers up to speak and introduce themselves, you may even get some immediate feedback on how you did that you can take away, think about and try to apply the next time you are up. If you are here from Tech-Twitter then you know about taking an iterative approach, and all iterations must start somewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking
&lt;/h3&gt;

&lt;p&gt;Spaces are all about people talking to people. They are the definition of networking &lt;strong&gt;on&lt;/strong&gt; a social network. Double network!&lt;/p&gt;

&lt;h4&gt;
  
  
  Professional
&lt;/h4&gt;

&lt;p&gt;A number of Spaces exist to not only get first-timers to pop their Space-Cherry, but to make themselves known to those that may be looking to connect with other developers. Some Spaces have gained a good reputation for this and getting up and introducing yourself has the potential to be as valuable as getting that golden opportunity of an elevator pitch with the CEO of that company you dream of working at.&lt;/p&gt;

&lt;h4&gt;
  
  
  Casual
&lt;/h4&gt;

&lt;p&gt;Not all Spaces are mega-super-serious. Some are just for fun or just a little more of a casual style. If you show up consistently because you gel with a particular group that also show up consistently... well, you're very likely to become friends. On a site like Twitter that can only work in your favour, thanks to the algorithm noticing your relationships, you'll all be shown each other's content more often and be very likely to engage making each of you score a little higher on the Twit-o-meter. Fantastic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entertainment
&lt;/h3&gt;

&lt;p&gt;Topics covered in spaces range from zero to absolutely everything. All kinds of things are discussed and go on in them and sometimes you'll find them as engrossing as your favourite podcasts. I dare even say you might forget about your podcasts all together in favour of the live-action versions going on every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;I have paid attention to spaces for a few months now, and I see so many improvements in my technical understanding with my work and so many improvements with how I use Twitter. I have listened to and even been a part of some amazing discussions and learnt what would have taken me a year of solid reading to learn in a matter of weeks.&lt;/p&gt;

&lt;p&gt;I see them as having huge value, especially when you compare joining a Twitter Space to, say, Netflix binging. It's the same vibe if not more fun, but the benefits are tangible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who to Watch out for
&lt;/h3&gt;

&lt;p&gt;I have a list of Twitter folks that will always draw me into a Space if I see their name on the roster, and I'd like to share them with you because they're ultimately the reasons for me getting all these good things out of this feature.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/AxelGarciaK" rel="noopener noreferrer"&gt;@AxelGarciaK&lt;/a&gt; and &lt;a href="https://twitter.com/hiro_codes" rel="noopener noreferrer"&gt;@hiro_codes&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;These guys are always involved in great Spaces on topics like &lt;strong&gt;Real Programming&lt;/strong&gt; (languages like C, Rust and Go), AI and making the most out of Twitter. I've gained tonnes of value from them and look forward to learning more from them.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://twitter.com/GrahamTheDev" rel="noopener noreferrer"&gt;@GrahamTheDev&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;This guy defines Dev Rel. Highly experienced, excellent succinct advice. Always around and open to questions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://twitter.com/ShawnBasquiat" rel="noopener noreferrer"&gt;@ShawnBasquiat&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;The host of one of the most valuable regular spaces in Tech-Twitter. Endlessly supportive. If you are gonna start somewhere, Shawn's "THE HUNT" Space is where it should be.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Of course, there are so, so many but I'd squash all the fun of exploration for you if I told you who else I enjoy talking with in these places! Obviously you should follow me too, &lt;a href="https://twitter.com/mizouzie" rel="noopener noreferrer"&gt;@mizouzie&lt;/a&gt;, and join any Space you see me in and get involved. You &lt;strong&gt;will not&lt;/strong&gt; regret it!&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%2Fmxjeloah4vjravd9g4wm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxjeloah4vjravd9g4wm.jpg" alt="podcast equipment" width="760" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>twitter</category>
      <category>beginners</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>3 things the best senior developers do</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Sat, 25 Mar 2023 00:03:39 +0000</pubDate>
      <link>https://dev.to/mizouzie/3-things-the-best-senior-developers-do-3ain</link>
      <guid>https://dev.to/mizouzie/3-things-the-best-senior-developers-do-3ain</guid>
      <description>&lt;p&gt;Working under the care of a more experienced developer can make or break a junior developer's career. Here are 3 things the best senior developers do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Senior Developers
&lt;/h2&gt;

&lt;p&gt;A senior developer has earned that title. They've waged wars and won, faced long days and nights, overcome the most obscure of obstacles. Now, for all their troubles they have to deal with you. Wet behind the ears and a danger if left unmonitored. Hardly seems fair, does it?&lt;/p&gt;

&lt;p&gt;This is the curse of such a vast wealth of knowledge. They've built up so much over the years they can't possibly apply it all at the same time. They &lt;strong&gt;must&lt;/strong&gt; delegate to be efficient. How do they choose what to pass down the line and to whom? Well that's all part of their new challenge.&lt;/p&gt;

&lt;p&gt;I've had some time now as a junior developer and I have been lucky enough to be under the care of a couple of seniors who have made my experience a very pleasant one, considering the mountain of varying knowledge I have acquired in such a short time. I want to point out the characteristics they display that I admire most and deeply appreciate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential traits
&lt;/h2&gt;

&lt;p&gt;Given that the responsibility of overseeing a project or even multiple projects is a stressful one, it is crazy to think that the senior developers of the tech industry &lt;em&gt;also&lt;/em&gt; have to essentially baby-sit at the same time. A lot can go wrong even before they have to throw inexperienced developers into the mix. 3 of the &lt;strong&gt;most important traits&lt;/strong&gt; for a successful senior developer to posses, in my opinion, are;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attentiveness&lt;/li&gt;
&lt;li&gt;Patience&lt;/li&gt;
&lt;li&gt;Optimism&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me explain to &lt;strong&gt;you&lt;/strong&gt;, who like me, is the junior developer in this arrangement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attentive
&lt;/h3&gt;

&lt;p&gt;I don't mean they need to be all lovey-dovey and sweep your hair out of you eyes when you talk, I mean they need to pay attention even when it's from afar. They need to have a good gauge of how you are feeling both in regard to your workload and in life in general. Not necessarily all the details of your every move, but are you happy? &lt;/p&gt;

&lt;p&gt;The reason for this is that if you're not happy, you won't produce good work which means more work down the line because the code you commit is not good enough or within the deadlines. Simply checking in with you daily is all a good senior will do, but a great senior will take action when needed as they have the experience to be able to do so effectively.&lt;/p&gt;

&lt;p&gt;The action does not have to be some grand gesture, sometimes just a few words of guidance or a "don't worry, I still have days like that" go a very long way in helping an overwhelmed junior developer get a handle on things.&lt;/p&gt;

&lt;h3&gt;
  
  
  Patient
&lt;/h3&gt;

&lt;p&gt;Often the team's senior developer is the one that is really face to face with the deadlines. They see the whole project in the "big picture" sense so will also forsee the knock-on effects of a missed deadline before anyone else. Despite this burden, the best senior developers are able to balance the pressure while displaying great patience with their team, affording them the time needed to discover solutions in their own ways and therefore build themselves into stronger developers in the process. It is an investment that will only pay dividends in the future, but of course, our highly esteemed senior knows that already.&lt;/p&gt;

&lt;p&gt;A part of this patience is the ability to block the rage and fury of the dreaded (and often agitated) client. They soak up the barrage of questions like "well, why isn't it done yet?" so that those in their care can keep a clear head and just focus on the task before them. They know that once deployment and delivery is accomplished, all that negative energy will evaporate anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimistic
&lt;/h3&gt;

&lt;p&gt;It is important to understand that this does not mean &lt;em&gt;naive&lt;/em&gt; optimism. Programming requires an air of pragmatism, and years of thinking like that will lead to a senior developer being so inclined. The optimism I mean is a type of faith. Faith in their juniors to overcome the obstacles they need to, faith that they will ask if they really do get stuck and faith in their own abilities to provide the necessary learning resources and road maps to becoming a capable developer.&lt;/p&gt;

&lt;p&gt;It is a type of self control that a father displays when their child first rides a bicycle without stabilizers. As much as they want to step in a protect, they know they must leave the space to fail in order for the kid to grow, to get stronger, better, to develop. They know if they can just hold off, it will pay off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some examples
&lt;/h2&gt;

&lt;p&gt;I've had a terrible week this past week after having a project I delivered utterly trashed by the client and had to take it almost right back to the drawing board and implement a bunch of (front end) stuff that I am very unfamiliar and very &lt;strong&gt;very&lt;/strong&gt; uncomfortable with. I wasted an entire week, if not more, trying out various JavaScript libraries to get an input form to perform more tricks than a circus and was  seriously losing my mind over it. I couldn't believe it was taking so long &lt;strong&gt;and&lt;/strong&gt; just not progressing as well.&lt;/p&gt;

&lt;p&gt;I was angry. At both the situation and myself. My senior dev, however;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;never swept in and bossed me around&lt;/li&gt;
&lt;li&gt;never complained about the amount of time I wasted&lt;/li&gt;
&lt;li&gt;checked in with me regularly&lt;/li&gt;
&lt;li&gt;afforded me the time to explore so many options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As if that wasn't enough, after about a week and without me even realising, he threw me a totally different small project that was in PHP which I am far more proficient in. I knocked that out in an afternoon, so he fed me a bonus task of dockerizing the application which I also managed relatively quickly. Two things, that if compared side by side with what I was so stuck on, would probably be considered slightly more advanced. It was definitely a morale boost. &lt;/p&gt;

&lt;p&gt;The next day, same project and this time just looking into refactoring some SQL queries (which is a favourite of mine) and &lt;em&gt;that&lt;/em&gt; had me feeling like bullets would bounce off me. I went back to the JavaScript that was torturing me, deleted the entire branch I'd spent a week tied up in and banged out a perfectly fine working solution in a couple of hours. Thanks to the previous day's distraction techniques, I didn't get hung up on the wasted time too!&lt;/p&gt;

&lt;p&gt;Thanks to my senior's attention, patience and faith in me I managed to eventually overcome something that I clearly wasn't able to do a week ago, plus I have gained the experience that will hopefully help me avoid getting so caught up in a problem in the future.&lt;/p&gt;

&lt;p&gt;I'm grateful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Created Environment
&lt;/h2&gt;

&lt;p&gt;You can see from just that one recent example that you have every right to be jealous of my working environment because my goodness, it is nurturing. Thanks to having this sort of support for the last 2 years, I can confidently say that I am more able as a developer than I should be for the number of years I have had in the industry. I have justifiable confidence because I have worked on real software used by some huge companies because I was not only taught the right stuff but given the opportunity to &lt;em&gt;use&lt;/em&gt; that knowledge to build something that is a part of something of real significance.&lt;/p&gt;

&lt;p&gt;I look forward to working every day because it is always challenging but never frightening and because I can look back at what I've made and been a part of with pride. It is a great team to be a part of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;I won't repeat that I've gained a huge amount of experience in a short time... but I really have. Not only that, though, I really believe that the future of the group I am a part of will be a great one because the next wave of junior developers after me are in for a solid support system and incredible guidance. This team has already achieved some great feats while getting little old me up to speed, so I can only see exponential success on the horizon.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>mentalhealth</category>
    </item>
    <item>
      <title>How to Unlock Formkit Multistep forms on a Laravel Inertia app with Vue 3</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Thu, 09 Mar 2023 23:54:31 +0000</pubDate>
      <link>https://dev.to/mizouzie/how-to-unlock-formkit-multistep-forms-on-a-laravel-inertia-app-with-vue-3-2m7o</link>
      <guid>https://dev.to/mizouzie/how-to-unlock-formkit-multistep-forms-on-a-laravel-inertia-app-with-vue-3-2m7o</guid>
      <description>&lt;p&gt;Formkit offers a great Multi-Step tool for building forms in your Vue app, but getting it to work inside a Laravel Inertia app is a little tricky. Here is how to get it running.&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%2Fi.vimeocdn.com%2Fvideo%2F1552229243-924c5e15957c2a63437131b1f6dd4910090c286c101ac2b8d19b5e1c46eec4b3-d_1280x720%3Fr%3Dpad" 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%2Fi.vimeocdn.com%2Fvideo%2F1552229243-924c5e15957c2a63437131b1f6dd4910090c286c101ac2b8d19b5e1c46eec4b3-d_1280x720%3Fr%3Dpad" alt="Formkit logo from Vue School" width="1280" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Formkit is a supercharger for developing applications on the already turbo platform of Laravel Inertia with Vue 3. It is a library of ready made components for building forms that make it very easy to construct any kind of form for retrieving user input. One of the features of this library that stood out the most for me was the &lt;code&gt;Multi-Step&lt;/code&gt; forms. &lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Step Forms
&lt;/h2&gt;

&lt;p&gt;So what is a multi-step form?&lt;/p&gt;

&lt;p&gt;It is a format that breaks the usual monotony of filling out a form for the user. It splits the form into smaller form-lets that helps to give a much nicer UX because they're not faced with such a huge list of questions all at once. The multi-step form can be split and navigated by tabs or a progress-map that resembles a London Underground map 😍&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%2Fygil658objkjh44wbjao.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%2Fygil658objkjh44wbjao.png" alt="An example of Formkit Multi-Step" width="521" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So as developers, we want to provide this kind of experience for our application users. Formkit is a very well provided for library with extensive documentation for it's implementation into a standard Vue 3 project, but when I tried to put it into a Laravel Inertia app &lt;em&gt;using&lt;/em&gt; Vue 3, it needed a little thinking outside of the dox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Formkit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What do the docs say?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://formkit.com/getting-started/installation#with-vue" rel="noopener noreferrer"&gt;Here you can check the Vue specific docs&lt;/a&gt; for the initial Formkit installation. They are nice and straightforward, but following these to the letter does not give us the desired result.&lt;/p&gt;

&lt;p&gt;We will install with npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @formkit/vue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The slight difference for Inertia
&lt;/h3&gt;

&lt;p&gt;Now to get it working in our case, we need to have our &lt;code&gt;app.js&lt;/code&gt; looking like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../css/app.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createInertiaApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolvePageComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;laravel-vite-plugin/inertia-helpers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ZiggyVue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../vendor/tightenco/ziggy/dist/vue.m&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;formkitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Laravel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;createInertiaApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&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;resolvePageComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`./Pages/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.vue`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Pages/**/*.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;plugin&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="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&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;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&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="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ZiggyVue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Ziggy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formkitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#4B5563&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The slight tweaks are evident on the &lt;code&gt;import&lt;/code&gt; and then that same tweak is repeated inside the &lt;code&gt;use()&lt;/code&gt; before the app is mounted.&lt;/p&gt;

&lt;p&gt;As we need to import "plugin" from formkit and we already &lt;em&gt;have&lt;/em&gt; a "plugin" named in our &lt;code&gt;setup()&lt;/code&gt; function, it is necessary to give the Formkit imported "plugin" an alias. Then later down the chain of &lt;code&gt;use()&lt;/code&gt;'s, we can provide that alias.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Multi-Step addon
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What do the docs say?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://formkit.com/plugins/multi-step#installation" rel="noopener noreferrer"&gt;Here you can check the official docs&lt;/a&gt; for installing the Multi-Step addon for Formkit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: It suggests the use of a &lt;code&gt;formkit.config.js&lt;/code&gt; file, which is fine if you're just using Vue... but we're not!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One other thing to note, is that it's not &lt;strong&gt;very&lt;/strong&gt; obvious that you actually need to install this separately with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @formkit/addons
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The slight difference for Inertia
&lt;/h3&gt;

&lt;p&gt;As you may have noticed, we've seen a part of that before. The importing &lt;code&gt;defaultConfig&lt;/code&gt; was in our first setup. We will use that to our advantage and do so inline stuff to get where we want to be.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../css/app.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/addons/css/multistep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createInertiaApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolvePageComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;laravel-vite-plugin/inertia-helpers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ZiggyVue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../vendor/tightenco/ziggy/dist/vue.m&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;formkitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMultiStepPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/addons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Laravel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;createInertiaApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&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;resolvePageComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`./Pages/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.vue`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Pages/**/*.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;plugin&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="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&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;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&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="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ZiggyVue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Ziggy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formkitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;createMultiStepPlugin&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="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#4B5563&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we've added;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a CSS import&lt;/li&gt;
&lt;li&gt;an addon module import&lt;/li&gt;
&lt;li&gt;that extra module &lt;em&gt;inside&lt;/em&gt; the previously added &lt;code&gt;defaultConfig&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using Formkit
&lt;/h2&gt;

&lt;p&gt;Now that it is setup, we are free to use the super speedy form building tool to it's fullest potential, stacking form sections in beautiful multi-step glory. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PrimaryButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/Components/PrimaryButton.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SecondaryButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/Components/SecondaryButton.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;clearForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your clear form handler&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submitForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your submit handler&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;multi-step&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;step&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;csv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spreadsheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.xls,.xlsx,.csv,.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Upload a csv, xls or xlsx file.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;When&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;csv&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;uploaded&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;we&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;heading&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="nx"&gt;so&lt;/span&gt; &lt;span class="nx"&gt;that&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;choose&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt;
                    &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;which&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt; &lt;span class="nx"&gt;contain&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormKit&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;step&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;columns&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Columns&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormKit&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;step&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rows&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rows&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormKit&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;step&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;maxLength&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Max Length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;500&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormKit&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormKit&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;step&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SecondaryButton&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clearForm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Cancel&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SecondaryButton&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PrimaryButton&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submitForm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Submit&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/PrimaryButton&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormKit&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormKit&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormKit&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the full documentation on actually &lt;em&gt;using&lt;/em&gt; Formkit (now that it's working 😉) &lt;a href="https://formkit.com/plugins/multi-step#usage" rel="noopener noreferrer"&gt;click here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy Form-Building!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>laravel</category>
      <category>vue</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Common Function Comparisons in PHP</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Tue, 07 Mar 2023 13:00:00 +0000</pubDate>
      <link>https://dev.to/mizouzie/common-function-comparisons-in-php-1jja</link>
      <guid>https://dev.to/mizouzie/common-function-comparisons-in-php-1jja</guid>
      <description>&lt;p&gt;How do you decide between two functions that, at a glance, seem to do the same thing? Let's pick apart the differences to try and make it easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Functions
&lt;/h2&gt;

&lt;p&gt;PHP is an arsenal of tools that can process data in a multitude of ways. This is one of the reasons that it powers ~75% of website server-side code. It is fast, has huge support and scales very well.&lt;/p&gt;

&lt;p&gt;If you were to investigate how many core functions PHP has on v8.1.2 you would find:&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="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$funcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; get_defined_functions&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
     &lt;span class="s2"&gt;"internal"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
       &lt;span class="s2"&gt;"zend_version"&lt;/span&gt;,
       &lt;span class="s2"&gt;"func_num_args"&lt;/span&gt;,
       &lt;span class="s2"&gt;"func_get_arg"&lt;/span&gt;,
       &lt;span class="s2"&gt;"func_get_args"&lt;/span&gt;,
       &lt;span class="s2"&gt;"strlen"&lt;/span&gt;,
       &lt;span class="s2"&gt;"strcmp"&lt;/span&gt;,
       &lt;span class="s2"&gt;"strncmp"&lt;/span&gt;,
       &lt;span class="s2"&gt;"strcasecmp"&lt;/span&gt;,
       &lt;span class="s2"&gt;"strncasecmp"&lt;/span&gt;,
       &lt;span class="s2"&gt;"error_reporting"&lt;/span&gt;,
       &lt;span class="s2"&gt;"define"&lt;/span&gt;,
       &lt;span class="s2"&gt;"defined"&lt;/span&gt;,
       &lt;span class="s2"&gt;"get_class"&lt;/span&gt;,
       &lt;span class="s2"&gt;"get_called_class"&lt;/span&gt;,
       &lt;span class="s2"&gt;"get_parent_class"&lt;/span&gt;,
       &lt;span class="s2"&gt;"is_subclass_of"&lt;/span&gt;,
       &lt;span class="s2"&gt;"is_a"&lt;/span&gt;,
       &lt;span class="s2"&gt;"get_class_vars"&lt;/span&gt;,
       &lt;span class="s2"&gt;"get_object_vars"&lt;/span&gt;,
       &lt;span class="s2"&gt;"get_mangled_object_vars"&lt;/span&gt;,
       &lt;span class="s2"&gt;"get_class_methods"&lt;/span&gt;,
:

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;count&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$funcs&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'internal'&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 1735
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a small amount by any means, so it is impossible to know them all. Even the most experienced PHP developers will regularly refer to &lt;a href="https://www.php.net/" rel="noopener noreferrer"&gt;php.net&lt;/a&gt; to look up which they can use for what.&lt;/p&gt;

&lt;p&gt;With 1735 functions being available, surely some must overlap or be similar. In this discussion we will look at the ones that seem like they could be the same thing and see if we can decide best use cases for each.&lt;/p&gt;

&lt;h3&gt;
  
  
  Most commonly used
&lt;/h3&gt;

&lt;p&gt;Looking through &lt;a href="https://www.exakat.io/en/the-100-php-functions-in-2022/" rel="noopener noreferrer"&gt;Exakat&lt;/a&gt;'s &lt;em&gt;top 100 php functions 2022&lt;/em&gt;, we can see a few likely candidates to choose from. Lets take:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.php.net/manual/en/function.implode" rel="noopener noreferrer"&gt;implode()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.php.net/manual/en/function.count" rel="noopener noreferrer"&gt;count()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.php.net/manual/en/function.explode" rel="noopener noreferrer"&gt;explode()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.php.net/manual/en/function.trim" rel="noopener noreferrer"&gt;trim()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.php.net/manual/en/function.strtr" rel="noopener noreferrer"&gt;strtr()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;sup&gt;click on any to see the official definitions&lt;sup&gt;&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Compared to their closest cousins
&lt;/h2&gt;

&lt;h3&gt;
  
  
  implode() vs join()
&lt;/h3&gt;

&lt;p&gt;Join is actually just an alias, so they're exactly the same. Implode works like running:&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;implode&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;$separator&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;$arr&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="nv"&gt;$imploded&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="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$arr&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="nv"&gt;$imploded&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$separator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="nv"&gt;$imploded&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&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;return&lt;/span&gt; &lt;span class="nv"&gt;$imploded&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;Going through the steps above, it does something along the lines of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initiate an empty string variable as &lt;code&gt;$imploded&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Loop through the input array&lt;/li&gt;
&lt;li&gt;If the element of the array is at index 0, &lt;strong&gt;do not&lt;/strong&gt; concatenate the separator to &lt;code&gt;$imploded&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Otherwise concatenate given separator string&lt;/li&gt;
&lt;li&gt;Concatenate element to &lt;code&gt;$imploded&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Repeat until all elements of array have been cycled&lt;/li&gt;
&lt;li&gt;Return fully constructed string &lt;code&gt;$imploded&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  count() vs if (!count()) {}
&lt;/h3&gt;

&lt;p&gt;This function has such high popularity due to it being used commonly for frontend "decision making". When choosing whether or not to display a particular component depending on there being any instances of something in the backend database, developers will call count() on a parameter passed to the view being displayed. The idea is that if it returns a "truthy" value, as in &lt;strong&gt;not&lt;/strong&gt; 0, then it confirms the existence of at least one instance that parameter in the database.&lt;/p&gt;

&lt;p&gt;This can be fine for a single call and if there is not an enormous number of instances of that parameter. Often though, there will be a large number of conditional components which means multiple calls to count() which ends up counting an enormous amount of your database. This is not ideal for UX as it can make the page load excruciatingly slowly. There is a simple optimization demonstrated below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;// Rather than calling count() on everything like so...
&lt;span class="cp"&gt;&amp;lt;?php&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;$param&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Show this example HTML component!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Show alternate HTML or Nothing 🤷&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;

// ...we can check NOT == 0 like this instead
&lt;span class="cp"&gt;&amp;lt;?php&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="nv"&gt;$param&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Show alternate HTML or Nothing 🤷&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Show this example HTML component!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The optimized second option flips the original and checks only for a &lt;strong&gt;non-falsey&lt;/strong&gt; value which is satisfied by the very first counter beyond 0. After that first 1 is counted, the rest of the code can move on and display the non-existent case or the existent case accordingly. We are effectively only "counting" a maximum of the number of calls to count as opposed to counting the number of calls to count &lt;strong&gt;multiplied&lt;/strong&gt; by the number of instances of the counted records in the database. That time can add up! Count one or zero and move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  explode() vs str_split() vs str_tok()
&lt;/h3&gt;

&lt;p&gt;These functions are all about creating an iterable out of a given string, each splitting the string at a chosen point. The way that point is chosen differs depending on which function is called.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;explode()&lt;/code&gt; searched through the string for a given sub-string and splits around that&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;str_split()&lt;/code&gt; simply counts out the specified number of bytes (i.e. characters in the ASCII set) and divides the string there, then starts counting again from the split to find the next split location.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;str_tok()&lt;/code&gt; the same as explode() but does not return the whole split up string at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two will return an array of the "pieces" of strings they have cut. This is handy when you need to derive a string from a url string, for example you can call:&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="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://mizouzie.dev/articles/that/help/developers/learn"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"https://mizouzie.dev/articles/that/help/developers/learn"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;explode&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="nv"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
     &lt;span class="s2"&gt;"https:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;"mizouzie.dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;"articles"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;"that"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;"developers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;"learn"&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;While with str_split() you will give an integer value (n) and it splits the string after each nth character.&lt;/p&gt;

&lt;p&gt;The function str_tok() is the outlier here as it only returns the first section (or token, as the name suggests) on it's first call. The interesting thing is that it will return the &lt;strong&gt;next&lt;/strong&gt; section on the next call, and the next one only on the next call after that and so on until it has none left to return and returns &lt;code&gt;false&lt;/code&gt;. This makes it ideal for use within a loop, as the returning of a falsey value will break out of the loop. It just removes the step of &lt;em&gt;creating&lt;/em&gt; the iterable array to &lt;em&gt;then&lt;/em&gt; do something with it. You can just get right down to business with this one.&lt;/p&gt;

&lt;h3&gt;
  
  
  trim() vs ltrim() vs rtrim() vs preg_replace()
&lt;/h3&gt;

&lt;p&gt;Trimming strings is a common necessity as many strings have invisible and undesirable baggage in the form of whitespace either lurking before or behind them. A string ending in a &lt;em&gt;new line&lt;/em&gt; or &lt;em&gt;carriage return&lt;/em&gt; character can wreak havoc on simple processing functions or scripts, so it is always wise to sanitize them with some sort of trim at the very least.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;trim()&lt;/code&gt; indiscriminately removes whitespace from in front and behind a string&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ltrim()&lt;/code&gt; &amp;amp; &lt;code&gt;rtirm()&lt;/code&gt; remove whitespace from the left and right of a string respectively&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;preg_replace()&lt;/code&gt; requires a little knowhow of the dark-art of regular expressions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Should you be familiar or at least comfortable with regex, you may specify exactly what type of whitespace is removed, where it is removed from or even only remove it given certain conditions. It is like the super-max-pro Premium fully licensed version of the trimming functions before it, as well as much more.&lt;/p&gt;

&lt;h3&gt;
  
  
  strtr() vs str_replace()
&lt;/h3&gt;

&lt;p&gt;For me, these two do the same thing. Search a string for a given substring, and then return that string with the substring replaced with a given alternative substring. Both accept arguments as strings or arrays, but there is a slight difference in &lt;em&gt;how&lt;/em&gt; they accept the arrays.&lt;/p&gt;

&lt;p&gt;The arrays passed to str_replace() (notice the plural &lt;strong&gt;arrays&lt;/strong&gt;) will be one array of search values and a second array of the search value's replacements. The search values and replacements will need to match up according to index in order to be executed properly.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;single&lt;/strong&gt; array passed to strtr() feels like a shortcut as the index &lt;em&gt;is&lt;/em&gt; the search value and the value is the replacement. i.e. &lt;code&gt;['from this' =&amp;gt; 'to that']&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The usefulness of this is determined by how you go about construction your arrays to be passed. In many cases it may be easier or faster to construct a single array with string indexes. For me, that option just feels more sensible, less room for error.&lt;/p&gt;

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

&lt;p&gt;Now that we have looked at some of the most common similarities and differences, I hope you will consider yourself well armed and well informed on the great choice of incredibly powerful weapons at your disposal!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now go slay some data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylcjx4yqwp5o74q648bb.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%2Fylcjx4yqwp5o74q648bb.png" alt="choose your weapon" width="605" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>beginners</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>L.I.F.T - the anti-advice that could save you</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Mon, 27 Feb 2023 11:00:00 +0000</pubDate>
      <link>https://dev.to/mizouzie/lift-the-anti-advice-that-could-save-you-30dl</link>
      <guid>https://dev.to/mizouzie/lift-the-anti-advice-that-could-save-you-30dl</guid>
      <description>&lt;p&gt;It's not bad advice when I say Leave It For Tomorrow!&lt;/p&gt;

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

                            It 

                                    For 

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

&lt;/div&gt;

&lt;p&gt;Seemingly controversial advice to give, but hear me out.&lt;/p&gt;

&lt;p&gt;When coding, at least learning to code, you will not only find yourself facing brand new subject matter constantly, but often trying to implement that new thing at the same time. The code you write is always to solve a problem and there are always a multitude of ways to solve it. You'll have to choose which path you take according to other dependencies and the structure you're using. You'll need to think the desired process through and break it down into small enough steps before writing a single line. Sometimes you will require the help of an extra plugin or library and therefore you will need to understand how that works in itself so that you can use it effectively. Already we've faced more decisions than we can shake a stick at and we don't even have anything written to show for it.&lt;/p&gt;

&lt;p&gt;So you start to write. Already slightly strained in the mental sense, you hit a snag. The code doesn't seem to work the way you predicted. Frustration sets in a bit faster than usual and you go on a tangent to try and solve this unpredictable obstacle. 15 minutes you didn't have pass and you're back on track. Another snag...&lt;/p&gt;

&lt;p&gt;Rinse and repeat.&lt;/p&gt;

&lt;p&gt;This is the nature of web development.&lt;/p&gt;

&lt;p&gt;Collins dictionary defines development as:&lt;br&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%2Ft9zk3s947sjgo6oe143z.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%2Ft9zk3s947sjgo6oe143z.png" alt="Collins dictionary definition of development" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Number 3 is my favourite. Making a basic design &lt;strong&gt;gradually&lt;/strong&gt; better. And it is just that when you're starting out, gradual. This is why I say that it is not actually a bad thing to leave it for tomorrow. The process described above is mentally exhausting. The normal urge is to stick at it until the problem is resolved, but the problem is often rather more difficult to resolve than predicted. Do what you can, do not exhaust yourself, come back to it tomorrow.&lt;/p&gt;

&lt;p&gt;There is a strange thing that happens when you exercise this approach. When you look upon the same project that stumped you the day before with fresh eyes, it somehow becomes much more simple and easy to overcome. Your subconscious has worked on it overnight and you are now a much more experience developer because of that and therefore much better equipped to resolve the present issue.&lt;/p&gt;

&lt;p&gt;Over time, the necessity to do this will be reduced as you compound your experience but there will be new challenges to face as you expand your abilities and if you managed to get into good working habits and recognise when to say "enough" and take a step back, your personal development will soar.&lt;/p&gt;

&lt;p&gt;So as un-philosophical as it may sound and as irresponsible as it may feel, leaving it for tomorrow can actually be the best thing for you. If you haven't already, I suggest you at least give it a try and see for yourself.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>codenewbie</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
