<?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>Forem: Kim Hallberg</title>
    <description>The latest articles on Forem by Kim Hallberg (@thinkverse).</description>
    <link>https://forem.com/thinkverse</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%2F180238%2Fdbeade92-b185-4702-8ce6-6b0e9f1299a8.jpg</url>
      <title>Forem: Kim Hallberg</title>
      <link>https://forem.com/thinkverse</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/thinkverse"/>
    <language>en</language>
    <item>
      <title>How to use Bootstrap with Laravel and Vite</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Sun, 25 Dec 2022 02:19:42 +0000</pubDate>
      <link>https://forem.com/thinkverse/how-to-use-bootstrap-with-laravel-and-vite-3h90</link>
      <guid>https://forem.com/thinkverse/how-to-use-bootstrap-with-laravel-and-vite-3h90</guid>
      <description>&lt;p&gt;While the Laravel community now mostly uses Tailwind CSS. &lt;a href="https://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt; - one of the most used CSS frameworks currently on the market, is still widely used by a portion of the community.&lt;/p&gt;

&lt;p&gt;Since Laravel's switch to Vite, the status quo of Webpack and Mix was broken and a growing number of users struggle to add Bootstrap to their projects. This post was written to go over how to install Bootstrap in a fresh Laravel installation to ease that struggle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Bootstrap
&lt;/h2&gt;

&lt;p&gt;Bootstrap and its dependencies are installed using npm, or your preferred node package manager. From the root of our Laravel application, run the following command.&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;bootstrap @popperjs/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bootstrap relies on &lt;a href="https://popper.js.org/" rel="noopener noreferrer"&gt;Popper&lt;/a&gt; for its dropdowns, popovers, and tooltips.&lt;/p&gt;

&lt;p&gt;Another dependency that Bootstrap requires is &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;Sass&lt;/a&gt;, which we will install as a development dependency.&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;sass &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Restructuring our CSS
&lt;/h2&gt;

&lt;p&gt;Since Laravel doesn't use Sass out of the box, we will rename our &lt;code&gt;css&lt;/code&gt; directory and change our &lt;code&gt;app.css&lt;/code&gt; extension to &lt;code&gt;scss&lt;/code&gt; to follow that convention.&lt;/p&gt;

&lt;p&gt;How you rename and change those is up to you, but I will use &lt;code&gt;git&lt;/code&gt; to keep track of the changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;mv &lt;/span&gt;resources/css/ resources/scss/
git &lt;span class="nb"&gt;mv &lt;/span&gt;resources/scss/app.css resources/css/app.scss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that is done we need to update our &lt;code&gt;vite.config.js&lt;/code&gt; file to use the new path in its &lt;code&gt;input&lt;/code&gt; array.&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="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;laravel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/scss/app.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="na"&gt;refresh&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="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;
  
  
  Importing Bootstrap CSS
&lt;/h2&gt;

&lt;p&gt;Our next course of action, before importing Bootstrap in our Sass file, is to set up an &lt;a href="https://vitejs.dev/config/shared-options.html#resolve-alias" rel="noopener noreferrer"&gt;alias&lt;/a&gt; for Bootstrap in our &lt;code&gt;vite.config.js&lt;/code&gt; file to make it simpler to import.&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="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&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;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;/../&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&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="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/bootstrap&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our alias configured all we have to do now is import Bootstrap's CSS in our Sass file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="c1"&gt;// resources/scss/app.scss&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"~bootstrap/scss/bootstrap"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will import &lt;strong&gt;all&lt;/strong&gt; the stylesheets Bootstrap offers, to import individual stylesheets, please refer to the documentation for &lt;a href="https://getbootstrap.com/docs/5.2/customize/sass/#importing" rel="noopener noreferrer"&gt;Sass imports&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importing Bootstrap JavaScript
&lt;/h2&gt;

&lt;p&gt;The last job we need to do is to import Bootstrap's JavaScript. And that is done in either your &lt;code&gt;bootstrap.js&lt;/code&gt; file or &lt;code&gt;app.js&lt;/code&gt;. For this example, I've gone with &lt;code&gt;app.js&lt;/code&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="c1"&gt;// resources/js/app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;bootstrap&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;bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finishing up
&lt;/h2&gt;

&lt;p&gt;With that done, all that is left is to add our Vite Blade directive and build our assets. For this example, we're updating the default &lt;code&gt;welcome.blade.php&lt;/code&gt; with some Bootstrap example 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="c"&gt;&amp;lt;!-- resources/views/welcome.blade.php --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    @vite(['resources/scss/app.scss', 'resources/js/app.js'])
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Header example
&lt;/h3&gt;

&lt;p&gt;Bootstrap offers some great &lt;a href="https://getbootstrap.com/docs/5.2/examples/" rel="noopener noreferrer"&gt;examples&lt;/a&gt; for you to quickly get started on a project. With that in mind, let's use one of their &lt;a href="https://getbootstrap.com/docs/5.2/examples/headers/" rel="noopener noreferrer"&gt;headers&lt;/a&gt; to test whether our Bootstrap installation is working correctly.&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="c"&gt;&amp;lt;!-- resources/views/welcome.blade.php --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-3 mb-3 border-bottom"&lt;/span&gt;&lt;span class="nt"&gt;&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;"container"&lt;/span&gt;&lt;span class="nt"&gt;&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;"d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-flex align-items-center mb-2 mb-lg-0 text-dark text-decoration-none"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt; &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"1.5"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bi me-2"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"40"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"img"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Storefront"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;stroke-linecap=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt; &lt;span class="na"&gt;stroke-linejoin=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349m-16.5 11.65V9.35m0 0a3.001 3.001 0 003.75-.615A2.993 2.993 0 009.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 002.25 1.016c.896 0 1.7-.393 2.25-1.016a3.001 3.001 0 003.75.614m-16.5 0a3.004 3.004 0 01-.621-4.72L4.318 3.44A1.5 1.5 0 015.378 3h13.243a1.5 1.5 0 011.06.44l1.19 1.189a3 3 0 01-.621 4.72m-13.5 8.65h3.75a.75.75 0 00.75-.75V13.5a.75.75 0 00-.75-.75H6.75a.75.75 0 00-.75.75v3.75c0 .415.336.75.75.75z"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

                &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link px-2 link-secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Overview&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link px-2 link-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Inventory&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link px-2 link-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Customers&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link px-2 link-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Products&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

                &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-12 col-lg-auto mb-3 mb-lg-0 me-lg-3"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Search..."&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Search"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/form&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;"dropdown text-end"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-block link-dark text-decoration-none dropdown-toggle"&lt;/span&gt;
                        &lt;span class="na"&gt;data-bs-toggle=&lt;/span&gt;&lt;span class="s"&gt;"dropdown"&lt;/span&gt; &lt;span class="na"&gt;aria-expanded=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://github.com/mdo.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"mdo"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"rounded-circle"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt;
                            &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-menu text-small"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;New project...&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Settings&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Profile&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sign out&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/ul&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;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we now build our assets, we should see our new Bootstrap headers working when we enter our site.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&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%2Fmx11xdeqpa3mv7kc5ppd.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%2Fmx11xdeqpa3mv7kc5ppd.png" alt="Bootstrap example page with working dropdown" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;With that, you now know how to install and import Bootstrap with Laravel and Vite. 🎉&lt;/p&gt;

&lt;p&gt;The finished code is available on my GitHub in the &lt;a href="https://github.com/thinkverse/laravel-vite-and-bootstrap/" rel="noopener noreferrer"&gt;laravel-vite-and-bootstrap&lt;/a&gt; repository and can be stepped through commit by commit.&lt;/p&gt;

&lt;p&gt;Til next time, have a great day. 👋&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>bootstrap</category>
      <category>vite</category>
    </item>
    <item>
      <title>How to use jQuery with Laravel and Vite</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Mon, 26 Sep 2022 22:03:32 +0000</pubDate>
      <link>https://forem.com/thinkverse/how-to-use-jquery-with-laravel-and-vite-50a7</link>
      <guid>https://forem.com/thinkverse/how-to-use-jquery-with-laravel-and-vite-50a7</guid>
      <description>&lt;p&gt;jQuery is one of the OG JavaScript libraries still in heavy use in the Laravel community to this day. It was a breeze to add with Laravel Mix, but since Laravel v9.2.0 Vite is now the default and a lot of users have had trouble getting it to work.&lt;/p&gt;

&lt;p&gt;Fret not, because in this post we will go over how to install it, import it, and how to use it with Laravel 9 and Vite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing jQuery
&lt;/h3&gt;

&lt;p&gt;jQuery is installed with a single command from your terminal using your preferred node package manager. We will use &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt; in this post.&lt;/p&gt;

&lt;p&gt;Travel to the root of your Laravel application and run the following command.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;We use the &lt;code&gt;--save-dev&lt;/code&gt; flag since Laravel added all its node dependencies as development dependencies by default, so why not follow their lead?&lt;/p&gt;

&lt;h3&gt;
  
  
  Importing jQuery
&lt;/h3&gt;

&lt;p&gt;Now that we have jQuery installed, we will import it in our &lt;code&gt;bootstrap.js&lt;/code&gt; file. That's where Laravel imports its dependencies, so again, why not do the same? We can import jQuery anywhere really, but for this example, we will add it below the lodash import.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import $ from 'jquery';
window.$ = $;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also add jQuery to the window object. This will be useful for when we need to access jQuery directly in a Blade file.&lt;/p&gt;

&lt;p&gt;This step is optional though, if you never intend on using jQuery directly in a Blade file and plan to use it in your &lt;code&gt;app.js&lt;/code&gt; file only, then there is no need to add it to the window object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Vite directive
&lt;/h3&gt;

&lt;p&gt;Now jQuery is installed and imported, but we still won't have access to it in our application. For that, we need to load our &lt;code&gt;app.js&lt;/code&gt; script using the &lt;code&gt;@vite&lt;/code&gt; Blade directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@vite('resources/js/app.js')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this simple example, we are only loading our &lt;code&gt;app.js&lt;/code&gt; asset. If you want to load your &lt;code&gt;app.css&lt;/code&gt; asset as well, then you will have to use an array and load both.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@vite(['resources/css/app.css', 'resources/js/app.js'])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information, I recommend you read Laravel's documentation on &lt;a href="https://laravel.com/docs/9.x/vite"&gt;Asset Bundling with Vite&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using jQuery?
&lt;/h3&gt;

&lt;p&gt;We now have jQuery installed, imported, and loaded in our application. But how do we actually use it? Before we could access jQuery using the &lt;code&gt;$&lt;/code&gt; in a blocking inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;If you try to do that now, it will result in the following console error.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Uncaught ReferenceError: $ is not defined&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So how do we prevent this from happening? It's rather simple, the first thing you need to understand is a bit about how browsers load JavaScript. Specifically how it loads &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;JavaScript modules&lt;/a&gt;, because that is how Laravel loads JavaScript with Vite.&lt;/p&gt;

