<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicolus</title>
    <description>The latest articles on DEV Community by Nicolus (@nicolus).</description>
    <link>https://dev.to/nicolus</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%2F103407%2Ffa672262-a9a9-440c-a6c8-1c040dec5c8a.png</url>
      <title>DEV Community: Nicolus</title>
      <link>https://dev.to/nicolus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nicolus"/>
    <language>en</language>
    <item>
      <title>5 essential tools for Laravel development</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sat, 17 Aug 2024 15:45:36 +0000</pubDate>
      <link>https://dev.to/nicolus/5-essential-tools-for-laravel-development-1b9</link>
      <guid>https://dev.to/nicolus/5-essential-tools-for-laravel-development-1b9</guid>
      <description>&lt;p&gt;Everyone loves a listicle right ? So here's one to give a shout out to my favorite tools for PHP/Laravel development &lt;/p&gt;

&lt;h2&gt;
  
  
  Xdebug
&lt;/h2&gt;

&lt;p&gt;(Free) &lt;a href="https://xdebug.org/" rel="noopener noreferrer"&gt;https://xdebug.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This one is really important to me. I know a lot of people will be happy&lt;br&gt;
 with throwing a &lt;code&gt;dd()&lt;/code&gt; around when needed and really don't feel like they need a debugger. I wouldn't go as far as to say they're wrong, but I just can't work like that : I need to be able to stop execution anywhere in the code and then inspect the state of every variable, or even change a value before resuming or call a couple of methods from the console to see what happens. This can save you from changing a &lt;code&gt;dd()&lt;/code&gt; and restarting the script dozens of times.&lt;/p&gt;

&lt;p&gt;I also find that it's particularly useful in conjunction with Unit Tests : Most of the time I'll run my tests in debug mode and go through the code line by line to make sure everything is going according to plan. In this case I'm not using the debugger to track a bug, just as part of my normal workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clockwork
&lt;/h2&gt;

&lt;p&gt;(Free) &lt;a href="https://underground.works/clockwork/" rel="noopener noreferrer"&gt;https://underground.works/clockwork/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is another tool that's really useful when developing, it provides a toolbar right in your browser's developer tools that will give you insight as to what happened during each request : Logs, which controller was called, which middlewares, how many database queries, how many cache hits and miss, RAM usage for the request and so on.&lt;/p&gt;

&lt;p&gt;I find the most useful part is the Database panel that allows you to see each SQL query that was made (with the parameters already replaced) and how much time it took. It makes it really easy to notice n+1 issues or to find out which query is taking longer than it should.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mailpit
&lt;/h2&gt;

&lt;p&gt;(Free) &lt;a href="https://mailpit.axllent.org/" rel="noopener noreferrer"&gt;https://mailpit.axllent.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mailpit is basically a "fake" SMTP server that instead of actually sending emails will display them in a web UI. This is invaluable for testing locally or in staging because it allows you to test things out without ever risking sending an actual email to a user, while still using actual email addresses in order to check that the recipients, Cc, Bcc are the correct ones.&lt;/p&gt;

&lt;p&gt;It's packed with useful features like tagging mails from custom headers, checking links, checking the spam assassin score for your emails, and compatibility with many email clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  PhpStorm
&lt;/h2&gt;

&lt;p&gt;(Paid) &lt;a href="https://www.jetbrains.com/phpstorm/" rel="noopener noreferrer"&gt;https://www.jetbrains.com/phpstorm/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You probably know PhpStorm already, I'm adding it to that list because it's definitely one of my favorite tools. It is paid, and it is a little heavy and slow compared to a simple text editor, but it provides so many useful features that it's totally worth it for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Laravel Idea
&lt;/h2&gt;

&lt;p&gt;(Paid) &lt;a href="https://laravel-idea.com/" rel="noopener noreferrer"&gt;https://laravel-idea.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This one is an even harder sell than PhpStorm as it's only a plugin for the IDE that will provide better support for Laravel, and it's on the expensive side for a plugin. Worse, this is all functionality that in my opinion should be part of PhpStorm. But at the end of the day it makes working with Laravel so much easier, and it make me so much more productive that it's easily worth it : It provides tools to create new Laravel classes (Models, migrations, Commands, Events Jobs...), makes it easy to navigate between all of them, and autocompletes basically everything you could wish for (properties, relationships, validation rules, request fields...).&lt;/p&gt;




&lt;p&gt;That's it for me !&lt;/p&gt;

&lt;p&gt;I Hope you found something you want to try out, and please share any other tool you like in the comments !&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>tooling</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Are PHP objects passed by reference ?</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sat, 08 Oct 2022 07:58:56 +0000</pubDate>
      <link>https://dev.to/nicolus/are-php-objects-passed-by-reference--2gp3</link>
      <guid>https://dev.to/nicolus/are-php-objects-passed-by-reference--2gp3</guid>
      <description>&lt;p&gt;TL;DR : No.&lt;/p&gt;

&lt;p&gt;For the longest time I've considered that Objects were "passed by reference" in PHP, and while it may not be technically true, it's a useful simplification that does the job in most cases. So if you read the title and thought "Yes they are" there's no need to panic, everything is probably fine, it doesn't mean that your apps will suddenly blow in your face. On the other hand if you thought "what on earth is a reference ?", you &lt;em&gt;miiight&lt;/em&gt; have a few surprises lurking in your codebase, and you're definitely in the right place !&lt;/p&gt;

&lt;p&gt;So let's dig in with a refresher on references, then we'll see how it looks like objects &lt;em&gt;are&lt;/em&gt; passed by reference, and then why it's actually a bit more complicated than that.&lt;/p&gt;




&lt;h3&gt;
  
  
  References in PHP
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.php.net/manual/en/language.oop5.references.php" rel="noopener noreferrer"&gt;PHP doc about references&lt;/a&gt; tells us that references are "aliases", which means that we can tell PHP we want two variables to point to the same data (the docs also tells us that despite appearances they are not pointers, which is not particularly helpful unless you're already proficient in C). The symbol to create a reference is &lt;code&gt;&amp;amp;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So we can do :&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;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// $a contains 'foo'&lt;/span&gt;
&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// $b is now a reference, or an alias of $a&lt;/span&gt;

&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'bar'&lt;/span&gt; &lt;span class="c1"&gt;// We're actually changing the content of $a&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;    &lt;span class="c1"&gt;// displays 'bar' (because we just changed the value)&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;    &lt;span class="c1"&gt;// displays 'bar' (because it's still a reference to $a)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This is a nice little oddity, but really not that useful in your everyday code. Now what's a lot more useful is that you can &lt;strong&gt;pass variables by reference&lt;/strong&gt; to a function, so that the function can actually modify the content of the variable outside of its own scope.&lt;/p&gt;