&lt;p&gt;JavaScript modules are deferred by default. So a blocking inline script tag, even added at the bottom of your &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; is executed before your JavaScript modules.&lt;/p&gt;

&lt;p&gt;Since the browser hasn't loaded in the &lt;code&gt;app.js&lt;/code&gt; module yet, jQuery hasn't yet been added to the window object, so trying to access it before that results in the reference error.&lt;/p&gt;

&lt;h4&gt;
  
  
  jQuery and Inline Scripts
&lt;/h4&gt;

&lt;p&gt;So you might think that we cannot use jQuery with inline scripts. We can, the only difference from before is that now your inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag also needs to be a JavaScript module. By doing that, we fix the loading issue.&lt;/p&gt;

&lt;p&gt;Add the following line in your &lt;code&gt;welcome.blade.php&lt;/code&gt; view, somewhere &lt;strong&gt;after your&lt;/strong&gt; &lt;code&gt;@vite&lt;/code&gt; directive call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script type="module"&amp;gt;
    $('body').html('&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;');
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we load our landing page, we should see the words - &lt;strong&gt;Hello World!&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  jQuery and App.js
&lt;/h4&gt;

&lt;p&gt;What if you want to access jQuery in your &lt;code&gt;app.js&lt;/code&gt; file? We can use the &lt;code&gt;$&lt;/code&gt; in there as well, and we can demonstrate that with this little snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$(() =&amp;gt; {
    setTimeout(() =&amp;gt; {
        alert('jQuery triggered via app.js')
    }, 2500);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've ever wanted to test some JavaScript this might look familiar. This simple snipper sets a timer that when finished triggers an alert.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finishing up
&lt;/h3&gt;

&lt;p&gt;If you've followed along we now have two jQuery calls, that both demonstrate accessing jQuery in different situations. If you now build your assets, with the following command.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And access the site, you will see the default Laravel landing page disappear and be replaced with &lt;strong&gt;Hello World!&lt;/strong&gt; , and after about 2 seconds the alert should pop up.&lt;/p&gt;

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

&lt;p&gt;Now you know how to install, import, and access jQuery with Larvel and Vite. 🎉&lt;/p&gt;

&lt;p&gt;As always, the finished code is available on my GitHub in the &lt;a href="https://github.com/thinkverse/laravel-vite-and-jquery"&gt;laravel-vite-and-jquery&lt;/a&gt; repository and can be stepped through commit by commit.&lt;/p&gt;

&lt;p&gt;Til next time, have a great day. 👋&lt;/p&gt;

</description>
      <category>jquery</category>
      <category>laravel</category>
      <category>vite</category>
    </item>
    <item>
      <title>Getting Started with TALL stack</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Tue, 13 Sep 2022 09:11:50 +0000</pubDate>
      <link>https://forem.com/thinkverse/getting-started-with-tall-stack-3jc3</link>
      <guid>https://forem.com/thinkverse/getting-started-with-tall-stack-3jc3</guid>
      <description>&lt;p&gt;&lt;a href="https://tallstack.dev/"&gt;TALL stack&lt;/a&gt; is a full-stack development solution used for building powerful, modern, and reactive Laravel applications. This stack can be used to build a multitude of applications, in fact, you're reading this on a platform built with the TALL stack.&lt;/p&gt;

&lt;p&gt;Built with a foundation in &lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt;, it uses &lt;a href="https://laravel-livewire.com"&gt;Livewire&lt;/a&gt; for dynamic interfaces, &lt;a href="https://tailwindcss.com/"&gt;Tailwind CSS&lt;/a&gt; for smooth and rapid designing, and &lt;a href="https://alpinejs.dev/"&gt;Alpine.js&lt;/a&gt; for composing client-side interactions. Hence the name - TALL stack.&lt;/p&gt;

&lt;p&gt;There are several ways to create a TALL stack app, but all begin with installing Laravel, so that's what we're going to start with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Laravel
&lt;/h3&gt;

&lt;p&gt;To start using the stack, we first need to install our foundation, which is Laravel. We can &lt;a href="https://laravel.com/docs/9.x/installation#your-first-laravel-project"&gt;install Laravel&lt;/a&gt; in several ways, but the quickest way is using &lt;a href="https://getcomposer.org/"&gt;Composer&lt;/a&gt;, and we can do that with the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project laravel/laravel tallstack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a new folder wherever you ran the command using the project name as the directory name. In this example, the directory will be &lt;code&gt;tallstack&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have installed a Laravel application, we can start adding the rest of our stack. We can install the rest of our stack using different ways, the easiest would be to use a Laravel starter as our base.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing via starter kit
&lt;/h3&gt;

&lt;p&gt;Laravel makes available two different starter kits, Breeze and Jetstream. If you've used Laravel UI before you'll be right at home with Breeze. If you want something heftier with profile management, two-factor authentication, browser sessions, and more you want to choose Jetstream.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using Laravel Breeze
&lt;/h4&gt;

&lt;p&gt;To &lt;a href="https://laravel.com/docs/9.x/starter-kits#laravel-breeze-installation"&gt;install Breeze&lt;/a&gt; we use Composer to require it, in the root of your newly created Laravel application, run the following command.&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 laravel/breeze &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we can now use Artisan to install Breeze's default stack (&lt;a href="https://laravel.com/docs/9.x/starter-kits#breeze-and-blade"&gt;Breeze &amp;amp; Blade&lt;/a&gt;), which will scaffold authentication and install Tailwind CSS and Alpine.js for us.&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 breeze:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To finish Breeze you will have to migrate your migrations using Artisan.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Your last step will be to install Livewire, which we go over further down in the manual section. The installation steps are the same the only difference is you add Livewire's JavaScript and CSS directives in your &lt;code&gt;app.blade.php&lt;/code&gt; and &lt;code&gt;guest.blade.php&lt;/code&gt; layout files.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using Laravel Jetstream
&lt;/h4&gt;

&lt;p&gt;To use &lt;a href="https://jetstream.laravel.com/2.x/installation.html#installing-jetstream"&gt;install Jetstream&lt;/a&gt; we first need to require it by using 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 laravel/jetstream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we have to install Jetstream using Artisan and let it scaffold our application and install the necessary dependencies.&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 jetstream:install livewire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that we are nearly complete with Jetstream, all that is left is to migrate our migrations.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;With that you have a newly created TALL stack application, you don't have to read anymore and can go create your next big project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing each dependency
&lt;/h3&gt;

&lt;p&gt;If you choose not to use a starter kit and want to install the rest of the stack manually, you can do that by following the steps down below.&lt;/p&gt;

&lt;h4&gt;
  
  
  Installing Livewire
&lt;/h4&gt;

&lt;p&gt;Livewire will be the next part of our stack and we can &lt;a href="https://laravel-livewire.com/docs/2.x/quickstart#install-livewire"&gt;install Livewire&lt;/a&gt; using the same tool as before, Composer. Open your Laravel application in your terminal and use Composer to require Livewire.&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 livewire/livewire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Livewire installed as a dependency, we can add the necessary JavaScript and CSS files to our view or layout file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that if you have a layout file, add the following to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of your layout file instead of each individual view. In this example we don't have a layout, so we're adding it directly to the bottom of our &lt;code&gt;welcome.blade.php&lt;/code&gt; view &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;livewireStyles&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To finish up Livewire we have one more line to add to the end of our &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. The same applies here, if you have a layout file, add it to the layout file. We only want to load Livewire's JavaScript and CSS files once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;livewireScripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure our assets rebuild when we're developing locally, we have to update your &lt;code&gt;vite.config.js&lt;/code&gt; file to include Livewire in its refresh paths. We do that by deconstructing the default paths and adding Livewire's paths into the new list.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&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;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;laravel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;refreshPaths&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;laravel-vite-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;laravel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/css/app.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&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="na"&gt;refresh&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;refreshPaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/Http/Livewire/**&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="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, we are up and running with Livewire. If you did this step after using Breeze you are now finished and have a fully-fledged TALL stack application. If you're doing this manually then Tailwind CSS is up next.&lt;/p&gt;

&lt;h4&gt;
  
  
  Installing Tailwind
&lt;/h4&gt;

&lt;p&gt;Setting up Tailwind CSS in a Laravel application is a breeze, the team at Tailwind CSS even has a &lt;a href="https://tailwindcss.com/docs/guides/laravel"&gt;guide&lt;/a&gt; for it. A guide that we will follow by installing Tailwind CSS and its dependencies as described.&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; &lt;span class="nt"&gt;-D&lt;/span&gt; tailwindcss postcss autoprefixer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to generate our Tailwind CSS and PostCSS config file using &lt;code&gt;npx&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;npx tailwindcss init &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With those steps finised we can configure our Tailwind CSS template paths by adding to the &lt;code&gt;content&lt;/code&gt; array in our &lt;code&gt;tailwind.config.js&lt;/code&gt; file.&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="cm"&gt;/** @type {import('tailwindcss').Config} */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&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="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./resources/**/*.blade.php&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./resources/**/*.js&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="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&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;plugins&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;I am omitting Vue files here since we are not using Vue, so Blade and JavaScript files are enough here.&lt;/p&gt;

&lt;p&gt;Now we can add the Tailwind directives to our &lt;code&gt;app.css&lt;/code&gt; file, located in &lt;code&gt;./resources/css/app.css&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we can update our view or layout file to use Laravel's Vite directive. Add the following line in your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; by replacing an existing &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; as we have in our &lt;code&gt;welcome.blade.php&lt;/code&gt;, or by adding it above our Livewire CSS directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nf"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'resources/css/app.css'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visiting our site now should result in the following error - &lt;strong&gt;Vite manifest not found at: /tallstack/public/build/manifest.json&lt;/strong&gt;. We can fix this by starting a Vite development server using the following command.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This is great when working locally, our assets update when we make changes in our views, but it does come with a caveat. When we stop our development server the error will be back. We can solve that by starting the server again or building for production by using &lt;code&gt;build&lt;/code&gt; instead of &lt;code&gt;dev&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;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use both Livewire and Tailwind CSS, our last step in Alpine.js&lt;/p&gt;

&lt;h4&gt;
  
  
  Installing Alpine.js
&lt;/h4&gt;

&lt;p&gt;Our final dependency to install is Apline.js. And we will &lt;a href="https://alpinejs.dev/essentials/installation#as-a-module"&gt;install Alpine.js as a module&lt;/a&gt; using NPM just like Tailwind CSS and following the installation guide.&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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now import Alpine in our &lt;code&gt;boostrap.js&lt;/code&gt; file, located in &lt;code&gt;./resources/js/bootstrap.js&lt;/code&gt;. Let's import Alpine at the bottom of our bootstrap file.&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="nx"&gt;Alpine&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;alpinejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, all we need do to is initialize Alpine using its start method.&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;Alpine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want more flexibility with Alpine, like accessing Alpine using the &lt;a href="https://github.com/alpine-collective/alpinejs-devtools"&gt;Alpine.js devtools&lt;/a&gt;, you can add Alpine to the window object, though it is not required for Alpine to work.&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Alpine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our last step is to update our Vite directive to include our &lt;code&gt;app.js&lt;/code&gt; file. We do that by placing our existing string argument inside an array and adding our &lt;code&gt;app.js&lt;/code&gt; path as an array item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nf"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'resources/css/app.css'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'resources/js/app.js'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And as with Tailwind CSS, you can either start a Vite development server or build for production to generate new asset files.&lt;/p&gt;

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

&lt;p&gt;And with that, you now have a TALL stack application. Your next step will be to create a &lt;a href="https://laravel-livewire.com/docs/2.x/making-components"&gt;Livewire component&lt;/a&gt; and perhaps build an &lt;a href="https://alpinejs.dev/start-here#building-a-dropdown"&gt;Alpine.js dropdown&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What you will build is up to you and your imagination, so go out and create your next big project. 🤘&lt;/p&gt;

&lt;p&gt;Source code for this article is available on my GitHub - &lt;a href="https://github.com/thinkverse/tallstack-example"&gt;thinkverse/tallstack-example&lt;/a&gt; - if you are more comfortable reading commits and code. You can find the Breeze and Jetstream examples in their respective branches. 👍&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>alpinejs</category>
      <category>livewire</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>How to Add Sign in With GitHub to Wave</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Fri, 12 Nov 2021 21:26:04 +0000</pubDate>
      <link>https://forem.com/thinkverse/how-to-add-sign-in-with-github-to-wave-1do5</link>
      <guid>https://forem.com/thinkverse/how-to-add-sign-in-with-github-to-wave-1do5</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;In this tutorial, we will cover how to add social login to Wave. For this example, we will use GitHub as our OAuth provider.&lt;/p&gt;

&lt;p&gt;We will start by adding Laravel's Socialite package. This package is designed for quickly and conveniently authenticating with an OAuth provider.&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 laravel/socialite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Boostrapping Socialite
&lt;/h3&gt;

&lt;p&gt;Next, we will follow the steps given to us via the Socialite documentation. Namely, setting up our environment variables. Linking those together with our services config. Creating our controllers and lastly our routes.&lt;/p&gt;

&lt;p&gt;Let's start by updating our &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;.env.example&lt;/code&gt; by adding these three variable keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;GITHUB_CLIENT_ID=&lt;/span&gt;
&lt;span class="s"&gt;GITHUB_CLIENT_SECRET=&lt;/span&gt;
&lt;span class="s"&gt;GITHUB_REDIRECT_URL=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we're not adding the secret keys to the &lt;code&gt;.env.example&lt;/code&gt; file and only empty placeholders.&lt;/p&gt;

&lt;p&gt;Moving on to our &lt;code&gt;config/services.php&lt;/code&gt; file, let us add the correct configuration so that Socialite gets the GitHub OAuth keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'github'&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;'client_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GITHUB_CLIENT_ID'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'client_secret'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GITHUB_CLIENT_SECRET'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'redirect'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GITHUB_REDIRECT_URL'&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;Before we go over to GitHub and get our secret keys, let us generate a new empty controller and add some routes.&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:controller Auth&lt;span class="se"&gt;\\&lt;/span&gt;GitHubSocialiteController
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will generate an empty controller in our existing &lt;code&gt;Controller\Auth&lt;/code&gt; folder. We will quickly add two empty methods called &lt;code&gt;redirect&lt;/code&gt; and &lt;code&gt;callback&lt;/code&gt; to it. There will be the ones our routes will call when hit.&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;GitHubSocialiteController&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;redirect&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;callback&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 in our &lt;code&gt;routes/web.php&lt;/code&gt;, we can add our two routes. Adding a name to our redirect endpoint makes it easier to generate a URL for it later.&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;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'guest'&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="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;'auth/github/redirect'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;GitHubSocialiteController&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;'redirect'&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;'github.login'&lt;/span&gt;&lt;span class="p"&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;'auth/github/callback'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;GitHubSocialiteController&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;'callback'&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 reason for adding the &lt;code&gt;guest&lt;/code&gt; middleware is that we don't want authenticated users to try and logged-in again when they're already logged in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registering a GitHub OAuth App
&lt;/h3&gt;

&lt;p&gt;Now that we have the boilerplate for Socialie done, we can head over to GitHub and register our &lt;a href="https://github.com/settings/applications/new"&gt;new OAuth app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YoTmnOWe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.devdojo.com/images/november2021/github-oauth-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YoTmnOWe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.devdojo.com/images/november2021/github-oauth-app.png" alt="Screenhot of GitHub's register a new OAuth application page" width="772" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill out the information with your application's name and appropriate URLs. The callback URL should match the URL you gave to the callback route.&lt;/p&gt;

&lt;p&gt;After registering the new app with GitHub, we get redirected to the applications' general settings. Here we can grab our applications' client ID and generate a new client secret.&lt;/p&gt;

&lt;p&gt;Keep in mind that you'll only see the applications' client secret ones. So make sure you copy it after generating it. Otherwise, you'll have to delete the old secret and generate a new one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--57hdTSPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.devdojo.com/images/november2021/github-oauth-secrets.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--57hdTSPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.devdojo.com/images/november2021/github-oauth-secrets.png" alt="Screenshot of generating a client secret key" width="771" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these keys generated, we can now update our &lt;code&gt;.env&lt;/code&gt; variables with those keys. Of course, your keys and callback URL will be different.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;GITHUB_CLIENT_ID=4f636859a54b7410a51f&lt;/span&gt;
&lt;span class="s"&gt;GITHUB_CLIENT_SECRET=26ba921db4bb0a8dca6c733de5705266ed28346d&lt;/span&gt;
&lt;span class="s"&gt;GITHUB_REDIRECT_URL='https://wave.test/auth/github/callback'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these keys set, Laravel Socialite can now create the correct payload to send to GitHub when a user's trying to authenticate via our application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extending our User Model
&lt;/h3&gt;

&lt;p&gt;Now that we've done the Socialite boilerplate and registered our new OAuth application. Our next step is to prepare our user model to store our id provided by GitHub.&lt;/p&gt;

&lt;p&gt;We do this by generating a new migration where we add our new column.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This command will generate a new migration named &lt;code&gt;Y_m_d_His_add_provider_id_to_users_table.php&lt;/code&gt;. Modify the new file and add the new varchar column named &lt;code&gt;provider_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The column should be &lt;code&gt;nullable&lt;/code&gt; since not all users will use the feature. Add &lt;code&gt;unique&lt;/code&gt; since GitHub will not return the same id for different users so we will reflect that in our column.&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;AddProviderIdToUsersTable&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Migration&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;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'provider_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;nullable&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;unique&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;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dropColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'provider_id'&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;Last but not least, add the &lt;code&gt;provider_id&lt;/code&gt; to the &lt;code&gt;App\User&lt;/code&gt;s' fillable property. That way, we can easily add it when creating our user later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @var array
 */&lt;/span&gt;
&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'verified'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'trial_ends_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'provider_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;h3&gt;
  
  
  Authenticating with GitHub
&lt;/h3&gt;

&lt;p&gt;The time has finally come to connect these pieces together and start authenticating against GitHub when a user hits the &lt;code&gt;auth/redirect&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;We will start with the simplest of additions to our code, a single line in our &lt;code&gt;GitHubSocialiteController&lt;/code&gt; controller.&lt;/p&gt;

&lt;p&gt;Update your &lt;code&gt;redirect&lt;/code&gt; method and add the following line of code.&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;redirect&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="nc"&gt;Socialite&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github'&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;redirect&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;Lets' not forget to also use the Socialite facade, if your IDE or editor has auto-complete you can skip this since it's already there.&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;Laravel\Socialite\Facades\Socialite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this Socialite will generate the necessary payload so when a user travels to the &lt;code&gt;auth/redirect&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;It will then redirect to GitHub, ask for the user permission to authenticate the application, and grant them access to the users' identity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6G6c3SlL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.devdojo.com/images/november2021/github-oauth-ask.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6G6c3SlL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.devdojo.com/images/november2021/github-oauth-ask.png" alt="Screenhot of GitHub's OAuth authentication process" width="559" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling the OAuth Callback
&lt;/h3&gt;

&lt;p&gt;Our last section will be the one with the most code. That is because we have things to consider in this callback state.&lt;/p&gt;

&lt;p&gt;We first need to get the user identity provided by GitHub, we also need to consider Wave's trial functionality and give the user our default role.&lt;/p&gt;

&lt;p&gt;Luckily, that isn't so difficult. Since the code for that has already been written by the maintainers of Wave we can simply copy that to match the functionality.&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;callback&lt;/code&gt; method in your &lt;code&gt;GitHubSocialiteController&lt;/code&gt; controller and add the following code.&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;callback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$github&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Socialite&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github'&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;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Role&lt;/span&gt;&lt;span class="o"&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;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'voyager.user.default_role'&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;$trial_days&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'billing.trial_days'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$trial_ends_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;intval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$trial_days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$trial_ends_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;now&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;addDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'billing.trial_days'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&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;Stepping through the code a bit. Firstly using the Socialite facade to get the identity provided by GitHub. Secondly, we use Voyager's Role model, and using the config we can find the default role, we'll need that soon.&lt;/p&gt;

&lt;p&gt;Last but not least we get the trial days defined in our site settings. We will also set the trial_ends_at variable to null as a default. We will only overwrite that if our trial days are greater than 0.&lt;/p&gt;

&lt;p&gt;Meaning if we've set our trial days to &lt;code&gt;-1&lt;/code&gt;, effectively negating them we don't set an end date and leave it null.&lt;/p&gt;

&lt;p&gt;We're almost done with this tutorial. We are finally going to tackle the last real hard part. Consider this scenario, we've already registered several users before we add this feature.&lt;/p&gt;

&lt;p&gt;Now, what happens when an already existing user tries to sign in with GitHub on our application? Well, their email is probably the same, maybe their username is also the same? So adding them again will create a duplicate entry error.&lt;/p&gt;

&lt;p&gt;Maybe we only add the &lt;code&gt;provider_id&lt;/code&gt; to their record? That will only work for existing users though. For new, users signing up for the first time via GitHub, we need to add their email, username, etc.&lt;/p&gt;

&lt;p&gt;We will have three states to contend with, existing users, new users, and returning users. Lets' handle all three scenarios step-by-step, starting with returning users.&lt;/p&gt;

&lt;p&gt;First, we need to check if any user in our records already has the id added, if that's the case we can simply return that user and sign them in.&lt;/p&gt;

&lt;p&gt;Update your &lt;code&gt;callback&lt;/code&gt; method with the following code.&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&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;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;'provider_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$github&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="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;login&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="s1"&gt;'Successfully logged in.'&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;For now, you don't have to worry about the &lt;code&gt;login&lt;/code&gt; method, I will show that last since it's a method we will call in more than one place.&lt;/p&gt;

&lt;p&gt;Next, we will tackle existing users. This is for the most part a carbon copy of the last scenario concerning returning users. The difference is we're checking for a matching email address, and if found we add the provider id and log the user in.&lt;/p&gt;

&lt;p&gt;Add the snippet below the last one in your &lt;code&gt;callback&lt;/code&gt; method.&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&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;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;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$github&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getEmail&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="p"&gt;)&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="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'provider_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$github&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&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;login&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="s1"&gt;'Successfully logged in.'&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;Two scenarios have not been handled. we'll now handle the last and final scenario, the new user. This scenario is where we'll use the &lt;code&gt;$role&lt;/code&gt; and &lt;code&gt;$trial_ends_at&lt;/code&gt; variables we defined before.&lt;/p&gt;

&lt;p&gt;Add this final code snippet to your &lt;code&gt;callback&lt;/code&gt; method.&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&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;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;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'provider_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$github&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$github&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getEmail&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;$github&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str_random&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="s1"&gt;'username'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$github&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getNickname&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s1"&gt;'verified'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'trial_ends_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$trial_ends_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'role'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$role&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;span class="nf"&gt;event&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;Registered&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="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;login&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="s1"&gt;'Thanks for signing up!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Taking full advantage of the identity provided for us by GitHub, we get an email for the user that's already verified by GitHub, a name, and a username. We only need to add the default role using the id and add the calculated trial end date.&lt;/p&gt;

&lt;p&gt;A caveat here though, new users will get a randomly generated password. For safety reasons we won't email it to them since it's never a good idea to send plain text passwords over the wire.&lt;/p&gt;

&lt;p&gt;So new users added via GitHub will have to reset their password via the forgot your password feature.&lt;/p&gt;

&lt;p&gt;Before logging the new user in we send off Laravel's registered event.&lt;/p&gt;

&lt;p&gt;Now before I end this post off. I will give you the last piece of this puzzle.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;login&lt;/code&gt; method, it's simply a DRY private method used to log the user in and redirect to the wave dashboard with a success toast message.&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;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;login&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="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;)&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;guard&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;login&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="kc"&gt;false&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;redirect&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;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wave.dashboard'&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;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'message_type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'success'&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;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;And there you have it, now all you need to do is add some sign-in or sign-up with GitHub buttons on your website, here's a quick example that works with Wave out-of-the-box.&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;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ route('github.login') }}"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex w-full items-center justify-center space-x-4 mt-4 py-4 px-8 text-white bg-gray-800 shadow-lg rounded-md font-medium text-lg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-8 h-8 fill-current"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        Sign in with GitHub
    &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As before, thank you for reading and the full source code is available on my GitHub under the &lt;a href="https://github.com/thinkverse/wave-with-socialite"&gt;wave-with-socialite&lt;/a&gt; repository.&lt;/p&gt;

&lt;p&gt;Have a great day. 👋&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>github</category>
      <category>socialite</category>
      <category>oauth</category>
    </item>
    <item>
      <title>How to use BuyMeACoffees webhooks with Laravel.</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Sun, 01 Aug 2021 17:17:52 +0000</pubDate>
      <link>https://forem.com/thinkverse/how-to-use-buymeacoffees-webhooks-with-laravel-2d4a</link>
      <guid>https://forem.com/thinkverse/how-to-use-buymeacoffees-webhooks-with-laravel-2d4a</guid>
      <description>&lt;p&gt;In this post, I will demonstrate how to use &lt;a href="https://www.buymeacoffee.com/webhook"&gt;BuyMeACoffees Webhooks&lt;/a&gt; in Laravel. BMCs Webhooks allows you to get near-instant notifications when an event happens on your account, as said by BMC themselves.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the event occurs—a supporter buys coffee for you, or someone purchases your coffeelink, etc.—BMC creates an Event object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When an account event is triggered, BMC will send a POST request to your desired URL with the event as its payload. Those payloads will be a JSON object with the event-specific values being under the response key.&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;"response"&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;"supporter_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"supporter@buymeacoffee.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"number_of_coffees"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total_amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"support_created_on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2021-08-01 16:00:00"&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;So, let us receive this event in Laravel by creating a POST route that will be our webhook URL, a controller to handle the event, and a middleware that will verify its authenticity. We will begin by using artisan to make our controller and middleware.&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:controller BuyMeACoffeeWebhookController &lt;span class="nt"&gt;--invokable&lt;/span&gt;