&lt;p&gt;This is done by appending the &lt;code&gt;&amp;amp;&lt;/code&gt; in front of the parameter in the function declaration.&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;/**
 * Decrements a number if it's &amp;gt; 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$a&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;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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;$timeLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$wasModified&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$timeLeft&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$timeLeft&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// will output 9&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As you can see, this allows us to return something, and modify what was passed to the function directly. This is notably used in the &lt;a href="https://www.php.net/manual/fr/function.preg-match.php" rel="noopener noreferrer"&gt;preg_match()&lt;/a&gt; function that will return true if something matched, and accept a parameter &lt;code&gt;$m&lt;/code&gt; that will be modified to contain what was matched. This is a useful feature, but it could also be the cause of hard to track bugs, so you should probably use this with caution.&lt;/p&gt;

&lt;p&gt;Here's a nice animation from &lt;a href="https://blog.penjee.com/passing-by-value-vs-by-reference-java-graphical/" rel="noopener noreferrer"&gt;this post&lt;/a&gt; that illustrates it nicely :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7zlwv9l4aosfm5smpv6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7zlwv9l4aosfm5smpv6.gif" alt="Animation of a coffee cup that gets duplicated then filled. When passed by reference the original cup gets filled to"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Why objects look like they're passed by reference
&lt;/h3&gt;

&lt;p&gt;It's likely that you've already read somewhere that objects are always passed by reference in PHP. And it sure looks like it.&lt;/p&gt;

&lt;p&gt;Take this simple example :&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;doStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'newValue'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'value'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nf"&gt;doStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// displays 'newValue'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As you can see, there's no &lt;code&gt;&amp;amp;&lt;/code&gt; in our function declaration, and yet &lt;code&gt;$object-&amp;gt;data&lt;/code&gt; now contains 'newValue' instead of 'value'. So the function did modify the object, which indeed looks a whole lot like it was passed by reference.&lt;/p&gt;

&lt;h4&gt;
  
  
  The issue with modifying objects
&lt;/h4&gt;

&lt;p&gt;Here's a more concrete example that is the source of bugs in actual production codebases. Let's say we want to send our users an email with a receipt for the coming month, and we want the title to display the beginning of the period and the end of the period in a user friendly manner like "&lt;em&gt;From Thursday July 1 to Saturday July 31&lt;/em&gt;", and the current date in the footer of the email. We'll create some functions to get the start and end of the month corresponding to the current date, and format them, then use the result in a string (or more realistically a template). It would look like this : &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;getFirstDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$date&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;$date&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;modify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'first day of this month'&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;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'l F j'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getLastDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$date&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;$date&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;modify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'last day of this month'&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;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'l F j'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$today&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;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2022-07-15'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$firstday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFirstDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$today&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$lastDay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getLastDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$today&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$emailTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Your receipt for the period from &lt;/span&gt;&lt;span class="nv"&gt;$firstday&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="nv"&gt;$lastDay&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$emailFooter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Sent on "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;  &lt;span class="nv"&gt;$today&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"l F j"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The title will say&lt;br&gt;
"&lt;em&gt;Your receipt for the period from Thursday July 1 to Saturday July 31&lt;/em&gt;", which is what we want, but the footer says "&lt;em&gt;Sent on Saturday July 31&lt;/em&gt;", which is definitely not what we want. The issue is that $today was actually modified by the functions when we called -&amp;gt;modify() on the date, so as soon as we use this on a date we lose the original value of the date forever...&lt;/p&gt;

&lt;p&gt;There are two ways around this :&lt;/p&gt;

&lt;p&gt;1- clone the object before working on it :&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;getFirstDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$today&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;clone&lt;/span&gt; &lt;span class="nv"&gt;$today&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;$date&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;modify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'first day of this month'&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;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'l F j'&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;2- Use a library like Carbon 2 that provides &lt;strong&gt;Immutable Objects&lt;/strong&gt;, which are essentially objects where every method always returns a clone instead of modifying the current object.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why objects aren't really passed by reference
&lt;/h3&gt;

&lt;p&gt;So we've seen that it looks an awful lot like objects are passed by reference and how to avoid potential issues, but the whole point of this post was to show that they're not, so here are a couple examples that make it obvious.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example 1 : objects in an array
&lt;/h4&gt;

&lt;p&gt;Let's assume a User class that takes the name of the user in the constructor and assigns it to a name property. Now let's see what happens if we put several of those users in an array and pass it to a function that makes the name uppercase for each element  :&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;User&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;){}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;capitalizeNames&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;$users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtoupper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&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="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'John'&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;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Jack'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nf"&gt;capitalizeNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;json_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [{"name":"JOHN"},{"name":"JACK"}]&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As you can see, each user in the array was modified by the capitalizeNames() function.&lt;/p&gt;

&lt;p&gt;We didn't use a reference, we never passed an object to the function since we passed an array (by value) so we might think we're safe. And yet every object inside of the array was modified.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example 2 : Assigning an object to another a variable
&lt;/h4&gt;

&lt;p&gt;Now let's look at what happens if we assign an instance of an object to a new variable :&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;$user1&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;User&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="nv"&gt;$user2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$user1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Jack'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$user1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Jack&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$user2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Jack&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;So basically as soon as we do &lt;code&gt;$user2 = $user1;&lt;/code&gt;, we can use both interchangeably and changing one will change the other.&lt;/p&gt;

&lt;h3&gt;
  
  
  So what happened ?
&lt;/h3&gt;

&lt;p&gt;The thing is that a variable never "contains" an object. Whenever we call &lt;code&gt;new&lt;/code&gt;, PHP will return a &lt;em&gt;handle&lt;/em&gt;, which is a &lt;del&gt;reference&lt;/del&gt;... a &lt;del&gt;pointer&lt;/del&gt;... yeah let's stick with handle. That handle is basically a number that identifies the object.&lt;br&gt;
You can actually see this object identifier when using &lt;code&gt;var_dump()&lt;/code&gt;, it's the number with a # in front when dumping an object, here with &lt;code&gt;var_dump($user1, $user2)&lt;/code&gt; from our previous example, we can see that they're both the same object since they have the same handle : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o51c2pfwle6ewjmjumx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o51c2pfwle6ewjmjumx.png" alt="Screenshot of a var_dump that shows the object handle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You could also use &lt;a href="https://www.php.net/manual/en/function.spl-object-id.php" rel="noopener noreferrer"&gt;&lt;code&gt;spl_object_id()&lt;/code&gt;&lt;/a&gt; which returns this object identifier.&lt;/p&gt;

&lt;p&gt;Whenever we copy an object variable, pass it to a function or put it in an array, we're not passing or copying the instance of the object, only its handle. So &lt;strong&gt;an object will only ever exist once&lt;/strong&gt; unless we use &lt;code&gt;clone&lt;/code&gt;. Kind of like an object in real life.&lt;/p&gt;




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

&lt;p&gt;While it might be useful to think that objects are passed by reference, I think it's better to keep in mind that when you create an object there's only one instance that exists, and what you're using is not the object but simply a handle.&lt;/p&gt;

&lt;p&gt;I hope this can be useful to someone. Also I don't have any background in C and only a vague understanding of how this is actually implemented in the PHP core. So if there's something blatantly wrong above please let me know in the comments.&lt;/p&gt;

</description>
      <category>php</category>
      <category>oop</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to properly retrieve Laravel models between two dates</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sat, 05 Jun 2021 14:50:08 +0000</pubDate>
      <link>https://dev.to/nicolus/how-to-properly-retrieve-laravel-models-between-two-dates-1bek</link>
      <guid>https://dev.to/nicolus/how-to-properly-retrieve-laravel-models-between-two-dates-1bek</guid>
      <description>&lt;p&gt;Let's say you have a blog with posts (or an ad board with listings, or travelers with trips... you get the idea) and you want to retrieve all the posts between two dates. Sounds familiar ? So how exactly do we do that ? &lt;/p&gt;




&lt;h3&gt;
  
  
  The candid approach
&lt;/h3&gt;

&lt;p&gt;It really seems like a trivial question with an easy (but completely wrong) answer : Just use &lt;code&gt;BETWEEN&lt;/code&gt; (or in Laravel &lt;code&gt;whereBetween&lt;/code&gt;) like so :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$endDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;whereBetween&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$endDate&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;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've all done that (at least I know I have) to retrieve all posts created in June. The issue here is that our &lt;code&gt;created_at&lt;/code&gt; column is usually a Datetime, so it's not a simple date but it also has a time. Which means that in practice any post created on the 30th won't be retrieved because their creation date will always be greater than 2021-06-30 (which SQL will assume means '2021-06-30 00:00:00').&lt;/p&gt;

&lt;p&gt;Or maybe we're using Carbon and have something like that :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$endDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;whereBetween&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$endDate&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;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's actually even worse because it becomes totally unpredictable. A Carbon instance represents an instant, and it has a time too, except if you don't specify a time it will default to the current time when the script runs. So if you run this script at 9AM and the post was created at 8AM on the 30th, you'll retrieve it... But run the exact same script at 7AM, and you won't retrieve that post anymore because $endDate will actually be '2021-06-30 07:00:00'.&lt;/p&gt;

&lt;p&gt;We could use $endDate-&amp;gt;toDateString() to get rid of the time, but we'd end up in the situation above.&lt;/p&gt;




&lt;h3&gt;
  
  
  A better way with carbon
&lt;/h3&gt;

&lt;p&gt;One solution would be to make sure that we specify a time in our query, and that this time is at the very start of the day for our start date (00:00:00) and at the very end of the day for our end date (23:59:59.999999).&lt;/p&gt;

&lt;p&gt;Fortunately, Carbon provides the &lt;code&gt;startOfDay()&lt;/code&gt; and &lt;code&gt;endOfDay()&lt;/code&gt; methods that do just that :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&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;startOfDay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$endDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&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;endOfDay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;whereBetween&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$endDate&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;get&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's much better, we can be pretty sure that everything created on the 1st or the 30th will be retrieved no matter what time they were created at or what time it is.&lt;/p&gt;

&lt;p&gt;It's a solid solution and you can definitely use it, but adding a time when really we only care about the date feels a tiny bit like a hack to me, so let's see another solution&lt;/p&gt;




&lt;h3&gt;
  
  
  Another way with MySQL
&lt;/h3&gt;

&lt;p&gt;We could also explicitly tell MySQL that we only care about the date by using &lt;code&gt;DATE()&lt;/code&gt;. The query we want is this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That way we'll compare dates with dates, and not with a Datetime. We'll need to resort to DB:raw() to replicate this with Eloquent, which would look like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$endDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;whereBetween&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DATE(created_at)'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$endDate&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;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ideally we should make sure that &lt;code&gt;$startDate&lt;/code&gt; and &lt;code&gt;$endDate&lt;/code&gt; are properly formatted as dates, but it seems to work even if we pass a full Carbon object (which is automatically converted to a string) as MySQL will ignore the time portion.&lt;/p&gt;

&lt;p&gt;So that's another way to do it, but I'm not a fan of using DB::raw() either, plus it could be slower (more about that in the last paragraph). So let's see a final solution that leverages Eloquent to handle that.&lt;/p&gt;




&lt;h3&gt;
  
  
  Yet another way with Eloquent
&lt;/h3&gt;

&lt;p&gt;Eloquent provides a very helpful &lt;code&gt;whereDate()&lt;/code&gt; method that will do two things&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build an SQL query that uses the &lt;code&gt;DATE()&lt;/code&gt; SQL function to format the content of the column as &lt;em&gt;Y-m-d&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Properly cast a Carbon or Datetime object to the &lt;em&gt;Y-m-d&lt;/em&gt; format before comparing it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using this, we can confidently pass Carbon instances and know that any time that happens to be a part of it will be discarded and we'll actually be searching between two dates :&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;$startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$endDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;gt;='&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$startDate&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;whereDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;='&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$endDate&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;get&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 generate this SQL query :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;"posts"&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it works flawlessly. The only downside is that we can't use between so it's a little bit longer to write, but if we're going to use it in several places we could easily write a scope (and maybe even make it generic so that it could be imported as a Trait in every model that needs it ?), something like that :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;scopeCreatedBetweenDates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$dates&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;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;gt;='&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;='&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use it 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="nv"&gt;$startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$endDate&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createdBetweenDates&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$endDate&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;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;strong&gt;that&lt;/strong&gt; looks pretty good to me ! Unfortunately it might not be the fastest solution...&lt;/p&gt;




&lt;h3&gt;
  
  
  What about performance ?
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Note : This was not part of the original article, and someone on Linkedin asked me "what about performance"... Which opened a whole new can of worms I hadn't really anticipated (which Oliver also pointed out in the comments).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All of the approaches above have about the same performance if you don't have any index on the created_at column, which is probably fine if you need to filter a few dozens or hundreds of models by date, but if you start working with a lot more than that you'll need to create an index and... Things get messy.&lt;/p&gt;

&lt;p&gt;If you create a simple index on the &lt;code&gt;created_at&lt;/code&gt; column, the Carbon approach that uses &lt;code&gt;-&amp;gt;startOfDay()&lt;/code&gt;, &lt;code&gt;-&amp;gt;endOfDay()&lt;/code&gt; and &lt;code&gt;-&amp;gt;between()&lt;/code&gt; will be a lot faster because it can leverage the index.&lt;/p&gt;

&lt;p&gt;Unfortunately anything that involves the &lt;code&gt;DATE()&lt;/code&gt; function, either by using &lt;code&gt;DB::raw()&lt;/code&gt; or Laravel's &lt;code&gt;WhereDate()&lt;/code&gt; function won't be able to use that index because it contains the timestamp.&lt;/p&gt;

&lt;p&gt;The theoretical solution to this is to create a &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-functional-key-parts" rel="noopener noreferrer"&gt;functional index&lt;/a&gt; on &lt;code&gt;DATE(created_at)&lt;/code&gt;in MySQL. There are two caveats though :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Functional indexes are only available on MySQL 8.0.13 and above&lt;/li&gt;
&lt;li&gt;For some reason that I can't figure out, the functional index is not used when using prepared statements. So in order for it to work you'd have to also use PDO's emulated prepared statements which is not the recommended way.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So all in all, my final recommendation is to stick with Carbon to get the start and end of day. And we can still use a scope for that to make it easier to use (we'll also make it accept either a Carbon instance or a string) :&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;scopeCreatedBetweenDates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$end&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereBetween&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nv"&gt;$start&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;startOfDay&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nv"&gt;$end&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;endOfDay&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 we can use it like so :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createdBetweenDates&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'2021-06-01'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-06-30'&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;get&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;Dealing with time is hard. I find that when dealing with dates and time, even if it looks simple, it pays to take an extra minute to wonder if it really is that simple and if you're not missing something (and we haven't even touched time zones, Daylight Saving Time, and leap seconds...)&lt;/p&gt;

&lt;p&gt;Anything I missed ? Questions ? Horror stories to share about dates ? hit the comments !&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>mysql</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How the new 'One Of Many' Laravel relationship made my project 600 times faster</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Fri, 21 May 2021 11:31:51 +0000</pubDate>
      <link>https://dev.to/nicolus/how-the-new-one-of-many-laravel-relationship-made-my-project-600-times-faster-27ll</link>
      <guid>https://dev.to/nicolus/how-the-new-one-of-many-laravel-relationship-made-my-project-600-times-faster-27ll</guid>
      <description>&lt;p&gt;When a framework is as mature as Laravel, most new features tend to become subtle improvements, "nice to haves", or something that covers an edge case that you might encounter someday... But sometimes there's a feature that makes you think "That's what I've been waiting for !".&lt;/p&gt;

&lt;p&gt;That's precisely what happened to me when the &lt;a href="https://laravel-news.com/one-of-many-eloquent-relationship" rel="noopener noreferrer"&gt;'One Of Many' relationships was added to Laravel 8.42&lt;/a&gt; a few days ago. And I'm pretty sure I'm not the only one since it solves a pretty common problem : getting the latest item out of a One To Many relationship.&lt;/p&gt;

&lt;p&gt;For example maybe you have a table where you write each time a user logs-in, and you want to get their latest login ? Or maybe an object that has to go through several steps in a workflow and you want to get its current status ? How convenient would it be to be able to just call &lt;code&gt;$user-&amp;gt;latestLogin()&lt;/code&gt; or &lt;code&gt;$order-&amp;gt;currentStatus()&lt;/code&gt; ?&lt;/p&gt;

&lt;p&gt;until now it was of course doable, but it was either really tedious or had a very high performance impact. Let me give you an example&lt;/p&gt;




&lt;h2&gt;
  
  
  My Monitoring app
&lt;/h2&gt;

&lt;p&gt;One of my current pet projects is a very simple monitoring app, that allows a user to enter a few URLs that the service will "ping" every minute, and send a text message if it becomes unavailable. The main (and only) page looks like this :&lt;/p&gt;

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

&lt;p&gt;I have a grand total of 3 models in the app :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt; : A Laravel user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Url&lt;/strong&gt; : A URL to monitor (a user can have many URLs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check&lt;/strong&gt; : A check that was made on a URL (a URL has many checks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The controller for this view is really simple and the most simple approach would be something like that :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$urls&lt;/span&gt; &lt;span class="o"&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;user&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;urls&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;get&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;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'urls.index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'urls'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$urls&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 then in the view we create a table with each row looking 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="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$urls&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;latestCheck&lt;/span&gt;&lt;span class="o"&gt;?-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;endforeach&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And of course, I need to make latestCheck a relationship that can be queried, so I just added it in my URL model like so :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;latestCheck&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;HasOne&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;hasOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Check&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;latest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works.&lt;/p&gt;

&lt;p&gt;Well it kind of works. We have our results but we also have an issue called the "n+1 queries" problem, because every time we call latestCheck in the view, it will actually trigger an SQL query to get the latest check for that URL. It's very obvious when using Clockwork :&lt;/p&gt;

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

&lt;p&gt;As you can see, we have 10 URLS to monitor so we make 10 SELECT queries on the &lt;em&gt;checks&lt;/em&gt; table, but if we had 100 we'd have 100 queries which would be significantly slower. Even as it is the page takes 600ms to load which is way too long for something simple as that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note : The subsequent queries are faster and faster. That's because for this test I seeded the checks for each URL one after the other, so the checks for the 10th URL will be higher in the table, and be found much faster. That's not really what would happen in production.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Eager loading to the rescue !
&lt;/h2&gt;

&lt;p&gt;Luckily Laravel provides us with a way to avoid this "n+1 queries" problem : eager loading. We can tell it to load all the elements of a relationships in one query by using the &lt;code&gt;-&amp;gt;with()&lt;/code&gt; method like so :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$urls&lt;/span&gt; &lt;span class="o"&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;user&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;urls&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;'latestCheck'&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;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And sure enough, we now have only one query :&lt;/p&gt;

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

&lt;p&gt;And now our page displays in... WHAAAAAAT ? 20 seconds ? And it's using 480MB of memory ? that can't be right. What's happening ?&lt;/p&gt;

&lt;p&gt;Looking at the query, it doesn't seem to have any kind of "LIMIT" statement :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`url_id`&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will fetch ALL of the checks for those 10 URLS, and apparently Laravel is then working on a collection to extract the first check from each URL, except in my case it's a collection of 500000 items so it takes a lot of time and a lot of memory. &lt;strong&gt;So in our case it turns out that eager loading is actually much slower than lazy loading.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is very unsatisfying but going back to lazy loading was our best option with Eloquent prior to Laravel 8.42. If we wanted better performance the only other way was to ditch Eloquent and write our own query with &lt;code&gt;JOIN&lt;/code&gt; and &lt;code&gt;MAX()&lt;/code&gt; to get the latest check.&lt;/p&gt;




&lt;h2&gt;
  
  
  LatestOfMany Relationship to the Rescue !
&lt;/h2&gt;

&lt;p&gt;Fortunately we now have a much better solution, we can just rewrite that relationship with a small change :&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;latestCheck&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;hasOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Check&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;latestOfMany&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 replaced &lt;code&gt;latest()&lt;/code&gt; with &lt;code&gt;latestOfMany()&lt;/code&gt;, and now Laravel will make the proper SQL query behind the scene :&lt;/p&gt;

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

&lt;p&gt;Now that's much better ! We went from 600ms (or 20000ms with eager loading) to less than 30ms (which &lt;em&gt;is&lt;/em&gt; over 600 times faster than the worst case scenario), and we do have only one query that fetches just what we need :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;EXPLAIN&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;
  &lt;span class="k"&gt;inner&lt;/span&gt; &lt;span class="k"&gt;join&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`url_id`&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;
    &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`url_id`&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;`latestCheck`&lt;/span&gt;
  &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="nv"&gt;`latestCheck`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt;
  &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;`latestCheck`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`url_id`&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`url_id`&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;`checks`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;`url_id`&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's really not something I'd want to write in raw SQL or the Query Builder if I don't have to, so it's really nice to have it available in one method !&lt;/p&gt;




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

&lt;p&gt;That's all there is to it really. Whenever you want the latest occurrence of a relationship you can use this new method and it will automatically be much faster while keeping your code clean and readable !&lt;/p&gt;

&lt;p&gt;Let us know if you've had similar experiences, or maybe a more original use case for these new relationships ?&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Laravel Fortify : Implement 2FA in a way that won't let users lock themselves out</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Mon, 17 May 2021 11:21:05 +0000</pubDate>
      <link>https://dev.to/nicolus/laravel-fortify-implement-2fa-in-a-way-that-won-t-let-users-lock-themselves-out-2ejk</link>
      <guid>https://dev.to/nicolus/laravel-fortify-implement-2fa-in-a-way-that-won-t-let-users-lock-themselves-out-2ejk</guid>
      <description>&lt;h2&gt;
  
  
  The problem with Fortify and Two Factor Authentication
&lt;/h2&gt;

&lt;p&gt;Laravel Fortify is pretty awesome. It handles most of the heavy lifting of authentication for you, but unlike Laravel Breeze (which publishes Controllers and views in your application) or Laravel Jetstream (which actually uses Fortify behind the scenes), it lets you in charge of creating your own views so you don't have to use tailwind CSS or inertia.js.&lt;/p&gt;

&lt;p&gt;One of the things it handles and was very appealing to me is Two Factor Authentication (2FA) with Time-Based One Time Passwords (TOTP) : The thing that asks you to scan a QR code in an application like &lt;a href="https://play.google.com/store/apps/details?hl=en&amp;amp;id=com.google.android.apps.authenticator2" rel="noopener noreferrer"&gt;Google Authenticator&lt;/a&gt; or &lt;a href="https://duo.com/" rel="noopener noreferrer"&gt;Duo&lt;/a&gt;, and then gives you a new 6 character password every 30 seconds that you have to enter to log-in.&lt;/p&gt;

&lt;p&gt;That's really nice because it's an essential feature for any application that need decent security, and I wouldn't know where to start if I had to implement it from scratch. But as of now it has one major limitation : If you implement it by following the documentation to the letter, there's a good chance that your users will end up locked out of your app when they try to enable it. The issue is described in detail &lt;a href="https://github.com/laravel/fortify/issues/201" rel="noopener noreferrer"&gt;here&lt;/a&gt;, but it boils down to the fact that Fortify won't ask for the user to enter a code to confirm that they successfully installed the app and scanned the QR code, so if they activate 2FA and then fail to add your site to Google Authenticator (or their computer crashes or something), they wont be able to log into your site ever again.&lt;/p&gt;

&lt;p&gt;Thankfully, Laravel is flexible enough that with a little work we can implement our own confirmation system while still leveraging all the goodies that Fortify gives us.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;The solution we'll be implementing is pretty common : Once a user activates 2FA, instead of simply enabling it, displaying the QR code once and calling it a day, we'll show the QR code, ask them to enter a TOTP generated with Google Authenticator to confirm they did everything correctly, and only then activate 2FA.&lt;/p&gt;

&lt;p&gt;You can find a working example of what we'll do on &lt;a href="https://github.com/nicolus/laravel-2fa" rel="noopener noreferrer"&gt;this github repository&lt;/a&gt; (keep in mind that it's just an example, you'd probably do things a bit differently in a real world app).&lt;/p&gt;

&lt;p&gt;Before we'll start I'll assume that you already installed Fortify and implemented 2FA following the &lt;a href="https://laravel.com/docs/8.x/fortify" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So let's dig in !&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1 : Add a new 'two_factor_confirmed' field
&lt;/h4&gt;

&lt;p&gt;Fortify comes with a migration that adds the &lt;code&gt;two_factor_secret&lt;/code&gt; and &lt;code&gt;two_factor_recovery_codes&lt;/code&gt; columns to the &lt;code&gt;users&lt;/code&gt; table. Whenever a user activates 2FA (by POSTing to the /user/two-factor-authentication endpoint) these fields get populated, and that's how Laravel knows it needs to ask for a TOTP when the user tries to login.&lt;/p&gt;

&lt;p&gt;Since we want the user to confirm that they have setup everything correctly, we need a new column to store that confirmation. To that end, we'll create a &lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/database/migrations/2021_05_09_100736_add_two_factor_confirmed_column_to_users_table.php" rel="noopener noreferrer"&gt;new migration&lt;/a&gt; that creates that column, the up() method will look like that :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="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;boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'two_factor_confirmed'&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;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'two_factor_recovery_codes'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;Now we probably have a view that displays either a button to enable 2FA, or the QR code when the user gets back to it after enabling 2FA. It's likely a variation of something like this :&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;!-- 2FA enabled, we display the QR code : --&amp;gt;&lt;/span&gt;        
@if(auth()-&amp;gt;user()-&amp;gt;two_factor_secret)
    {!! auth()-&amp;gt;user()-&amp;gt;twoFactorQrCodeSvg() !!}
&lt;span class="c"&gt;&amp;lt;!-- 2FA not enabled, we show an 'enable' button  : --&amp;gt;&lt;/span&gt;
@else
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/user/two-factor-authentication"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        @csrf
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Activate 2FA&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
@endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we should be able to modify the &lt;code&gt;two_factor_confirmed&lt;/code&gt; column in the database and it will change what we display on the page.&lt;/p&gt;

&lt;p&gt;There are still two major issues though : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We don't have a way to update our new column&lt;/li&gt;
&lt;li&gt;Laravel itself doesn't care about it, and will keep asking the user for a TOTP as soon as the &lt;code&gt;two_factor_secret&lt;/code&gt; column is filled.&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  Step 2 : Update the column when the User confirms 2FA
&lt;/h4&gt;

&lt;p&gt;First we'll need a route on which we'll POST a TOTP to confirm that the user is able to get one. So let's add it to our routes/web.php file, along with a corresponding TwoFactorAuthController&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/routes/web.php#L25" rel="noopener noreferrer"&gt;/routes/web.php&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="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;'/2fa-confirm'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TwoFactorAuthController&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;'confirm'&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;'two-factor.confirm'&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 could handle the verification and update directly in the Controller, but I think it makes more sense to let the User model do it, so the &lt;code&gt;confirm()&lt;/code&gt; method of our Controller will only tell the User to check the TOTP provided in the &lt;code&gt;code&lt;/code&gt; parameter, and then redirect back (with an error if the code was not valid).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/app/Http/Controllers/TwoFactorAuthController.php#L11" rel="noopener noreferrer"&gt;/app/Http/Controllers/TwoFactorAuthController&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;confirm&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;$confirmed&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;user&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;confirmTwoFactorAuth&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;code&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;$confirmed&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;back&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;withErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Invalid Two Factor Authentication code'&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;back&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 finally we add the &lt;code&gt;confirmTwoFactorAuth()&lt;/code&gt; method in our User model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/app/Models/User.php#L45" rel="noopener noreferrer"&gt;/app/Models/User&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;confirmTwoFactorAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$codeIsValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TwoFactorAuthenticationProvider&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;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;decrypt&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;two_factor_secret&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;$code&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;$codeIsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;two_factor_confirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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;Now we can update our main view to either :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display the "Activate 2FA" button if it's not enabled at all&lt;/li&gt;
&lt;li&gt;Display the QR Code and a form that POSTs to the route we just created if it's enabled but not confirmed&lt;/li&gt;
&lt;li&gt;Display a button that will disable 2FA by sending a DELETE request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/resources/views/home.blade.php" rel="noopener noreferrer"&gt;/resources/views/home.blade.php&lt;/a&gt; :&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;!-- 2FA confirmed, we show a 'disable' button to disable it : --&amp;gt;&lt;/span&gt;        
@if(auth()-&amp;gt;user()-&amp;gt;two_factor_confirmed)
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/user/two-factor-authentication"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        @csrf
        @method('delete')
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Disable 2FA&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- 2FA enabled but not yet confirmed, we show the QRcode and ask for confirmation : --&amp;gt;&lt;/span&gt;
@elseif(auth()-&amp;gt;user()-&amp;gt;two_factor_secret)
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Validate 2FA by scanning the floowing QRcode and entering the TOTP&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    {!! auth()-&amp;gt;user()-&amp;gt;twoFactorQrCodeSvg() !!}
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"{{route('two-factor.confirm')}}"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        @csrf
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Validate 2FA&lt;span class="nt"&gt;&amp;lt;/button&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&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- 2FA not enabled at all, we show an 'enable' button  : --&amp;gt;&lt;/span&gt;
@else
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/user/two-factor-authentication"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        @csrf
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Activate 2FA&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
@endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should work well enough, so now the only problem remaining is that Fortify doesn't know about the &lt;code&gt;two_factor_confirmed&lt;/code&gt; column and will keep asking for a TOTP.&lt;/p&gt;




&lt;h4&gt;
  
  
  Step 3 : check if the user has confirmed 2FA before asking for a TOTP
&lt;/h4&gt;

&lt;p&gt;We can see how Fortify determines if it needs to ask for a TOTP in its &lt;a href="https://github.com/laravel/fortify/blob/1.x/src/Actions/RedirectIfTwoFactorAuthenticatable.php#L48" rel="noopener noreferrer"&gt;RedirectIfTwoFactorAuthenticatable&lt;/a&gt; which has this code in the handle 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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;two_factor_secret&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TwoFactorAuthenticatable&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="nf"&gt;class_uses_recursive&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="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;twoFactorChallengeResponse&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="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems if &lt;code&gt;$user-&amp;gt;two_factor_secret&lt;/code&gt; is not null the user will be redirected. So the solution is pretty easy : We just have to change this to say &lt;code&gt;if (optional($user)-&amp;gt;two_factor_confirmed&lt;/code&gt; instead, right ?&lt;/p&gt;

&lt;p&gt;Well yeah, except this file is in Fortify itself (in the vendor directory) so we're definitely not going to modify it directly.&lt;/p&gt;

&lt;p&gt;Our best bet would be to create our own version of &lt;code&gt;RedirectIfTwoFactorAuthenticatable&lt;/code&gt; and slightly change its behavior. So let's create a &lt;code&gt;RedirectIfTwoFactorConfirmed&lt;/code&gt; class that extends the original one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/app/Actions/Fortify/RedirectIfTwoFactorConfirmed.php" rel="noopener noreferrer"&gt;app/Actions/Fortify/RedirectIfTwoFactorConfirmed&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\Actions\Fortify&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;Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable&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;Laravel\Fortify\TwoFactorAuthenticatable&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;RedirectIfTwoFactorConfirmed&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;RedirectIfTwoFactorAuthenticatable&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="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&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="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validateCredentials&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;two_factor_confirmed&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TwoFactorAuthenticatable&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="nf"&gt;class_uses_recursive&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="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;twoFactorChallengeResponse&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="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&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="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;Looks good, now to teach Fortify that it needs to use our Action now, we need to customize the Authentication Pipeline by adding this in &lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/app/Providers/FortifyServiceProvider.php#L48-L55" rel="noopener noreferrer"&gt;/app/Providers/FortifyServiceProvider&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="nc"&gt;Fortify&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;authenticateThrough&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="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;array_filter&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;'fortify.limiters.login'&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="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EnsureLoginIsNotThrottled&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;Features&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Features&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;twoFactorAuthentication&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;RedirectIfTwoFactorConfirmed&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&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="nc"&gt;AttemptToAuthenticate&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;PrepareAuthenticatedSession&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again it's identical to the default Pipeline, except we replaced &lt;code&gt;RedirectIfTwoFactorAuthenticatable&lt;/code&gt; with &lt;code&gt;RedirectIfTwoFactorConfirmed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And that's it, our users now need to confirm that they can get a valid TOTP before 2FA is actually enabled and they can't lock themselves out of our app !&lt;/p&gt;

&lt;p&gt;Or can they ?...&lt;/p&gt;

&lt;p&gt;Well there's still an issue with our workflow : what happens when we hit that 'Disable 2FA' button and we send a DELETE request to the Fortify Controller ? Fortify will set the two_factor_secret field to &lt;em&gt;null&lt;/em&gt;, but now that we've modified the Authentication Pipeline to check for two_factor_confirmed instead, we've introduced a new problem, and we'll keep asking for a TOTP even after the user has disabled 2FA.&lt;/p&gt;




&lt;h4&gt;
  
  
  Step 4 : set 'two_factor_confirmed' to false when we disable 2FA
&lt;/h4&gt;

&lt;p&gt;I we go back to Fortify's source code, we can see that it sets both two_factor_secret and two_factor_recovery_codes to null in the &lt;a href="https://github.com/laravel/fortify/blob/1.x/src/Actions/DisableTwoFactorAuthentication.php" rel="noopener noreferrer"&gt;DisableTwoFactorAuthentication&lt;/a&gt; Action :&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;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;forceFill&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'two_factor_secret'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'two_factor_recovery_codes'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we'll just need to add our column there, but once again we certainly don't want to start modifying our vendor directory. And this time there isn't a façade that allows us to change the Pipeline for that.&lt;/p&gt;

&lt;p&gt;Luckily, we can rely on the Service Container to help us inject our own version of this Action.&lt;/p&gt;

&lt;p&gt;Let's look at how it's used in Fortify. It all happens in the &lt;a href="https://github.com/laravel/fortify/blob/1.x/src/Http/Controllers/TwoFactorAuthenticationController.php#L36-L43" rel="noopener noreferrer"&gt;TwoFactorAuthenticationController&lt;/a&gt; (the very same that handles the DELETE 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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;destroy&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;DisableTwoFactorAuthentication&lt;/span&gt; &lt;span class="nv"&gt;$disable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$disable&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;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;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;wantsJson&lt;/span&gt;&lt;span class="p"&gt;()&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;JsonResponse&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="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;back&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;'status'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'two-factor-authentication-disabled'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's our action, and it looks like instead of being hardcoded inside of the function, it's resolved through dependency injection and then called right away. That's awesome news because it means we just have to tell the Service Container "whenever someone asks for &lt;em&gt;DisableTwoFactorAuthentication&lt;/em&gt;, just use our own version instead".&lt;/p&gt;

&lt;p&gt;So first let's create our own version (it's very important that it extends the original or else the Service Container won't be able to resolve it) :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/app/Actions/Fortify/DisableTwoFactorAuthentication.php" rel="noopener noreferrer"&gt;/app/Actions/Fortify/DisableTwoFactorAuthentication&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\Actions\Fortify&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;DisableTwoFactorAuthentication&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Laravel\Fortify\Actions\DisableTwoFactorAuthentication&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="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;forceFill&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'two_factor_secret'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'two_factor_recovery_codes'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'two_factor_confirmed'&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&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 then tell the Service Container to bind this new class to the parent one by adding this in &lt;a href="https://github.com/nicolus/laravel-2fa/blob/master/app/Providers/FortifyServiceProvider.php#L57-L59" rel="noopener noreferrer"&gt;app/Providers/FortifyServiceProvider&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Laravel\Fortify\Actions\DisableTwoFactorAuthentication&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="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App\Actions\Fortify\DisableTwoFactorAuthentication&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;Aaaaaaaaaaaand that's it ! We should finally have a fully working 2FA implementation that won't let your users lock themselves out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping things up
&lt;/h2&gt;

&lt;p&gt;Looking at the wall of text and code above I realize it looks like &lt;strong&gt;a lot&lt;/strong&gt; to take in, but it's really not that complicated, what we did was :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a new 'confirmed' column with a migration&lt;/li&gt;
&lt;li&gt;Add a new route and controller to set that column to true&lt;/li&gt;
&lt;li&gt;Extend the &lt;em&gt;RedirectIfTwoFactorAuthenticatable&lt;/em&gt; action with our own that checks for that column instead of the 'two_factor_secret' one&lt;/li&gt;
&lt;li&gt;Override the Authentication Pipeline to use our own action&lt;/li&gt;
&lt;li&gt;Extend the &lt;em&gt;DisableTwoFactorAuthentication&lt;/em&gt; Action with our own that disables the 'confirmed' column&lt;/li&gt;
&lt;li&gt;Use the service container to bind our own action to &lt;em&gt;DisableTwoFactorAuthentication&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any question ? anything you would have done differently ? Post in the comments !&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Laravel Sanctum Explained : SPA Authentication</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sun, 24 May 2020 15:35:35 +0000</pubDate>
      <link>https://dev.to/nicolus/laravel-sanctum-explained-spa-authentication-45g1</link>
      <guid>https://dev.to/nicolus/laravel-sanctum-explained-spa-authentication-45g1</guid>
      <description>&lt;p&gt;This is going to be a multi-part article about &lt;a href="https://github.com/laravel/sanctum" rel="noopener noreferrer"&gt;Laravel Sanctum&lt;/a&gt; (previously known as "Airlock"), the new Laravel authentication system. I've played with Sanctum a lot in the last few weeks and it appeared to me that while the package itself works really well and does exactly what it says it does, there are A LOT of ways things could go wrong. And yes, it's almost always user error, but it can be incredibly hard to debug and find out what you missed unless you have a basic understanding of what's going on, which is what we'll try and get here.&lt;/p&gt;

&lt;p&gt;Note that this is not a complete tutorial (that may come later), so you will still need to read &lt;a href="https://laravel.com/docs/7.x/sanctum#spa-authentication" rel="noopener noreferrer"&gt;the documentation&lt;/a&gt; along with this article&lt;/p&gt;

&lt;h3&gt;
  
  
  How sanctum works with Single Page applications
&lt;/h3&gt;

&lt;p&gt;If you read the docs, you already know that Sanctum provides several authentication methods : API tokens, SPA Authentication, and Mobile application authentication. It boils down to two different approaches : &lt;a href="https://en.wikipedia.org/wiki/Stateless_protocol" rel="noopener noreferrer"&gt;Stateless&lt;/a&gt; authentication (without sessions) and Stateful authentication (with sessions).&lt;br&gt;
When using a single page application that runs in the browser we want to use stateful authentication, because it only relies on a HttpOnly session cookie to identify the user, which cannot be stolen through an XSS attack. We could use stateless authentication (actually that's what most of us did before Sanctum was released, with Laravel Passport), but this gives you a bearer token that you have to store somewhere, and it usually end up in the LocalStorage or a regular cookie that can be stolen through an XSS injection.&lt;/p&gt;
&lt;h3&gt;
  
  
  Things to know before you start
&lt;/h3&gt;

&lt;p&gt;Most of this is in the docs, but it's really important so I'll summarize here :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both your SPA and your API must share the same top-level domain. They can be on different subdomains though. For example you could have your front-end SPA on &lt;em&gt;mydomain.com&lt;/em&gt; and the API on &lt;em&gt;api.mydomain.com&lt;/em&gt;, or &lt;em&gt;ui.mydomain.com&lt;/em&gt; and &lt;em&gt;api.mydomain.com&lt;/em&gt;. But you cannot have on on &lt;em&gt;mydomain.com&lt;/em&gt; and another on &lt;em&gt;anothercomain.com&lt;/em&gt;. It simply won't work because the login request will come from your SPA, and the browser will not allow the backend to set a cookie for a different domain.&lt;/li&gt;
&lt;li&gt;You must declare the domain of your SPA as "stateful" in the sanctum configuration file. This is because Sanctum uses a Middleware to force requests from your SPA to be considered as stateful (which is to say it will start a session for those requests). If you forgot to do it or change the domain of your SPA Laravel will not even try to use a session and nothing will work&lt;/li&gt;
&lt;li&gt;CORS is a pain. Luckily Laravel 7 provides a CORS middleware out of the box, but by default it's configured (in the &lt;code&gt;config/cors.php&lt;/code&gt; file) to only apply to routes starting with &lt;code&gt;/api/*&lt;/code&gt;, you need to either change this to &lt;code&gt;*&lt;/code&gt; or add every path your SPA will call like &lt;code&gt;/login/&lt;/code&gt; or &lt;code&gt;/sanctum/csrf-cookie&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The whole Process
&lt;/h3&gt;

&lt;p&gt;So here's a diagram of what happens when your SPA authenticates to your backend :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbpekb8vyseptvpp91vdt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbpekb8vyseptvpp91vdt.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a little dense, but let's see what happens with each step :&lt;/p&gt;
&lt;h4&gt;
  
  
  1 : Getting a CSRF token
&lt;/h4&gt;

&lt;p&gt;Although our cookies should be pretty safe, we still don't want to risk a malicious website tricking a user into logging in, so the login route (like all POST routes) is protected by a CSRF token. In a typical page with a form the token is served with the form and injected in a hidden field, but of course our SPA cannot do that, so we'll have to get it manually. Sanctum provides a &lt;code&gt;/sanctum/csrf-cookie&lt;/code&gt; route that generates a CSRF token and return it, so the very first thing we need our SPA to do is make a GET request on that route&lt;/p&gt;
&lt;h4&gt;
  
  
  1a : Dealing with CORS
&lt;/h4&gt;

&lt;p&gt;Since our frontend and backend are on two different subdomains, there's no way the browser will let us make some ajax request without some kind of verification, so the first thing that happens is that it makes an OPTIONS request. If everything is configured correctly, the &lt;em&gt;HandleCors&lt;/em&gt; middleware will intercept the request and anwser with the correct authorization headers.&lt;/p&gt;

&lt;p&gt;If you notice that your SPA sends an OPTIONS request and never tries to send a GET request look no further, your CORS settings are not properly configured.&lt;/p&gt;
&lt;h4&gt;
  
  
  1b : retrieving the CSRF cookie
&lt;/h4&gt;

&lt;p&gt;After dealing with CORS the GET request will actually go through, and Sanctum will return the csrf token. Or rather it will return an empty page with an &lt;code&gt;XSRF-TOKEN&lt;/code&gt; cookie.&lt;br&gt;
This cookie is not supposed to be used as-is, what your SPA should do is read it, and then put its content into an &lt;code&gt;X-XSRF-TOKEN&lt;/code&gt; header when it makes a POST request to login. This is a convention that's used by several frameworks and libraries including Axios and Angular, but you can also do it yourself. Note that Angular is &lt;a href="https://github.com/angular/angular/issues/20511#issuecomment-430672830" rel="noopener noreferrer"&gt;a little picky&lt;/a&gt; about this header.&lt;/p&gt;
&lt;h4&gt;
  
  
  2 : Loggin in
&lt;/h4&gt;

&lt;p&gt;Now we can log-in. Once again the &lt;em&gt;HandleCors&lt;/em&gt; middleware will do its magic, and then the &lt;em&gt;EnsureFrontEndRequestsAreStateful&lt;/em&gt; Middleware will (as its long name implies) make sure the request creates and uses a new session. This middleware will only be triggered if the domain name of your SPA is listed in the &lt;code&gt;SANCTUM_STATEFUL_DOMAINS&lt;/code&gt; variable of your .env file, so make sure it's correctly configured.&lt;/p&gt;

&lt;p&gt;If everything works, a new session will be created and the corresponding cookie will be returned.&lt;/p&gt;

&lt;p&gt;Note that the cookie will be set to the domain declared in the &lt;code&gt;SESSION_DOMAIN&lt;/code&gt; of your .env file, which should be your top-level domain preceded by a &lt;code&gt;.&lt;/code&gt;. So if you use &lt;em&gt;mydomain.com&lt;/em&gt; and &lt;em&gt;api.mydomain.com&lt;/em&gt; you want to set the &lt;code&gt;SESSION_DOMAIN&lt;/code&gt; to &lt;code&gt;.mydomain.com&lt;/code&gt; so that both subdomains will be allowed to access it.&lt;/p&gt;

&lt;p&gt;Also, the documentation recommends you use scaffolding, but it seems to me that it defeats the purpose of making an SPA. You don't want your typical redirect to /home either, so you can make your own LoginController with a very simple login method like that :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;login&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="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;attempt&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;only&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password'&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="s2"&gt;"success"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&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;"success"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;403&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;h4&gt;
  
  
  3 : making requests to your app
&lt;/h4&gt;

&lt;p&gt;From there on, you're SPA is connected like any stateful application. You can use the sanctum guard to protect routes and it will check that the user of the SPA is correctly authenticated.&lt;/p&gt;

&lt;p&gt;That's it ! I hope this can be useful to someone. In the next weeks I'll do a complete write-up on how to use Sanctum with an Angular SPA, and with an Ionic App.&lt;/p&gt;

&lt;p&gt;Also if you have any trouble with Sanctum, feel free to leave a comment and I'll try to help !&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>spa</category>
    </item>
    <item>
      <title>Closing a modal with the back button in Ionic 5 / Angular 9</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sun, 17 May 2020 16:37:36 +0000</pubDate>
      <link>https://dev.to/nicolus/closing-a-modal-with-the-back-button-in-ionic-5-angular-9-50pk</link>
      <guid>https://dev.to/nicolus/closing-a-modal-with-the-back-button-in-ionic-5-angular-9-50pk</guid>
      <description>&lt;p&gt;I'm going to share this because it took me a couple hours of research and experimenting to achieve something that in my opinion should be the default behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  The issue :
&lt;/h2&gt;

&lt;p&gt;So let's say you want to use a modal to display some information in your Ionic PWA (In my case I was displaying a list of articles, and I wanted to display the full article in a modal so as to not completely change page). You probably have a "back" or "cancel" button somewhere in your modal, and if your screen is big enough to see the rest of the page behind you can click that to dismiss the modal. So far so good !&lt;/p&gt;

&lt;p&gt;Now the problem is that many users will want to use the hardware back button on their mouse or their phone to dismiss the modal (especially on a small screen where the modal takes the whole screen and looks like a new page), and in that case the default behavior is that it will change the actual page that's still behind your modal to the previous page... Which is definitely not what you would expect to happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution :
&lt;/h2&gt;

&lt;p&gt;From Angular's perspective it makes sense : As far as the router component is concerned you never changed page (you just put a huge popup in front of your page), and hitting back will just bring you to the previous page... So let's change that !&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Dismiss the Pop-up when the back button is pressed
&lt;/h4&gt;

&lt;p&gt;This can be done easily with the &lt;a href="https://angular.io/api/core/HostListener" rel="noopener noreferrer"&gt;@HostListener()&lt;/a&gt; decorator, which allows you to listen for a DOM event and trigger the decorated method when it happens. So in our modal component we can listen for the history &lt;a href="https://developer.mozilla.org/fr/docs/Web/API/Window/popstate_event" rel="noopener noreferrer"&gt;popState&lt;/a&gt; and dismiss our modal :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;HostListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;window:popstate&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="s1"&gt;$event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="nf"&gt;dismissModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dismiss&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;Chances are you already have a method that dismisses your modal that you may call from a "cancel" or "close" button in your html. If that's the case you don't need to create a new method, you can just add the decorator to your existing method.&lt;/p&gt;

&lt;p&gt;That should work great for dismissing the modal, except won't prevent the back button from &lt;em&gt;also&lt;/em&gt; going back in the history and switch to the previous page.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Don't go back to the previous page after dismissing the modal
&lt;/h4&gt;

&lt;p&gt;Unfortunately there doesn't seem to be a way to prevent the default behavior of the back button, so we'll need to be get clever. One solution is to push a "fake" state for our modal in the history when it's displayed, that way the popState event will just get rid of that fake state. We can put anything we want in the "state" parameter of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History/pushState" rel="noopener noreferrer"&gt;history.pushState()&lt;/a&gt;, so we'll put a &lt;code&gt;modal&lt;/code&gt; boolean in case we later need to check if a specific state was created for a modal. Let's so it in our ngOnInit method :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;modal&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;desc&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fake state for our modal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pushState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalState&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is good. But there's still a tiny little problem : What happens if the user dismisses the modal without using the back button (by clicking on the close button in the modal itself, or clicking outside of the modal) ? We're left with a phantom state in our history and the next time they press back nothing will happen !&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Remove any phantom history when the modal is dismissed
&lt;/h4&gt;

&lt;p&gt;We'll need to manually cleanup the history in this case. So let's use our &lt;code&gt;modal&lt;/code&gt; to remove the last state if needed when we dismiss our modal in the &lt;br&gt;
ngDestroy() method :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;back&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 &lt;strong&gt;NOW&lt;/strong&gt; we're good to go. We should have covered all cases and it will give the perfect illusion that you can dismiss a popup with the back button !&lt;/p&gt;

&lt;p&gt;Here's the whole component with the constructor and our 3 methods :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HostListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&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;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModalController&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;@ionic/angular&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&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-mymodal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./mymodal.page.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&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;./mymodal.page.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModalComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;modalController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;modal&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;desc&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fake state for our modal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pushState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalState&lt;/span&gt;&lt;span class="p"&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="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;back&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="nd"&gt;HostListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;window:popstate&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="s1"&gt;$event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="nf"&gt;dismissModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dismiss&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;Thanks for reading ! So far it seems to work fine for me but let me know if I missed anything or if you have another solution.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ionic-team/ionic-v3/issues/563" rel="noopener noreferrer"&gt;https://github.com/ionic-team/ionic-v3/issues/563&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@david.dalbusco/how-to-close-ionic-modals-using-the-hardware-back-button-aaddeb23dd35" rel="noopener noreferrer"&gt;https://medium.com/@david.dalbusco/how-to-close-ionic-modals-using-the-hardware-back-button-aaddeb23dd35&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://forum.ionicframework.com/t/how-to-close-modal-alert-on-back-button-in-ionic4-pwa/168633" rel="noopener noreferrer"&gt;https://forum.ionicframework.com/t/how-to-close-modal-alert-on-back-button-in-ionic4-pwa/168633&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/51729751/close-angular-modal-and-remain-on-same-page-on-back-button-click" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/51729751/close-angular-modal-and-remain-on-same-page-on-back-button-click&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ionic</category>
      <category>angular</category>
      <category>typescript</category>
      <category>pwa</category>
    </item>
    <item>
      <title>Sprint charts : Burn down or Burn up ?</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sun, 21 Jul 2019 13:54:30 +0000</pubDate>
      <link>https://dev.to/nicolus/sprint-charts-burn-down-or-burn-up-37e</link>
      <guid>https://dev.to/nicolus/sprint-charts-burn-down-or-burn-up-37e</guid>
      <description>&lt;p&gt;So my team has been working with Scrum (or at least some scrum-inspired in-house methodology) for a few month now, and I realize that I'm not entirely satisfied with the Burn down charts that gitlab (or most other tools) is providing us. I feel they don't always tell the whole story.&lt;/p&gt;

&lt;p&gt;I found that burn &lt;em&gt;up&lt;/em&gt; charts are a lot more interesting, but I don't see many people using them. So maybe it's just me ? Or maybe we're not planning the way we should ? Let me explain my point and tell me what you think in the comments !&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Ideal" Sprint
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k8ggi1tx15hjuw1wmyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k8ggi1tx15hjuw1wmyq.png" width="640" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
An ideal sprint : burn down chart on the left, burn up on the right



&lt;p&gt;Let's consider a pretty perfect sprint above. We determined our team velocity and estimated that as a team we could tackle about 100 points a week. Then during sprint planning we estimated some tasks and put 100 points worth of tasks in our sprint. In this example it worked really well and we were able to complete all the tasks in time at a very steady rate, yay !&lt;/p&gt;

&lt;p&gt;Here the two charts are not really that different : The burn down chart on the left starts at 100 points in the upper left corner with the red line representing the number of tasks (or rather points) left to complete, and the goal is to bring it down by following the dashed grey line as closely as possible. The burn up chart is working the other way : The blue line at the top represents the number of points to complete, and the aim is to complete them all and bring the red line up.&lt;/p&gt;

&lt;p&gt;In this ideal scenario there's no real advantage to a burn up chart, but honestly I have yet to see a chart that looks like this in our team, so let's move on to other scenarios&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Can we just add this tiny task ?" Sprint
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ku5evd2zcztz2gbx81f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ku5evd2zcztz2gbx81f.png" width="640" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
A sprint where we added a task : burndown chart on the left, burn up on the right



&lt;p&gt;That's when things start to go South. In each an everyone of our sprints there's always something that we did not anticipate and that we just have to deal with. So naturally we add a task to the sprint and we try to handle it the best we can. Sometimes it works out, and sometimes it doesn't.&lt;/p&gt;

&lt;p&gt;In this case it didn't quite work out as we can see on the charts. But what's interesting is that by looking at the traditional burn down chart we don't know what happened. It just looks like for some reason the team got less productive towards the end of the sprint (which can indeed happen if we hit a roadblock). The burn up chart is a lot more interesting here because we clearly see that the team handled exactly the amount of work that was planned, but we missed our objective because we had to add on to that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Maybe we don't need that" Sprint
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx873jl3vojchoqdznxrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx873jl3vojchoqdznxrf.png" width="640" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
A sprint where we removed a tasks : burndown chart on the left, burn up on the right



&lt;p&gt;This is the opposite of the previous example : At some point during the sprint something was dropped. Maybe we had to wait for something external to the team and decided to move it to a future sprint, or someone changed their mind about a feature, or maybe we just realized we were late on that sprint and decided to cheat a little and remove less critical tasks...&lt;/p&gt;

&lt;p&gt;Anyway, the result is that with a burn down chart everything looks fine : We completed our 100 points ! But once again the burn up chart shows the whole story, and we clearly see that we only did 80 points worth of tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does it matter ?
&lt;/h2&gt;

&lt;p&gt;As we saw from the examples, Burn up charts only make a difference when tasks are added or removed mid sprint, so if this never happens in your team it won't make much of a difference. If that's the kind of things that does happen, it can give you a better view of what actually happened.&lt;/p&gt;

&lt;p&gt;The goal here is not to put the blame on someone when expectations aren't met, but simply to be able to better adjust our velocity for the next sprints and get more efficient as a team. I feel that if we can better visualize what went wrong (or right), we'll be able to better plan the next sprints.&lt;/p&gt;

&lt;p&gt;So what do you think ? Are burn down charts just fine, or is it better to use burn up charts ? Or do you have a completely different way of evaluating a sprint ?&lt;/p&gt;

</description>
      <category>agile</category>
      <category>scrum</category>
      <category>discuss</category>
    </item>
    <item>
      <title>What you should know about CORS</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sun, 14 Jul 2019 17:11:59 +0000</pubDate>
      <link>https://dev.to/nicolus/what-you-should-know-about-cors-48d6</link>
      <guid>https://dev.to/nicolus/what-you-should-know-about-cors-48d6</guid>
      <description>&lt;p&gt;If you're anything like me, the first time you encountered CORS (or Cross-origin resource sharing), all you wanted was for your server to accept those darn ajax requests and be done with it. So you went to stack overflow, copy pasted a code snippet to set some headers, and it worked.&lt;/p&gt;

&lt;p&gt;There are however a few things you might want to know.&lt;/p&gt;

&lt;h1&gt;
  
  
  What CORS is, and what it is not
&lt;/h1&gt;

&lt;p&gt;This is often a source of confusion for newcomers because it's not immediately apparent what CORS is supposed achieve. Firstly CORS is not a security measure in itself, it's actually the opposite: CORS is a way to circumvent the "Same Origin Policy" which is the security measure preventing you from making ajax requests to a different domain.&lt;/p&gt;

&lt;p&gt;The Same Origin Policy states that a website on one domain cannot make an xhr request to another domain. This prevents a malicious website from making requests to a known website (think Facebook or Google) hoping the user are already logged-in so that it can impersonate them.&lt;br&gt;
This policy is implemented by the browser (all of them implement SOP, although there are minor differences), which means that it won't apply to requests made from a server, or any other HTTP clients like cURL or POSTman. Also the server has absolutely no control over this : it will process every request as if it was coming from a trusted domain, it is entirely up to the browser to block the requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SOP is in no way meant to prevent an attacker from making requests to your server&lt;/strong&gt; (since an attacker would obviously not use a browser). It's only meant to prevent legitimate users using a reputable browser from unknowingly making requests to your website.&lt;/p&gt;

&lt;p&gt;Now CORS are a way to bypass SOP in some cases where you want to allow one specific website to make requests to your server, even though it would normally be blocked. (typically, to allow your front-end app to make requests to your API).&lt;/p&gt;

&lt;h1&gt;
  
  
  How CORS work.
&lt;/h1&gt;

&lt;p&gt;CORS, like the rest of HTTP is basically a dialogue between the browser and the server. Assuming your front-end is on domain-a.com and your API on Domain-b.com, it would go something like this :&lt;/p&gt;

&lt;p&gt;  -&lt;strong&gt;Browser :&lt;/strong&gt; "Hey Domain-B, this script on Domain-A.com is asking me to make an ajax query to you, but I'm supposed to block it unless you tell me it's OK."&lt;br&gt;
  -&lt;strong&gt;Server :&lt;/strong&gt; "I don't know, but I can tell you that only &lt;code&gt;https://domain-a.com&lt;/code&gt; is allowed to make GET, POST, OPTIONS and DELETE requests, and this needs to be validated every 10 minutes.&lt;br&gt;
  &lt;em&gt;Browser thinks to himself "yeah, that's the right domain, I'll send the request !"&lt;/em&gt;&lt;br&gt;
  -&lt;strong&gt;Browser :&lt;/strong&gt; "Hey domain-b, I'd like to POST on this endpoint please.&lt;br&gt;
  -&lt;strong&gt;Server :&lt;/strong&gt; Sure thing, here's a 200&lt;/p&gt;

&lt;p&gt;Or if the user is on a different domain the dialogue would be shorter, and look like that :&lt;/p&gt;

&lt;p&gt;  -&lt;strong&gt;Browser :&lt;/strong&gt; "Hey domain-b.com, this script on malicious-domain.com is asking me to make an ajax query to you, but I'm supposed to block it unless you tell me it's OK."&lt;br&gt;
  -&lt;strong&gt;Server :&lt;/strong&gt; "I don't know, but I can tell you that only &lt;code&gt;https://domain-a.com&lt;/code&gt; is allowed to make GET, POST, OPTIONS and DELETE requests, and this needs to be validated every 10 minutes.&lt;br&gt;
  &lt;em&gt;Browser thinks to himself "Oh it's not the right domain, we'd better not make that request" and proceeds to send an error in the console.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How it looks in the browser
&lt;/h1&gt;

&lt;p&gt;In my little scenes above, the first question from the browser is called a &lt;strong&gt;Preflight request&lt;/strong&gt;, and the corresponding HTTP verb is &lt;code&gt;OPTIONS&lt;/code&gt;. The server should always answer to Preflight Requests with a 200 response that has no body but contains the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; and a few other headers. In our example the headers would be :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://domain-a.com&lt;/span&gt;
&lt;span class="na"&gt;Access-Control-Allow-Methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET, POST, OPTIONS, DELETE&lt;/span&gt;
&lt;span class="na"&gt;Access-Control-Max-Age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3600&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;It tells the browser that it can only perform the request if it comes from domain-A.com, that it can only make &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;OPTIONS&lt;/code&gt; or &lt;code&gt;DELETE&lt;/code&gt; requests (a &lt;code&gt;PUT&lt;/code&gt; request would be blocked for example), and that it can cache this information for 3600 seconds so it doesn't need to make a new &lt;code&gt;OPTIONS&lt;/code&gt; request every single time.&lt;/p&gt;

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

&lt;p&gt;And of course, if we're on a different domain that won't work. The browser will send an &lt;code&gt;OPTIONS&lt;/code&gt; request, throw an error in the console and never send the &lt;code&gt;POST&lt;/code&gt; request :&lt;/p&gt;

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

&lt;p&gt;Pretty straight forward, right ?&lt;/p&gt;

&lt;p&gt;Well yes, except there are a few gotchas...&lt;/p&gt;

&lt;h1&gt;
  
  
  Tricky things about CORS
&lt;/h1&gt;

&lt;h3&gt;
  
  
  All Responses should contain the CORS headers
&lt;/h3&gt;

&lt;p&gt;You might think that if your server answers to the OPTIONS request with a 200 and the right headers you're in the clear, and you'll see the browser send the OPTIONS request, then send your actual request, and then fail miserably... That's because every request (GET, POST, or otherwise) should &lt;em&gt;also&lt;/em&gt; contain the same "Access-Control-Allow-Headers".&lt;/p&gt;

&lt;h3&gt;
  
  
  Not all requests will trigger a Preflight Request
&lt;/h3&gt;

&lt;p&gt;There are a few requests that won't trigger a Preflight Request, for example GET requests, or POST request with with a &lt;code&gt;Content-Type&lt;/code&gt; header set to &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;. Those are "simple requests" that have always been allowed by browsers (you've always been able to make a link or POST a form to a different website, even before CORS exsisted), and you can find the full list &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
in the case of a POST request the result is a little counter-intuitive : The browser &lt;strong&gt;will&lt;/strong&gt; make the POST Request (so your server will likely persist some data), and then ignore the response !&lt;/p&gt;

&lt;p&gt;In a traditional web app you'd use &lt;code&gt;application/json&lt;/code&gt; as a content-type so there will be a preflight request, but keep in mind your server may still receive POST requests from other domains, so don't blindly accept them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The allowed domain must include the protocol
&lt;/h3&gt;

&lt;p&gt;You can't just put &lt;code&gt;mydomain.com&lt;/code&gt; as a domain, it needs to include the protocol (eg. &lt;code&gt;https://mydomain.com&lt;/code&gt;). The fun part is you can't really accept both http and https because...&lt;/p&gt;

&lt;h3&gt;
  
  
  You can only allow one domain
&lt;/h3&gt;

&lt;p&gt;You can either allow every domain with &lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt;, or only one. This means that if you need several domains to access your api, you'll need to handle it yourself.&lt;/p&gt;

&lt;p&gt;The easiest way to handle this is to maintain a list of allowed domains on your server, and change the content of the header dynamically if the domain is in that list. Here's how it would look in plain PHP for example :&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;$allowedDomains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"http://www.mydomain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://www.mydomain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"http://www.myotherdomain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"http://www.myotherdomain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nv"&gt;$originDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_ORIGIN'&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;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$originDomain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$allowedDomains&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Access-Control-Allow-Origin: &lt;/span&gt;&lt;span class="nv"&gt;$originDomain&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or in Node.js (adapted from &lt;a href="https://stackoverflow.com/a/32481816/1578702" rel="noopener noreferrer"&gt;this SO anwser&lt;/a&gt;)&lt;/p&gt;


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

&lt;p&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedOrigins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;br&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&lt;a href="http://www.mydomain.com" rel="noopener noreferrer"&gt;http://www.mydomain.com&lt;/a&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&lt;a href="https://www.mydomain.com" rel="noopener noreferrer"&gt;https://www.mydomain.com&lt;/a&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&lt;a href="http://www.myotherdomain.com" rel="noopener noreferrer"&gt;http://www.myotherdomain.com&lt;/a&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&lt;a href="http://www.myotherdomain.com" rel="noopener noreferrer"&gt;http://www.myotherdomain.com&lt;/a&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;&lt;br&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allowedOrigins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Same Origin Policy applies to the file system on Chrome and Safari, not on Firefox.&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;If you make a request to a local file, Firefox will consider that it's always on the same domain and allow the request. Webkit based browsers like Chrome or Safari will consider this a security risk and block ajax queries to local files. The only way to get around this is to either use Firefox, or install a web server that will send an &lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt; header.&lt;br&gt;
As pointed out by &lt;a class="mentioned-user" href="https://dev.to/brianjenkins94"&gt;@brianjenkins94&lt;/a&gt; in the comments, you could also start Chrome with the &lt;code&gt;--disable-web-security&lt;/code&gt; flag.&lt;/p&gt;

&lt;h3&gt;
  
  
  The iOS WKWebview needs CORS
&lt;/h3&gt;

&lt;p&gt;If you're developing a mobile app that uses a webview (with Cordova or Ionic), Android won't give you any trouble, but the new WKWebview on iOS will require CORS. This means you pretty much have to always set the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header to &lt;code&gt;*&lt;/code&gt;, which is really not ideal.&lt;br&gt;
Another alternative is to not make ajax requests in your app and use a cordova plugin to make native http requests, which will happily ignore the Same origin Policy.&lt;/p&gt;

&lt;p&gt;Thanks for reading !&lt;br&gt;
If you want a more in depth description of CORS, head to MDN : &lt;a href="https://developer.mozilla.org/docs/Web/HTTP/CORS" rel="noopener noreferrer"&gt;https://developer.mozilla.org/docs/Web/HTTP/CORS&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>http</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting Homestead to play nice with Hyper-V</title>
      <dc:creator>Nicolus</dc:creator>
      <pubDate>Sat, 02 Feb 2019 08:16:45 +0000</pubDate>
      <link>https://dev.to/nicolus/getting-homestead-to-play-nice-with-hyper-v-4202</link>
      <guid>https://dev.to/nicolus/getting-homestead-to-play-nice-with-hyper-v-4202</guid>
      <description>&lt;p&gt;Homestead is a fantastic tool for local development. It's basically a preconfigured Ubuntu Vagrant box that already has everything you'd want for PHP development and more.&lt;br&gt;
The most straightforward way to use it is to install Virtualbox. So if you don't need Hyper-V you can safely stop reading this post and be on your merry way.&lt;/p&gt;

&lt;p&gt;However if you're like me, you may need it to run on Hyper-V instead of Virtualbox, because you can't have both running at the same time on Windows. So if you want to use Docker (which uses Hyper-V) or a Hyper-V machine for something else, it means you'll have to reboot your machine each time you want to use one or the other, which is really not practical.&lt;br&gt;
The good news is that Homestead's support for Hyper-V has made a lot of progress in the past couple of years, but there are still a lot of gotchas that I'll try and go through here.&lt;/p&gt;

&lt;p&gt;This was going to be a complete guide, but I figured that the &lt;a href="https://laravel.com/docs/5.7/homestead#configuring-homestead" rel="noopener noreferrer"&gt;official docs&lt;/a&gt; should be enough to get you started, so I'll just cover the specific issues I encountered when running Homestead with hyper-V.&lt;/p&gt;
&lt;h1&gt;
  
  
  Use everything as administrator
&lt;/h1&gt;

&lt;p&gt;The first annoying thing is that for Homestead (and the underlying Vagrant) to be able to share your work folders with SMB, you need to use them as an administrator. Which in turn means that your IDE needs to be run as administrator to communicate with Homestead.&lt;/p&gt;

&lt;p&gt;So you'll probably want to create shortcuts to start Powershell (or CMD) and your IDE as administrator and get into the habit of using those.&lt;/p&gt;
&lt;h1&gt;
  
  
  Set up the network
&lt;/h1&gt;

&lt;p&gt;The main issue with this setup is that Vagrant is not (yet ?) able to manage Hyper-V's virtual switches, so you'll have to create one yourself or you won't be able to access both the internet and your own host machine from homestead.&lt;br&gt;
To do so, open hyper-V manager, select &lt;em&gt;Virtual Switch Manager&lt;/em&gt; in the &lt;em&gt;Actions&lt;/em&gt; pane, click on &lt;em&gt;New virtual Network Switch&lt;/em&gt;, and click on the create button. Give it a useful name (like "External Switch"), make sure &lt;em&gt;External&lt;/em&gt; network is checked and the physical Ethernet controller that's connected to your network and the internet is selected, then click OK.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx3z5o5yhirdhevszrhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx3z5o5yhirdhevszrhy.png" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first time Homestead starts, it should ask you which network to use, and you'll tell it to use this External Switch.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6uu2lig145tq7hm31w0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6uu2lig145tq7hm31w0f.png" width="700" height="306"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Automatically manage the host file
&lt;/h1&gt;

&lt;p&gt;Through the &lt;a href="https://github.com/devopsgroup-io/vagrant-hostmanager" rel="noopener noreferrer"&gt;vagrant-hostmanager&lt;/a&gt; plugin, homestead is able to automatically update your &lt;em&gt;hosts&lt;/em&gt; file to make the domains you declare in Homestead.yaml accessible.&lt;br&gt;
This is particularly useful with Hyper-V because the IP of your machine might change whenever you restart it, so without this plugin you'd need to go and edit your &lt;em&gt;hosts&lt;/em&gt; file manually each time. Assuming Vagrant is installed you can install the plugin by running &lt;code&gt;vagrant plugin install vagrant-hostmanager&lt;/code&gt; from anywhere in the command line.&lt;/p&gt;

&lt;p&gt;From now on, each time your homestead starts your &lt;em&gt;hosts&lt;/em&gt; file will be automagically updated so that all the domains declared in the Homestead.yaml file will point to your virtual machine. There are two things to keep in mind :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The plugin only triggers on &lt;code&gt;vagrant up&lt;/code&gt;, not on &lt;code&gt;vagrant reload&lt;/code&gt;, so when you restart your homestead machine you should always run &lt;code&gt;vagrant halt&lt;/code&gt; then &lt;code&gt;vagrant up&lt;/code&gt; to make sure your hosts are kept up to date&lt;/li&gt;
&lt;li&gt;This only works because in this scenario we have to run vagrant as administrator so it has write access to the hosts file.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  Allow Homestead to access your work folders
&lt;/h1&gt;

&lt;p&gt;Homestead uses SMB to share files between your machine and the virtual machine when using Hyper-V. By default, it will ask for your login and password each time it starts up, which quickly becomes annoying.&lt;br&gt;
Fortunately, you can now specify credentials to use for SMB shares directly in the Homestead.yaml file, but I wouldn't recommend putting your own credentials in plain sight in a file on your computer. What I found to be an acceptable solution was to :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new windows user names "vagrant" with the password "vagrant".&lt;/li&gt;
&lt;li&gt;Share my code folder (and every folder declared in the Homestead.yaml file) with this user and give it read/write permissions&lt;/li&gt;
&lt;li&gt;Use the "vagrant" user credentials for each folder in the Homestead.yaml file like so :
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;folders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/code&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/vagrant/code&lt;/span&gt;
      &lt;span class="na"&gt;smb_username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vagrant&lt;/span&gt;
      &lt;span class="na"&gt;smb_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vagrant&lt;/span&gt;

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

&lt;/div&gt;

&lt;h1&gt;
  
  
  Get x-debug to work from the command-line
&lt;/h1&gt;

&lt;p&gt;X-debug should work out of the box to debug web pages, but it won't work from the command line with the provided &lt;code&gt;xphp&lt;/code&gt; command. The reason is that this command assumes that your host machine's IP from the VM is &lt;em&gt;192.168.10.1&lt;/em&gt;, which is indeed the case with virtualbox, but not at all when running Hyper-v.&lt;br&gt;
I found a solution to that, which is to modify the xphp alias so that it will find the last SSH connection to the VM, and use this IP as the remote_host for xdebug. It's probably not 100% reliable, but in most cases the IP should be your own since you'll be the only one to connect to the VM through ssh.&lt;br&gt;
So what you'll need to do is edit the &lt;em&gt;aliases&lt;/em&gt; file at the root of the Homestead directory, and replace the xphp() function with this one :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;xphp&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;php &lt;span class="nt"&gt;-m&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; xdebug&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nv"&gt;XDEBUG_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
    &lt;/span&gt;&lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nv"&gt;XDEBUG_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false
    &lt;/span&gt;&lt;span class="k"&gt;fi

    if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$XDEBUG_ENABLED&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;xon&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;#Find the IP of the latest ssh connection :&lt;/span&gt;
    &lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;last &lt;span class="nt"&gt;--limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oP&lt;/span&gt; &lt;span class="s1"&gt;'\d+(\.\d+){3}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    php &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-dxdebug&lt;/span&gt;.remote_host&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-dxdebug&lt;/span&gt;.remote_autostart&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$XDEBUG_ENABLED&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;xoff&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for today, I hope this can be of help to someone !&lt;/p&gt;

</description>
      <category>php</category>
      <category>vagrant</category>
      <category>hyperv</category>
      <category>windows</category>
    </item>
  </channel>
</rss>