php artisan make:middleware VerifyBuyMeACoffeeWebhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will use an invokable controller simply because this controller will only handle one thing. Now we will register our POST route and attach our controller and middleware.&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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/buymeacoffee'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BuyMeACoffeeWebhookController&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;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VerifyBuyMeACoffeeWebhook&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify that our webhook is authentic and is sent from BMC, we will use hash_hmac to verify that the SHA256 signatures match, this is done by hashing the incoming request and using our webhook secret as the hashing key, and checking that the resulting hash matches the given signature.&lt;/p&gt;

&lt;p&gt;You can find your webhook secret in the webhook dashboard, each webhook you add will have its own secret, and can be regenerated by removing the webhook and adding it back again. It is best not to add our secret directly into our code, so we will create a new file under /config/webhooks.php which will get our secret from our environment variables.&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;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s1"&gt;'buymeacoffee'&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;'secret'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'BUYMEACOFFEE_WEBHOOK_SECRET'&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 when we need our secret we can use Laravels config function to grab it.&lt;/p&gt;

&lt;p&gt;So, time now to move along and update our middleware to verify the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Response&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Closure&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;VerifyBuyMeACoffeeWebhook&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'x-bmc-event'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x-bmc-signature'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&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;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Webhook signature didn't match!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;verify&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="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="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;headers&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;has&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;headers&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;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'X-Bmc-Signature'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'X-Bmc-Signature'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;hash_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash_hmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sha256'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'webhooks.buymeacoffee.secret'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nv"&gt;$signature&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;Let me step over what we've done here. When the request first comes in we immediately pass it along to a private verify function that returns a boolean indicating if the request has been verified. If it has we let the request pass through to the next middleware and then on to our controller. Otherwise, we break the middleware chain by returning a 400 bad request response.&lt;/p&gt;

&lt;p&gt;The private verify function will start by checking if the request has the necessary headers present that a BMC webhook request should have, mainly X-Bmc-Event and X-Bmc-Signature. We store those in a private array property on the middleware, so should the headers increase in the future we have an easy way of checking for those too.&lt;/p&gt;

&lt;p&gt;This piece of logic is made easier with the help of Laravels collect method. Turning the headers into a collection gives us an easy method to call and check if the headers are present and if they're not we return false breaking the chain.&lt;/p&gt;

&lt;p&gt;We could've also added a check in here for the BMC user-agent, which I omitted in favour of keeping this post shorter. Never the less that piece of logic could look 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="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="nf"&gt;str_contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'BMC-HTTPS-ROBOT'&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;false&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;Moving along to our next piece which is the signature check. We start by first storing the request signature and then removing it from our header bag. This is done to prevent the signature from leaking out of our middleware and into our controller.&lt;/p&gt;

&lt;p&gt;Lastly, as mentioned previously we use hash_hmac to hash the request content using our secret and check if it matches our signature. Since this is the last piece of logic we can simply return the outcome of this check.&lt;/p&gt;

&lt;p&gt;If all of those checks pass, we can safely assume the request is valid and pass the request along the chain.&lt;/p&gt;

&lt;p&gt;Now with a verified request, we can use our controller to delegate what we should do based on a given event. While you could handle both events together, I've chosen to separate them in this post to show how can be done. This is how our controller will 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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\JsonResponse&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Str&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;BuyMeACoffeeWebhookController&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;$event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Str&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;camel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'x-bmc-event'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
     &lt;span class="nv"&gt;$payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'response'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$event&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="nb"&gt;call_user_func&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$payload&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;response&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;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"The event &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'x-bmc-event'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is unsupported."&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;coffeePurchase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResponse&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;response&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;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Thank you for your support &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'supporter_email'&lt;/span&gt;&lt;span class="p"&gt;]&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;coffeeLinkPurchase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResponse&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;response&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;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Thank you for your support &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'supporter_email'&lt;/span&gt;&lt;span class="p"&gt;]&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start by transforming our event into a camel case version using Laravels string facade, this is done because PHP doesn't allow dashes in function names. Next, we use the json method on the request to grab the event-specific values from the response key, as mentioned in the beginning.&lt;/p&gt;

&lt;p&gt;We then move along and check if we have a function to handle that event. This step might be redundant and unnecessary even in this context considering everything is located inside our controller.&lt;/p&gt;

&lt;p&gt;I think it's useful to show how this check is done because. If this was implemented by yourself or another developer, these methods might be located in another class, or use snake case instead of camel case, maybe a method was misspelled of you haven't implemented a method to handle a specific event.&lt;/p&gt;

&lt;p&gt;This simple check makes sure the event you want to handle can actually be handled, if it couldn't be handled, we return a message saying the event is unsupported. If a method was found, we pass in the payload into the method and call it.&lt;/p&gt;

&lt;p&gt;Now it is up to each developer to decide how to handle this payload. Whether that is to associate the supporter_email to a user in your system, maybe give access to a private GitHub repository if the amount supported reaches a certain threshold, or simply send them an email thanking them.&lt;/p&gt;

&lt;p&gt;Thank you for reading, I hope you enjoyed it. 🙌&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>webhooks</category>
    </item>
    <item>
      <title>Solving Multisoft's Monthly Code Challenge</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Tue, 06 Jul 2021 11:18:19 +0000</pubDate>
      <link>https://forem.com/thinkverse/solving-multisoft-s-monthly-code-challenge-5730</link>
      <guid>https://forem.com/thinkverse/solving-multisoft-s-monthly-code-challenge-5730</guid>
      <description>&lt;p&gt;Swedish software company &lt;a href="https://www.multisoft.se"&gt;Multisoft&lt;/a&gt; does a code challenge each month, where it provides a fun little challenge for developers to solve. They do this in hopes of finding new candidates for potential employment.&lt;/p&gt;

&lt;p&gt;In this post, we will go over and solve this month's following code challenge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input = "0219247151", output = ""

for (i in 1 .. length(input))
    if (input[i]%2 == input[i-1]%2)
        output += max(input[i], input[i-1])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The challenge is written in pseudo-code and we want to know what will be stored in the &lt;code&gt;output&lt;/code&gt; variable when the algorithm is finished.&lt;/p&gt;

&lt;p&gt;The algorithm in itself is relatively simple and doesn't have very many working parts, but can be tricky if you're not paying close attention to the setup.&lt;/p&gt;

&lt;p&gt;The setup for the algorithm creates two variables, we will call them &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;output&lt;/code&gt; for simplicity. Our &lt;code&gt;input&lt;/code&gt; stores our initial numbers, and &lt;code&gt;output&lt;/code&gt; will store the result set of our &lt;code&gt;for&lt;/code&gt; operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Algorithm.
&lt;/h2&gt;

&lt;p&gt;The algorithm will step over each number in the &lt;code&gt;input&lt;/code&gt; string starting from the second index through to the last number, in each iteration we will check if the current and previous index have the same remainder when divided by &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When both indexes have the same remainder, we add the maximum value to our &lt;code&gt;output&lt;/code&gt; variable.&lt;/p&gt;

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

&lt;p&gt;Given the above algorithm, we could expect different results based on how a language handles string and integer concatenation.&lt;/p&gt;

&lt;p&gt;If for instance, our language coerces the string returned from &lt;code&gt;max&lt;/code&gt; to integers during the concatenation assignment, we could end up adding each result to each other instead of concatenating them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;+=&lt;/code&gt; usually indicated an arithmetic addition of the previous value added to our new value. In this instance though it indicated a string concatenation assignment.&lt;/p&gt;

&lt;p&gt;Given that, stepping through the algorithm will look something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RvzE0bEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://imgur.com/yfdWrLe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RvzE0bEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://imgur.com/yfdWrLe.gif" alt="Visual representation of the algorithm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Storing the final string value of &lt;strong&gt;294755&lt;/strong&gt; in to the &lt;code&gt;output&lt;/code&gt; variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion.
&lt;/h2&gt;

&lt;p&gt;This was a fun little challenge done by &lt;a href="https://www.multisoft.se"&gt;Multisoft&lt;/a&gt;, and I look forward to next month's challenge.&lt;/p&gt;

&lt;h3&gt;
  
  
  More challenges.
&lt;/h3&gt;

&lt;p&gt;If you're interested is solving coding challenges, check out some of the links below. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.codewars.com/r/ab28sQ"&gt;CodeWars&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codingame.com/"&gt;CodeinGame&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/"&gt;LeetCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hackerrank.com/"&gt;HackerRank&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coderbyte.com/"&gt;CodeByte&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>challenge</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>How to create a simple CLI app with MiniCLI.</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Thu, 10 Jun 2021 14:12:21 +0000</pubDate>
      <link>https://forem.com/thinkverse/how-to-create-a-simple-cli-app-with-minicli-54na</link>
      <guid>https://forem.com/thinkverse/how-to-create-a-simple-cli-app-with-minicli-54na</guid>
      <description>&lt;p&gt;In this post we're covering how to create a simple CLI app with the help of &lt;a href="https://github.com/minicli/minicli" rel="noopener noreferrer"&gt;MiniCLI&lt;/a&gt;. What we'll be creating is a small CLI tool to ping websites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up our requirements.
&lt;/h2&gt;

&lt;p&gt;The first thing we do is to create a folder for our new tool, which I'll name &lt;code&gt;ping-cli&lt;/code&gt; and require the &lt;code&gt;minicli/minicli&lt;/code&gt; package.&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 minicli/minicli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's also create a &lt;code&gt;.gitignore&lt;/code&gt; to make sure the &lt;code&gt;/vendor&lt;/code&gt; folder doesn't get added to source control.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating our entry-point.
&lt;/h2&gt;

&lt;p&gt;With the requirements done we can continue on to creating our entry-point. This is what'll be called from the command-line. Create a &lt;code&gt;bin&lt;/code&gt; folder and a file named &lt;code&gt;ping-cli&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="nb"&gt;mkdir &lt;/span&gt;bin &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;touch &lt;/span&gt;bin/ping-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use &lt;code&gt;bash&lt;/code&gt; and the &lt;code&gt;minicli&lt;/code&gt; package to create our new tool. Start by using a shebang to load our new &lt;code&gt;ping-cli&lt;/code&gt; file in a &lt;code&gt;php&lt;/code&gt; environment, and add out opening &lt;code&gt;php&lt;/code&gt; tags.&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;#!/usr/bin/env php&lt;/span&gt;
&amp;lt;?php &lt;span class="nb"&gt;declare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;strict_types &lt;span class="o"&gt;=&lt;/span&gt; 1&lt;span class="o"&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 can omit &lt;code&gt;declare&lt;/code&gt; if you don't want strict typing.&lt;/p&gt;

&lt;p&gt;Before moving on to using &lt;code&gt;minicli&lt;/code&gt;, we must first make sure we're calling this file from the CLI. We do this with the &lt;code&gt;php_sapi_name&lt;/code&gt; functions, which returns the string of our current interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;php_sapi_name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'cli'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;exit&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;
  
  
  Integrating with MiniCLI.
&lt;/h2&gt;

&lt;p&gt;To integrate &lt;code&gt;minicli&lt;/code&gt; we include the &lt;code&gt;composer&lt;/code&gt; autoloader and instantiate a new &lt;code&gt;Minicli&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;We do this by establishing a new variable &lt;code&gt;$root&lt;/code&gt; to hold the parent directory of the directory &lt;code&gt;bin/ping-cli&lt;/code&gt;. Adding a check to see if we can grab the autoloader using that path. Should that operation be false, we will set the &lt;code&gt;$root&lt;/code&gt; to be &lt;code&gt;4&lt;/code&gt; levels up from our parent directory.&lt;/p&gt;

&lt;p&gt;This is done so that if our tool is required and is symlinked to &lt;code&gt;vendor/bin/ping-cli&lt;/code&gt;, we use the autoloader generated by the outside project correctly.&lt;/p&gt;

&lt;p&gt;Lastly we require the autoloader and instantiate a new &lt;code&gt;Minicli\App&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;is_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&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="k"&gt;require&lt;/span&gt; &lt;span class="nv"&gt;$root&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&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;Minicli\App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$app&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;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the CLI tool to run, we have to call the &lt;code&gt;runCommand&lt;/code&gt; method on our &lt;code&gt;$app&lt;/code&gt;. Add the following line to the end of our &lt;code&gt;ping-cli&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;runCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;$argv&lt;/code&gt; variable is a reserved variable provided to us by PHP, you can read more about it in the &lt;a href="https://php.net/manual/en/reserved.variables.argv.php" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Running our command now will output &lt;code&gt;./minicli help&lt;/code&gt; to the console, try it yourself by running the command.&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;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ping&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cli&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updating our CLI signature.
&lt;/h3&gt;

&lt;p&gt;Before embarking on the journey of creating the new command, let us first update our signature. This signature will replace the default &lt;code&gt;./minicli help&lt;/code&gt; signature ran when running our tool with no input.&lt;/p&gt;

&lt;p&gt;We set our new signature using the &lt;code&gt;setSignature&lt;/code&gt; method on the &lt;code&gt;minicli&lt;/code&gt; &lt;code&gt;$app&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setSignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;&amp;lt;&amp;lt;&amp;lt;EOD
           _                        ___ 
    ____  (_)___  ____ _      _____/ (_)
   / __ \/ / __ \/ __ `/_____/ ___/ / / 
  / /_/ / / / / / /_/ /_____/ /__/ / /  
 / .___/_/_/ /_/\__, /      \___/_/_/   
/_/            /____/ \e[0;32m Ver. 0.0.1

EOD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give us the following signature.&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%2Fraw.githubusercontent.com%2Fthinkverse%2Fping-cli%2Fmain%2Fassets%2Fcli-signature.png%3Ftoken%3DAAQ6NMWFSAKV2WPI74FGG3DAZNTOW" 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%2Fraw.githubusercontent.com%2Fthinkverse%2Fping-cli%2Fmain%2Fassets%2Fcli-signature.png%3Ftoken%3DAAQ6NMWFSAKV2WPI74FGG3DAZNTOW" alt="Screenshot of new CLI signature"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Registering our command.
&lt;/h2&gt;

&lt;p&gt;With the basic setup out-the-way, let's continue on by registering our &lt;code&gt;ping&lt;/code&gt; command. Since this tool will only have a single command, we will forgo registering a namespace and just register a single command with the &lt;code&gt;registerCommand&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;To register the command, we pass it the &lt;code&gt;name&lt;/code&gt; and the &lt;code&gt;callable&lt;/code&gt; which will get passed the &lt;code&gt;$input&lt;/code&gt;. For convenience we will also use the &lt;code&gt;$app&lt;/code&gt; in out &lt;code&gt;callable&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ping'&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;CommandCall&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPrinter&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;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'We have lift-off! 🚀'&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;Calling the &lt;code&gt;getPrinter&lt;/code&gt; method access the output handler, which we then use to print a &lt;code&gt;success&lt;/code&gt; message to the console.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;./bin/ping-cli ping&lt;/code&gt; will now print back &lt;em&gt;We have lift-off! 🚀&lt;/em&gt; in our console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating our command.
&lt;/h2&gt;

&lt;p&gt;With the command registered, let us move swiftly along to implementing our real &lt;code&gt;ping&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;This command will take a &lt;code&gt;url&lt;/code&gt; parameter, in either of &lt;em&gt;two&lt;/em&gt; formats, HTTP or HTTPS. With this parameter, we will send a request to the &lt;code&gt;url&lt;/code&gt; and see if it's accessible.&lt;/p&gt;

&lt;p&gt;To grab the parameter we call &lt;code&gt;getParam&lt;/code&gt; on our &lt;code&gt;$input&lt;/code&gt; and specify which parameter we want. Let's store our &lt;code&gt;url&lt;/code&gt; parameter in a &lt;code&gt;$url&lt;/code&gt; variable, or default to &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With this we can sent a &lt;code&gt;error&lt;/code&gt; output using &lt;code&gt;getPrinter&lt;/code&gt; and exit early if no &lt;code&gt;url&lt;/code&gt; was provided.&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;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getParam&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="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;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;$url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPrinter&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Parameter &amp;lt;url&amp;gt; was not provided'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&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 can continue on and validate the incoming &lt;code&gt;$url&lt;/code&gt; parameter. To do that we will use RegEx and &lt;code&gt;filter_var&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We first check for a valid URL - since URLs can be valid even without the HTTP protocol, we add this check first. Returning early is the check fails.&lt;/p&gt;

&lt;p&gt;Next we use RegEx to check if the &lt;code&gt;$url&lt;/code&gt; provided starts with a valid HTTP(s) protocol. Returning early with a message if that fails.&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="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;filter_var&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="no"&gt;FILTER_VALIDATE_URL&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPrinter&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Parameter &amp;lt;url&amp;gt; not a valid URL.'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&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="nb"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'#^https?://#i'&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="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPrinter&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Parameter &amp;lt;url&amp;gt; has to include a valid HTTP protocol.'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this isn't the end-all be-all of validating the &lt;code&gt;$url&lt;/code&gt;, it'll do for a simple ping command.&lt;/p&gt;

&lt;h2&gt;
  
  
  A streaming context
&lt;/h2&gt;

&lt;p&gt;Before we try and access the &lt;code&gt;$url&lt;/code&gt; provided, we need to create a stream context for &lt;code&gt;file_get_contents&lt;/code&gt; to use. In this context we will set the HTTP method and some HTTP headers.&lt;/p&gt;

&lt;p&gt;To keep things a bit separated, let's create a new function called &lt;code&gt;getStreamContext&lt;/code&gt; where we'll create our new context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getStreamContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'Accept: text/html,application/xhtml+xml,application/xml;q=0.9'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'Accept-Language: en-US,en;q=0.9'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'Upgrade-Insecure-Requests: 1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'X-Application: PingCLI/0.0.1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'Sec-GPC: 1'&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="nb"&gt;stream_context_create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'http'&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;'method'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="s1"&gt;'header'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$headers&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;We set some headers so the &lt;code&gt;$url&lt;/code&gt; we're accessing thinks the site is being used from a Chrome browser running on a Mac.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finishing up the command.
&lt;/h2&gt;

&lt;p&gt;With the context created we can now use &lt;code&gt;file_get_contents&lt;/code&gt; to ping the &lt;code&gt;$url&lt;/code&gt;. Since we won't use the returning content for anything, we can use &lt;code&gt;file_get_contents&lt;/code&gt; directly in our if statement.&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="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;file_get_contents&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="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getStreamContext&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPrinter&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Parameter &amp;lt;url&amp;gt; could not be reached.'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&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 reasoning being the silencing (@) is because we can provide a valid URL that &lt;code&gt;file_get_contents&lt;/code&gt; might not be able to access, that will give of warnings unless silenced.&lt;/p&gt;

&lt;p&gt;If all those checks are cleared, we can safely assume the site is reachable and up. Let's give the user an indication the site was reached by adding the following code to the end of our &lt;code&gt;callable&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPrinter&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;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'URL &amp;lt;%s&amp;gt; is up.'&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;p&gt;We can now test our ping command by running the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/ping-cli ping &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://devdojo.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce the following 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%2Fraw.githubusercontent.com%2Fthinkverse%2Fping-cli%2Fmain%2Fassets%2Fcli-successful-ping.png%3Ftoken%3DAAQ6NMUNCOZM3BKTW3YDNY3AZOCRQ" 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%2Fraw.githubusercontent.com%2Fthinkverse%2Fping-cli%2Fmain%2Fassets%2Fcli-successful-ping.png%3Ftoken%3DAAQ6NMUNCOZM3BKTW3YDNY3AZOCRQ" alt="Screenshot of successful ping"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending our command.
&lt;/h2&gt;

&lt;p&gt;Before I leave you, I'd like to add one more feature to our command. That's the estimated ping time, which is an estimate of how long it took to access the website.&lt;/p&gt;

&lt;p&gt;We'll do this with the &lt;code&gt;microtime&lt;/code&gt; function and some subtraction. We'll Add the following right above our &lt;code&gt;file_get_contents&lt;/code&gt; check.&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;$start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;microtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as_float&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;Below our if, and before we output our success message we add the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;microtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as_float&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;These two variables will now be used to estimate how long it took to access the site. Since they're places in between &lt;code&gt;file_get_contents&lt;/code&gt; we should get a fairly close estimate.&lt;/p&gt;

&lt;p&gt;Let's print that estimate to our user below out success output.&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;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPrinter&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;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Est. ping time: %.02f sec'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$end_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$start_time&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will now add an estimated ping time to the end of our output, as displayed below.&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%2Fraw.githubusercontent.com%2Fthinkverse%2Fping-cli%2Fmain%2Fassets%2Fcli-estimated-time.png%3Ftoken%3DAAQ6NMQKJY3F3KLND7XG7XLAZOEFW" 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%2Fraw.githubusercontent.com%2Fthinkverse%2Fping-cli%2Fmain%2Fassets%2Fcli-estimated-time.png%3Ftoken%3DAAQ6NMQKJY3F3KLND7XG7XLAZOEFW" alt="Screenshot of estimated time"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;This is how you can create a simple CLI tool with the help of &lt;a href="https://github.com/minicli/minicli" rel="noopener noreferrer"&gt;MiniCLI&lt;/a&gt;. You can read up more about &lt;code&gt;minicli&lt;/code&gt; on their &lt;a href="https://github.com/minicli/minicli" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; page, or their &lt;a href="https://docs.minicli.dev/en/latest/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, also follow the creator Erika Heidi on &lt;a href="https://twitter.com/erikaheidi" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's all for me folks, thank you for reading. 👋&lt;/p&gt;

&lt;p&gt;Complete source available on my &lt;code&gt;ping-cli&lt;/code&gt; &lt;a href="https://github.com/thinkverse/ping-cli" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting.
&lt;/h2&gt;

&lt;p&gt;If you're having issues running your new CLI tool, make sure the permissions are turned on to use the file as an executable. On Linux system this can be done with &lt;code&gt;chmod&lt;/code&gt;, use the equivalent command for windows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping-cli ~ &lt;span class="nb"&gt;chmod&lt;/span&gt; +x bin/ping-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>php</category>
      <category>cli</category>
      <category>tutorial</category>
      <category>minicli</category>
    </item>
    <item>
      <title>The future of Responsive Design with Container Queries.</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Sat, 22 May 2021 09:42:56 +0000</pubDate>
      <link>https://forem.com/thinkverse/the-future-of-responsive-design-with-container-queries-26d0</link>
      <guid>https://forem.com/thinkverse/the-future-of-responsive-design-with-container-queries-26d0</guid>
      <description>&lt;p&gt;When we write responsive design using CSS today, we use the &lt;code&gt;media&lt;/code&gt; at-rule, more commonly known as a &lt;em&gt;Media Query&lt;/em&gt;. This at-rule queries the device or user-agent to grab the values it needs for our media condition. That condition can be a multitude of conditions based on the provided media type or media feature.&lt;/p&gt;

&lt;p&gt;One thing that &lt;code&gt;media&lt;/code&gt; cannot do sadly, is query DOM elements directly. This is where the &lt;code&gt;container&lt;/code&gt; at-rule proposal from &lt;a href="https://www.miriamsuzanne.com/who/"&gt;Miriam Suzanne&lt;/a&gt; comes in. A new at-rule specification that is currently being proposed, affectionately called &lt;em&gt;Container Query Proposal&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The TL:DR; version of this proposal is to query an elements parent container for context based dimensions instead of the viewport dimensions. For instance if the parent container has a &lt;code&gt;min-width: n&lt;/code&gt; do the following.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to test the new at-rule.
&lt;/h3&gt;

&lt;p&gt;Currently, there is only one browser that has released a prototype for the proposed specification and that is Chrome. Available in their nightly build - Chrome Canary, under the flag &lt;em&gt;“CSS Container Queries”&lt;/em&gt;. Here are the steps on how to enable the flag.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download &lt;a href="https://www.google.com/chrome/canary/"&gt;Chrome Canary&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;chrome://flags&lt;/code&gt; in the URL bar.&lt;/li&gt;
&lt;li&gt;Search for &lt;em&gt;“CSS Container Queries”&lt;/em&gt;, enable the feature.&lt;/li&gt;
&lt;li&gt;Restart the browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://www.miriamsuzanne.com/who/"&gt;Miriam&lt;/a&gt;, the author of the proposal has a put together a &lt;a href="https://codepen.io/collection/XQrgJo"&gt;CodePen collection&lt;/a&gt; of &lt;em&gt;Container Queries&lt;/em&gt; demos for your testing pleasure. For more information on  &lt;em&gt;Container Queries&lt;/em&gt;, I recommend reading &lt;a href="https://www.miriamsuzanne.com/2021/05/02/container-queries/"&gt;Container Queries Explainer &amp;amp; Proposal&lt;/a&gt; also written by the proposals author.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Container.
&lt;/h3&gt;

&lt;p&gt;To make &lt;em&gt;Container Queries&lt;/em&gt; work, we need to have a &lt;code&gt;container&lt;/code&gt; available to query. That is done by creating a &lt;code&gt;container&lt;/code&gt;. For that we use the CSS &lt;code&gt;contain&lt;/code&gt; property along with the &lt;code&gt;layout&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;selector&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="n"&gt;inline-size&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 &lt;code&gt;size&lt;/code&gt; value &lt;code&gt;inline-size&lt;/code&gt; uses the inline-axis on the container. A quick note here, there is a &lt;code&gt;block-size&lt;/code&gt; in the prosposal. That is currently &lt;strong&gt;not available&lt;/strong&gt; in the Chrome prototype, there is still a discussion if this axis is even needed so keep that in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Container Queries.
&lt;/h3&gt;

&lt;p&gt;With a new &lt;code&gt;container&lt;/code&gt; established, we can now query for it using the &lt;code&gt;container&lt;/code&gt; at-rule.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@container&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;container-query-list&lt;/span&gt;&lt;span class="err"&gt;&amp;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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;stylesheet&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the proposed syntax, similar to &lt;code&gt;@media&lt;/code&gt; except it uses &lt;code&gt;@container&lt;/code&gt; instead. Your &lt;code&gt;&amp;lt;container-query-list&amp;gt;&lt;/code&gt; uses queries based on the &lt;code&gt;containment context&lt;/code&gt; i.e &lt;code&gt;min-width&lt;/code&gt;, &lt;code&gt;max-width&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt; etc, similar to &lt;em&gt;Media Queries&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;stylesheet&amp;gt;&lt;/code&gt; will now be responsive to the nearest ancestor container  if finds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@container (min-width: n) {
    selector {
        display: none;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example for instance, will set the &lt;code&gt;display&lt;/code&gt; to &lt;code&gt;none&lt;/code&gt; for the given &lt;code&gt;selector&lt;/code&gt;, when it finds an ancestor container that matched the provided &lt;em&gt;Container Query&lt;/em&gt; &lt;code&gt;min-width&lt;/code&gt; of &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  More examples.
&lt;/h3&gt;

&lt;p&gt;That will be our brief overview of the &lt;em&gt;Container Query Proposal&lt;/em&gt;. For more examples of &lt;em&gt;Container Queries&lt;/em&gt;, I recommend watching &lt;a href="https://twitter.com/una"&gt;Una Kravets&lt;/a&gt; talk; &lt;a href="https://web.dev/new-responsive/"&gt;The new responsive: Web design in a component-driven world&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/channel/UCJZv4d5rbIKd4QHMPkcABCw"&gt;Kevin Powell&lt;/a&gt; video; &lt;a href="https://www.youtube.com/watch?v=JsN_iE3prm0"&gt;Container Queries are going to be a game changer!&lt;/a&gt; and, of course. Take a peek at the &lt;a href="https://github.com/w3c/csswg-drafts/issues/5796"&gt;proposal&lt;/a&gt; itself.&lt;/p&gt;

</description>
      <category>css</category>
      <category>experimental</category>
      <category>responsive</category>
      <category>mediaqueries</category>
    </item>
    <item>
      <title>You don’t necessarily need Composer</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Sat, 15 May 2021 22:49:39 +0000</pubDate>
      <link>https://forem.com/thinkverse/you-don-t-necessarily-need-composer-n71</link>
      <guid>https://forem.com/thinkverse/you-don-t-necessarily-need-composer-n71</guid>
      <description>&lt;p&gt;Don't get me wrong, &lt;a href="https://getcomposer.org/"&gt;Composer&lt;/a&gt; is an amazing product. It has an easy-to-use API for quick autoloading, supports multiple standards, and has autoloading optimization built-in - it even lets you search and require packages easily. It's a reason Composer is the most used package manager for PHP.&lt;/p&gt;

&lt;p&gt;If your project is a lightweight OOP project with no external packages though. Using Composer might be a bit overkill, you could easily implement autoloading using a simple &lt;code&gt;array&lt;/code&gt; and PHP's &lt;code&gt;spl_autoload_register&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;For those not familiar, &lt;code&gt;spl_autoload_register&lt;/code&gt; is what we can use to add to our own autoloading function to PHPs autoloading queue. We can use that together with a simple &lt;code&gt;array $classmap&lt;/code&gt; to autoload our small project. Here's our project structure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/public/index.php&lt;/li&gt;
&lt;li&gt;/src/*&lt;em&gt;/&lt;/em&gt;.php&lt;/li&gt;
&lt;li&gt;autoload.php&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;/public&lt;/code&gt; will be our front-facing entry point, &lt;code&gt;/src&lt;/code&gt; will hold our classes, and &lt;code&gt;autoload.php&lt;/code&gt; will handle our autoloading. Our classes will be formatted in PSR-4, with our vendor namespace prefix being used as the key for our internal &lt;code&gt;$classmap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's create our &lt;code&gt;autoload.php&lt;/code&gt; file and add some autoloading to our project.&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="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PHPNEXUS_VERSION'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0.0.1'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$classmap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'PHPNexus'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;'/src/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nb"&gt;spl_autoload_register&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;string&lt;/span&gt; &lt;span class="nv"&gt;$classname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$classmap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'\\'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$classname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$namespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$classfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;array_key_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$classmap&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="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$classmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$namespace&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="no"&gt;DIRECTORY_SEPARATOR&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$classfile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;class_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$classname&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going over our code shows we first define a new &lt;strong&gt;constant&lt;/strong&gt; - &lt;code&gt;PHPNEXUS_VERSION&lt;/code&gt;, this will be used to check if our autoload file has already been loaded later. &lt;code&gt;$classmap&lt;/code&gt; is an associative array - as previously mentioned our vendor namespace is our key. The value of which is the location to our source files, in this case, that is &lt;code&gt;/src&lt;/code&gt;. And since &lt;code&gt;autoloading.php&lt;/code&gt; is in our root, we can take advantage of the &lt;code&gt;__DIR__&lt;/code&gt; constant.&lt;/p&gt;

&lt;p&gt;The first argument of &lt;code&gt;spl_autoload_register&lt;/code&gt; is the callback function - that's our autoloading function. That function will take a string parameter - when you instantiate a class with &lt;code&gt;new&lt;/code&gt;, the FQCN gets passed as that parameter's argument.&lt;/p&gt;

&lt;p&gt;Next, we are destructuring our &lt;code&gt;$classname&lt;/code&gt; argument by separating each value into an &lt;code&gt;array $parts&lt;/code&gt; variable. Since we know our first &lt;code&gt;$parts&lt;/code&gt; value is our vendor namespace, we use &lt;code&gt;array_shift&lt;/code&gt; to grab it and use &lt;code&gt;array_pop&lt;/code&gt; to grab the actual filename since we also know that's the last part of our &lt;code&gt;$classname&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We then do a quick check to see if the &lt;code&gt;$namespace&lt;/code&gt; is in our &lt;code&gt;$classmap&lt;/code&gt; so we can handle the file location, if that's not the case we simply do an early return out of the function. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$path&lt;/code&gt; will be the variable holding the remaining parts of our &lt;code&gt;$parts&lt;/code&gt; array, since the filename and namespace are already removed, we can assume the rest of the pieces are the rest of our file path.&lt;/p&gt;

&lt;p&gt;We then reassemble our file path info into a temporary &lt;code&gt;$file&lt;/code&gt; variable and check if that file exists. As a precaution, we also include a check to see if the class has already been defined. If either fails - as before, we return out of the function and be on our merry way.&lt;/p&gt;

&lt;p&gt;Lastly, if nothing fails all we do is require the &lt;code&gt;$file&lt;/code&gt; that contains our class so PHP can now initialize it.&lt;/p&gt;

&lt;p&gt;To then use our simple autoloading file, in our &lt;code&gt;public/index.php&lt;/code&gt; we simply add the following if statement.&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="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PHPNEXUS_VERSION'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/autoload.php'&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 does a check for the earlier constant to see if the file has already been included or required earlier, if that fails we require our &lt;code&gt;autoload.php&lt;/code&gt; file and now we can use our classes, e.g. if we had a &lt;code&gt;PHPNexus\Request\Request&lt;/code&gt; class located in &lt;code&gt;/src/Request/Request&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PHPNEXUS_VERSION'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&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;PHPNexus\Request\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's how we can create simple autoloading for our project without having to rely on Composer. As mentioned above though, if your project already requires packages from other sources via Composer, then it's best to stick with Composers autoloader instead.&lt;/p&gt;

&lt;p&gt;To leave off, have you ever written your own function to handle autoloading before? Perhaps you didn't know how to do it and you know do, let me know by replying to the topic. Would love to hear your thought on implementing simple autoloading for projects.&lt;/p&gt;

</description>
      <category>php</category>
      <category>composer</category>
    </item>
    <item>
      <title>Laravel Quickie: Basic Controllers</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Wed, 02 Dec 2020 06:33:35 +0000</pubDate>
      <link>https://forem.com/thinkverse/laravel-quickie-basic-controllers-4jdj</link>
      <guid>https://forem.com/thinkverse/laravel-quickie-basic-controllers-4jdj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to &lt;strong&gt;Laravel Quickie&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;In this section, we will go over the two basic controllers used in Laravel. The regular controller and the single-action controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;If you don't already have a Laravel project up and running. I'd suggest using a DigitalOcean Ubuntu Droplet. Use my affiliate code to get &lt;a href="https://m.do.co/c/646e3da9d160"&gt;free $100 DigitalOcean credit over 60 days&lt;/a&gt; to spin up your own server!&lt;/p&gt;

&lt;p&gt;If you do not have that yet. You can follow the &lt;a href="https://devdojo.com/bobbyiliev/how-to-install-laravel-on-digitalocean-with-1-click"&gt;How to Install Laravel on DigitalOcean with 1-Click&lt;/a&gt; tutorial on how to do set that up.&lt;/p&gt;

&lt;p&gt;Alternatively, you could use the awesome &lt;a href="https://devdojo.com/episode/laravel-on-digital-ocean-with-larasail"&gt;LaraSail&lt;/a&gt; script to do the installation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regular Controller
&lt;/h2&gt;

&lt;p&gt;The regular controller. A simple controller that is used in every Laravel application. Usually extending the &lt;code&gt;BaseController&lt;/code&gt; that comes with a new Laravel project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Controller
&lt;/h3&gt;

&lt;p&gt;To generate a regular controller instead of creating one manually you can use the following &lt;code&gt;artisan&lt;/code&gt; 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:controller &lt;span class="o"&gt;{&lt;/span&gt;name&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will generate a blank controller with the given name argument; for instance.&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:controller ProductController
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will generate a blank &lt;code&gt;ProductController&lt;/code&gt; class located under &lt;code&gt;app/Http/Controllers&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&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;ProductController&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="c1"&gt;//&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use Controller
&lt;/h3&gt;

&lt;p&gt;To use our newly created controller we need to give it a method we can access somewhere in our code, our &lt;code&gt;routes/web.php&lt;/code&gt; perhaps.&lt;/p&gt;

&lt;p&gt;Let's add a quick public &lt;code&gt;index()&lt;/code&gt; method on our new &lt;code&gt;ProductController&lt;/code&gt;. We can return Laravel's default &lt;code&gt;welcome&lt;/code&gt; view.&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;ProductController&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;index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;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;'welcome'&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 that our controller has been updated. We can update the route file to &lt;strong&gt;use&lt;/strong&gt; that instead of returning the view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Route&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\ProductController&lt;/span&gt;&lt;span class="p"&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;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;ProductController&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;'index'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Single Action Controller
&lt;/h2&gt;

&lt;p&gt;Now a &lt;code&gt;ProductController&lt;/code&gt; isn't really the place to return a &lt;em&gt;welcome&lt;/em&gt; view from. That sounds like a single action. And that's a perfect way to use invokable controllers.&lt;/p&gt;

&lt;p&gt;An invokable controller is a single action - or method, controller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Controller
&lt;/h3&gt;

&lt;p&gt;We can use &lt;code&gt;artisan&lt;/code&gt; to create those controllers as well using the &lt;code&gt;--invokable&lt;/code&gt; flag. Let's generate a single action controller to return our view instead.&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:controller WelcomeController &lt;span class="nt"&gt;--invokable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This type of controller comes with a php magic method called &lt;code&gt;__invoke&lt;/code&gt;. The method in question gets &lt;a href="https://www.php.net/manual/en/language.oop5.magic.php#object.invoke"&gt;called whenever the class is called as a function&lt;/a&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="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&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;WelcomeController&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="cd"&gt;/**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */&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="c1"&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;
  
  
  Use Controller
&lt;/h3&gt;

&lt;p&gt;Now we can move the return view statement to that controller instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&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;WelcomeController&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="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;'welcome'&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 our controllers look mostly the same except for the method signature. You might think we call this by simply adding &lt;code&gt;__invoke&lt;/code&gt; as the second array value.&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;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;WelcomeController&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;'__invoke'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While that works. There an even cleaner and shorter way to use single-action controllers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Route&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\WelcomeController&lt;/span&gt;&lt;span class="p"&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;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;WelcomeController&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Controller Parameters
&lt;/h2&gt;

&lt;p&gt;Let's finish by talking a bit about parameters.&lt;br&gt;
Used to pass information to our controller. The most basic usage is for URL parameters and the current incoming &lt;code&gt;Request&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;As you've most likely noticed all generated controllers come with the &lt;code&gt;Request&lt;/code&gt; already &lt;a href="https://www.php.net/manual/en/language.namespaces.importing.php"&gt;imported using the &lt;strong&gt;use&lt;/strong&gt; keyword&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's add a new &lt;code&gt;public show()&lt;/code&gt; method to our &lt;code&gt;ProductController&lt;/code&gt; that takes that &lt;code&gt;Request&lt;/code&gt; and a &lt;code&gt;$product&lt;/code&gt; as parameters.&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;ProductController&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;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&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;We can now update our routes yet again and add a new &lt;code&gt;/products/{product}&lt;/code&gt; route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Route&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\WelcomeController&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\ProductController&lt;/span&gt;&lt;span class="p"&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;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;WelcomeController&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="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;'/products/{product}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;ProductController&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most others might use &lt;code&gt;{id} here. But by using&lt;/code&gt;{product}` instead, illustrates the point that the name you give the route parameter will be the name of the controller parameter.&lt;/p&gt;

&lt;p&gt;To see the arguments passed to the parameters. We use Laravel's built-in die dump function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;php&lt;br&gt;
class ProductController extends Controller&lt;br&gt;
{&lt;br&gt;
    public function show(Request $request, string $product)&lt;br&gt;
    {&lt;br&gt;
        dd($product, $request);&lt;br&gt;
    }&lt;br&gt;
}&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Passing our two arguments into the die dump function will give you similar output to this when visiting &lt;code&gt;/products/laravel-quickie&lt;/code&gt; in a browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_dbFb1c---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JluPjQX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_dbFb1c---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JluPjQX.png" alt="Screen shot of die dump output" width="770" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same would work for a single-action controller too, just add your parameters to the &lt;code&gt;__invoke()&lt;/code&gt; method, and use it as a regular controller method.&lt;/p&gt;

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

&lt;p&gt;I hope this little quickie answers any questions you have about basic controllers. And, as always, code is available on &lt;a href="https://github.com/thinkverse/"&gt;my GitHub&lt;/a&gt; under the &lt;a href="https://github.com/thinkverse/laravel-quickie"&gt;/laravel-quickie repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this section take a gander under the &lt;a href="https://github.com/thinkverse/laravel-quickie/tree/quickie-basic-controllers"&gt;quickie-basic-controllers branch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading and, till next time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Note
&lt;/h4&gt;

&lt;p&gt;The last code block won't render correctly, but as stated above. The code is available in the repository.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Laravel Quickie: How to install and build TailwindCSS v2 with Laravel Mix 😎</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Mon, 30 Nov 2020 17:28:17 +0000</pubDate>
      <link>https://forem.com/thinkverse/laravel-quickie-how-to-install-and-build-tailwindcss-v2-with-laravel-mix-3k81</link>
      <guid>https://forem.com/thinkverse/laravel-quickie-how-to-install-and-build-tailwindcss-v2-with-laravel-mix-3k81</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to another &lt;strong&gt;Laravel Quickie&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;In this quickie, we will go over how to install and build &lt;a href="https://blog.tailwindcss.com/tailwindcss-v2" rel="noopener noreferrer"&gt;TailwindCSS v2&lt;/a&gt; with the help of &lt;a href="https://laravel-mix.com/" rel="noopener noreferrer"&gt;Laravel Mix&lt;/a&gt;. If you've already tried and have run into issues, hopefully, this post will solve those issues for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;If you don't already have a Laravel project up and running. I'd suggest using a DigitalOcean Ubuntu Droplet. Use my affiliate code to get &lt;a href="https://m.do.co/c/646e3da9d160" rel="noopener noreferrer"&gt;free $100 DigitalOcean credit over 60 days&lt;/a&gt; to spin up your own server!&lt;/p&gt;

&lt;p&gt;If you do not have that yet. You can follow the &lt;a href="https://devdojo.com/bobbyiliev/how-to-install-laravel-on-digitalocean-with-1-click" rel="noopener noreferrer"&gt;How to Install Laravel on DigitalOcean with 1-Click&lt;/a&gt; tutorial on how to do set that up.&lt;/p&gt;

&lt;p&gt;Alternatively, you could use the awesome &lt;a href="https://devdojo.com/episode/laravel-on-digital-ocean-with-larasail" rel="noopener noreferrer"&gt;LaraSail&lt;/a&gt; script to do the installation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current issues
&lt;/h2&gt;

&lt;p&gt;Before we go on with the installation and building of TailwindCSS v2, let's go over some of the current issues that arise when installing TailwindCSS v2 into an existing project running Laravel Mix v5.&lt;/p&gt;

&lt;p&gt;With the newest version on TailwindCSS v2. They've upped their PostCSS dependency to ones compatible with PostCSS 8, being a relatively new version. Most tools haven't yet updated, as explained in their documentation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Tailwind CSS depends on PostCSS 8. Because PostCSS 8 is only a few months old, many other tools in the ecosystem haven't updated yet"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So with that in mind, let's go over installing TailwindCSS v2 with Laravel Mix 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailwind v2 and Laravel Mix 5
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setup a test view
&lt;/h3&gt;

&lt;p&gt;Let's start with setting up a test view that will contain code from TailwindCSS v2 so we can test if we've successfully built it correctly.&lt;/p&gt;

&lt;p&gt;If you're following along with a new Laravel project, you can open your default &lt;code&gt;welcome.blade.php&lt;/code&gt; file and update accordingly.&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;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"{{ str_replace('_', '-', app()-&amp;gt;getLocale()) }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Laravel&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ mix('/css/app.css') }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"antialiased"&lt;/span&gt;&lt;span class="nt"&gt;&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;"flex items-center min-h-screen pl-20 bg-gray-100 dark:bg-gray-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-black text-9xl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                Welcome to &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-transparent bg-clip-text bg-gradient-to-tr from-blue-700 to-indigo-400"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;TailwindCSS v2&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/h1&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;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet of code introduces the new &lt;code&gt;text-9xl&lt;/code&gt; class from TailwindCSS v2. Opening this in our browser should result in the following exception; &lt;strong&gt;The Mix manifest does not exist. (View: /./resources/views/welcome.blade.php)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With our test view out of the way let's install TailwindCSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing TailwindCSS
&lt;/h3&gt;

&lt;p&gt;To install TailwindCSS v2 you need only run the following command.&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;tailwindcss &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install the latest version of TailwindCSS as a developer dependency.&lt;/p&gt;

&lt;p&gt;We can now update our &lt;code&gt;webpack.mix.js&lt;/code&gt; file and our &lt;code&gt;/resources/css/app.css&lt;/code&gt; file to include TailwindCSS v2.&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;mix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postCss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/css/app.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&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 now run our development build process and see what happens when we try and build.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Whoops! While Laravel Mix starts to build - it even downloads a new dev dependency in &lt;code&gt;vue-template-compiler&lt;/code&gt;. In the end, it fails due to our incompatibility with the current version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PostCSS plugin tailwindcss requires PostCSS 8.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the issue I was talking about in the beginning, while I explained it. It's always best to see it in action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's solve the build
&lt;/h3&gt;

&lt;p&gt;We can solve this build issue rather simply. Let's first uninstall our current TailwindCSS dependency.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Thankfully the amazing developers over at TailwindLabs have released a compatible version. So let's install that instead.&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;tailwindcss@npm:@tailwindcss/postcss7-compat &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a version installed that's compatible with Laravel Mix 5, we can now run our build process again.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&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.imgur.com%2FZEDPG4D.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.imgur.com%2FZEDPG4D.png" alt="Screen shot of successful build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Success!&lt;/strong&gt; You have now successfully build TailwindCSS v2 with Laravel Mix 5! 🎉&lt;/p&gt;

&lt;p&gt;Going to our page now - if you've followed along, should look similar to 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.imgur.com%2FKtoyHI6.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.imgur.com%2FKtoyHI6.png" alt="Screen shot of our page with the text welcome to tailwind CSS v 2 in bold"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TailwindCSS v2 and Laravel Mix 6 Beta
&lt;/h2&gt;

&lt;p&gt;You've successfully build TailwindCSS v2 already with Laravel Mix 5. But if you'd like to use Laravel Mix 6 - which is currently in its beta stage and is running PostCSS 8. We will have to uninstall some dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm uninstall tailwindcss laravel-mix vue-template-compiler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to install the Laravel Mix 6 beta and the latest version of TailwindCSS.&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;tailwindcss laravel-mix@next &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might see some resolve errors in your console about overriding dependencies. They shouldn't give you any problems, and the installation should work just fine.&lt;/p&gt;

&lt;p&gt;Now we can run our development build as before.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&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.imgur.com%2FOQXBAfd.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.imgur.com%2FOQXBAfd.png" alt="Screen shot of successful build using Laravel Mix 6 beta"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, you've successfully installed and built using the Laravel Mix 6 beta. 🎉&lt;/p&gt;

&lt;p&gt;Going to our page now - if you've followed along, should look similar to 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.imgur.com%2F4l9ynuV.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.imgur.com%2F4l9ynuV.png" alt="Screen shot of our page with the text welcome to tailwind CSS v 2 in bold"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Production build
&lt;/h3&gt;

&lt;p&gt;To run a production build with Laravel Mix 6 you need to update your build script a bit.&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm run production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --config=node_modules/laravel-mix/setup/webpack.config.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, you can not run your production build using.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus: Purging with TailwindCSS
&lt;/h2&gt;

&lt;p&gt;As I mention production runs, let me show you how to purge your CSS classes to not make your production build too large. This will for both versions.&lt;/p&gt;

&lt;p&gt;First - if you haven't generated your &lt;code&gt;tailwind.config.js&lt;/code&gt; file yet. Let's run the following command at the root of our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tailwindcss init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this file generated, we can add the resources we want TailwindCSS to purge on a production run by updating the &lt;code&gt;purge&lt;/code&gt; array.&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;purge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/views/**/*.blade.php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/**/*.js&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="na"&gt;darkMode&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="c1"&gt;// or 'media' or 'class'&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&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;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&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;plugins&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;TailwindCSS will look for the &lt;code&gt;tailwind.config.js&lt;/code&gt; file in the root of your project by default, so you're not required to pass it in as you did in the past.&lt;/p&gt;

&lt;p&gt;But if you want to do that just update your &lt;code&gt;webpack.mix.js&lt;/code&gt; file in the following way.&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;mix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postCss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/css/app.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./tailwind.config.js&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this next time you run &lt;code&gt;npm run prod&lt;/code&gt; TailwindCSS will use PurgeCSS to remove unused CSS classes. &lt;/p&gt;

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

&lt;p&gt;There you have it, two ways to install and build TailwindCSS v2 in Laravel with the help of Laravel Mix 5 and, 6 beta.&lt;/p&gt;

&lt;p&gt;I hope that helped you in some way, and as before. Till next time.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL:DR; Show me code
&lt;/h3&gt;

&lt;p&gt;Like most of my articles, the code is available publicly on &lt;a href="https://github.com/thinkverse" rel="noopener noreferrer"&gt;my GitHub&lt;/a&gt;, the following article can be found in the repository named &lt;a href="https://github.com/thinkverse/tailwind-and-laravel-mix" rel="noopener noreferrer"&gt;/tailwind-and-laravel-mix&lt;/a&gt;, separated into a master branch and another called &lt;a href="https://github.com/thinkverse/tailwind-and-laravel-mix/tree/laravel-mix-beta" rel="noopener noreferrer"&gt;laravel-mix-beta&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will find the Laravel Mix 5 version in the master and the latter in the beta branch.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>css</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Useful HTML codes with a quick click. 👍</title>
      <dc:creator>Kim Hallberg</dc:creator>
      <pubDate>Fri, 06 Nov 2020 09:20:47 +0000</pubDate>
      <link>https://forem.com/thinkverse/useful-html-codes-with-a-quick-click-opi</link>
      <guid>https://forem.com/thinkverse/useful-html-codes-with-a-quick-click-opi</guid>
      <description>&lt;p&gt;Just found out that we can use HTML codes to create arrows - e.g. a right-pointing arrow &lt;em&gt;"→"&lt;/em&gt;. There are a lot of useful HTML codes out there. Here is a quick CodePen of some I think might be useful. 😀&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/Thinkverse/embed/PozdwyX?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>codepen</category>
      <category>webdev</category>
      <category>todayilearned</category>
    </item>
  </channel>
</rss>
