<?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: Martin Betz</title>
    <description>The latest articles on DEV Community by Martin Betz (@martin_betz).</description>
    <link>https://dev.to/martin_betz</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%2F1413%2Fbd8f8a39967f1ec8d624e76be819b1a7.jpeg</url>
      <title>DEV Community: Martin Betz</title>
      <link>https://dev.to/martin_betz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/martin_betz"/>
    <language>en</language>
    <item>
      <title>How to use AlpineJS with Laravel Mix</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Thu, 09 Jul 2020 00:22:25 +0000</pubDate>
      <link>https://dev.to/martin_betz/how-to-use-alpinejs-with-laravel-mix-50cc</link>
      <guid>https://dev.to/martin_betz/how-to-use-alpinejs-with-laravel-mix-50cc</guid>
      <description>&lt;p&gt;This is another thing I do over and over and tend to forget how to properly do it: How can I use &lt;a href="https://github.com/alpinejs/alpine"&gt;AlpineJS&lt;/a&gt; with Laravel Mix?&lt;/p&gt;

&lt;p&gt;AlpineJS is a great lightweight library to sprinkle some interactivity into your website. I struggled a lot in the past with the question: "Do I really need to learn VueJS to get a simple dropdown account menu?" With AlpineJS, this is super simple to do.&lt;/p&gt;

&lt;p&gt;If you want to use AlpineJS within your Laravel app, you can of course simply use the CDN version (&lt;code&gt;&amp;lt;script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.3.5/dist/alpine.min.js" defer&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;), but when I use other scripts as well, I prefer to have it bundled to one file to reduce requests.&lt;/p&gt;

&lt;p&gt;Here's how to use AlpineJS with Laravel Mix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm install alpinejs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(in &lt;code&gt;resources/js/app.js&lt;/code&gt;) Add the line &lt;code&gt;import 'alpinejs';&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;(in &lt;code&gt;webpack.mix.js&lt;/code&gt;) Make sure &lt;code&gt;mix.js('resources/js/app.js', 'public/js')&lt;/code&gt; is there&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run dev&lt;/code&gt; (or &lt;code&gt;production&lt;/code&gt; or &lt;code&gt;watch&lt;/code&gt; instead of &lt;code&gt;dev&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;(in the Blade file where you want to use Alpine) Insert &lt;code&gt;&amp;lt;script src="{{ asset('js/app.js') }}" defer&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section&lt;/li&gt;
&lt;li&gt;Use Alpine as described in the docs, such as the following account dropdown
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div x-data="{ open: false }"&amp;gt;
    &amp;lt;button @click="open = true"&amp;gt;Open Dropdown&amp;lt;/button&amp;gt;

    &amp;lt;ul
        x-show="open"
        @click.away="open = false"
    &amp;gt;
        Dropdown Body
    &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>tech</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Laravel Forms 101</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Wed, 08 Jul 2020 01:21:14 +0000</pubDate>
      <link>https://dev.to/martin_betz/laravel-forms-101-2em6</link>
      <guid>https://dev.to/martin_betz/laravel-forms-101-2em6</guid>
      <description>&lt;p&gt;I need to admit, I always have to look up how forms work in Laravel. So consider this blog post a quick overview – and a cheatsheet for myself in several months.&lt;/p&gt;

&lt;p&gt;Here is how a simple form with one input field, say a &lt;code&gt;fullname&lt;/code&gt;, and server-side validation looks like. I will annotate every line. I use &lt;a href="//tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt; together with the &lt;a href="https://github.com/tailwindcss/custom-forms"&gt;form plugin&lt;/a&gt; to get a decent UI with minimal extra markup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- Blade, e.g. welcome.blade.php --&amp;gt;
&amp;lt;form action="{{ route('form.submit') }}" method="POST" class="space-y-4"&amp;gt;
        @csrf

        &amp;lt;div&amp;gt;
            @error('fullname')
            &amp;lt;div class="text-red-500"&amp;gt;{{ $message }}&amp;lt;/div&amp;gt;
            @enderror

            &amp;lt;label for="fullname"&amp;gt;Fullname&amp;lt;/label&amp;gt;
            &amp;lt;input type="text" name="fullname" value="{{ old('fullname') ?? '' }}" class="form-input"&amp;gt;

        &amp;lt;/div&amp;gt;

        &amp;lt;div&amp;gt;

            &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;

        &amp;lt;/div&amp;gt;

    &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;L1: &lt;code&gt;action="{{ route('form.submit') }}"&lt;/code&gt; - I use named routes to stay flexible&lt;/li&gt;
&lt;li&gt;L1: &lt;code&gt;method="POST"&lt;/code&gt; - you can set &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; directly in the &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tag, for &lt;code&gt;PUT/PATCH/DELETE&lt;/code&gt; you would need to add a &lt;code&gt;@method('PUT')&lt;/code&gt; helper in the form&lt;/li&gt;
&lt;li&gt;L2: &lt;code&gt;@csrf&lt;/code&gt; this is to protect your app from submission abuse, if you forget it, you get a &lt;code&gt;419&lt;/code&gt; error (I often forget it…)&lt;/li&gt;
&lt;li&gt;L3: Wrap each form element in a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; to style it later (I actually just use &lt;code&gt;space-y-4&lt;/code&gt; on the form so there will be vertical space between every element on the form…&lt;/li&gt;
&lt;li&gt;L4: &lt;code&gt;@error('fullname')&lt;/code&gt; you can display an error for the field with the name &lt;code&gt;fullname&lt;/code&gt; if it exists&lt;/li&gt;
&lt;li&gt;L5: &lt;code&gt;{{ $message }}&lt;/code&gt; - I often try and fail with &lt;code&gt;{{ $error }}&lt;/code&gt; first, but a good hint is that it's about the error's message…&lt;/li&gt;
&lt;li&gt;L7: &lt;code&gt;&amp;lt;label for="fullname"&amp;gt;Fullname&amp;lt;/label&amp;gt;&lt;/code&gt; Use the name of the field and a text and put it before the field&lt;/li&gt;
&lt;li&gt;L8: &lt;code&gt;name="fullname"&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; is what matters to Laravel, not &lt;code&gt;id&lt;/code&gt;. As &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname"&gt;MDN&lt;/a&gt; defines: "Name of the input form control. Submitted with the form as part of a name/value pair."&lt;/li&gt;
&lt;li&gt;L8: &lt;code&gt;value="{{ old('fullname') ?? '' }}"&lt;/code&gt; - this will get the old input if your previous submission did not validate properly and will stay empty if it's a fresh attempt. The &lt;code&gt;??&lt;/code&gt; is called &lt;a href="https://stitcher.io/blog/shorthand-comparisons-in-php#null-coalescing-operator"&gt;null-coalescing-operator&lt;/a&gt; and translates to "If there is an old value, use it, if not, use an empty string"&lt;/li&gt;
&lt;li&gt;L11: &lt;code&gt;&amp;lt;button type="submit"&amp;gt;&lt;/code&gt; - I always use a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; for submission and not &lt;code&gt;&amp;lt;input type="submit"&amp;gt;&lt;/code&gt; because I can put and style content in the buttons body (opposed to only &lt;code&gt;value="Submit"&lt;/code&gt; on the input)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get your form working, you need to catch the submission. Here's the code for that with some basic validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// routes/web.php
&amp;lt;?php

use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;

Route::get('/', function () {
    return view('welcome');
});

Route::post('/submit', function (Request $request) {
    $request-&amp;gt;validate([
        'fullname' =&amp;gt; 'required|alpha|min:3',
    ]);

    return 'Submission allowed';
})-&amp;gt;name('form.submit');

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



&lt;ul&gt;
&lt;li&gt;L3: &lt;code&gt;use Illuminate\Support\Facades\Route;&lt;/code&gt; - this is the right import for Routes (your editor might help you with the import)&lt;/li&gt;
&lt;li&gt;L4: &lt;code&gt;use Illuminate\Http\Request;&lt;/code&gt; - this is the only right import for a request (editor might help)&lt;/li&gt;
&lt;li&gt;L8: &lt;code&gt;Route::post('/submit', function (Request $request) { … }&lt;/code&gt; this is how you pass the request to this route callback function&lt;/li&gt;
&lt;li&gt;L9: &lt;code&gt;$request-&amp;gt;validate([array])&lt;/code&gt; the array holds the criteria to check the submitted fields&lt;/li&gt;
&lt;li&gt;L10: &lt;code&gt;'fullname' =&amp;gt; 'required|alpha&lt;/code&gt;, so the pipe (&lt;code&gt;|&lt;/code&gt;) is the easiest way to separate multiple validations for a field, not &lt;code&gt;,&lt;/code&gt; or &lt;code&gt;;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;L13: &lt;code&gt;-&amp;gt;name('form.submit')&lt;/code&gt; - this is how to give your route a name that you can then use with &lt;code&gt;{{ route('form.submit') }}&lt;/code&gt; in your Blade files&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Quick setup Laravel (with Tailwind scaffold)</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Tue, 30 Jun 2020 06:21:07 +0000</pubDate>
      <link>https://dev.to/martin_betz/quick-setup-laravel-with-tailwind-scaffold-593</link>
      <guid>https://dev.to/martin_betz/quick-setup-laravel-with-tailwind-scaffold-593</guid>
      <description>&lt;p&gt;I often install a fresh Laravel app to test a new package or replicate the setup for a tutorial. This is the fastest way to get a vanilla Laravel with Auth and Tailwind. The first step is only required if you have not installed the Laravel installer before (&lt;code&gt;$&lt;/code&gt; means that you have to enter that to your terminal):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(&lt;code&gt;$ composer global require laravel/installer&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ laravel new project&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$ cd project &amp;amp;&amp;amp; code .&lt;/code&gt; (opens in VSCode)&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;DB_CONNECTION=mysql&lt;/code&gt; to &lt;code&gt;DB_CONNECTION=sqlite&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remove all lines not needed for SQLite: &lt;code&gt;DB_HOST&lt;/code&gt;, &lt;code&gt;DB_PORT&lt;/code&gt;, &lt;code&gt;DB_DATABASE&lt;/code&gt;, &lt;code&gt;DB_USERNAME&lt;/code&gt; and &lt;code&gt;DB_PASSWORD&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$ touch database/database.sqlite&lt;/code&gt; to create the SQLite database&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ composer require laravel-frontend-presets/tailwindcss --dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$ php artisan ui tailwindcss --auth&lt;/code&gt; to scaffold Tailwind frontend&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$ npm install &amp;amp;&amp;amp; npm run dev&lt;/code&gt; to install the frontend&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$ php artisan migrate&lt;/code&gt; to migrate the database&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$ valet open&lt;/code&gt; or &lt;code&gt;$ php artisan serve&lt;/code&gt; to open the site&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P5ZmN4fY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://martinbetz.eu/files/articles/laravel-quick-setup.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P5ZmN4fY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://martinbetz.eu/files/articles/laravel-quick-setup.jpg" alt=""&gt;&lt;/a&gt;Source: &lt;a href="https://twitter.com/Martin_Betz/status/1256610649716723716"&gt;https://twitter.com/Martin_Betz/status/1256610649716723716&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;P.S. If you want to automate the installation and add Git and some more, you might find &lt;a href="https://github.com/tightenco/lambo"&gt;Tighten Co's Lambo&lt;/a&gt; useful.&lt;/p&gt;

</description>
      <category>tech</category>
    </item>
    <item>
      <title>Lessons Learnt: Confident Laravel</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Mon, 08 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/martin_betz/lessons-learnt-confident-laravel-33b8</link>
      <guid>https://dev.to/martin_betz/lessons-learnt-confident-laravel-33b8</guid>
      <description>&lt;p&gt;I took the course &lt;a href="https://confidentlaravel.com/"&gt;Confident Laravel&lt;/a&gt; when I was on vacation. It is suitable for total testing beginners.&lt;/p&gt;

&lt;p&gt;Here are my takeaways in the format of question and answer. They are sorted by occurence in the course but you can use whatever you need for your application and testing – not everything is related to testing:&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create a basic PHPUnit test (= extend test case)?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PHPUnit extends TestCase
{
  public function testAssertions() 
  {
    $this-&amp;gt;assertTrue(true);
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What are the testing definitions?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is &lt;code&gt;$subject&lt;/code&gt; in our tests??

&lt;ul&gt;
&lt;li&gt;The thing we want to test&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What is &lt;code&gt;$expected&lt;/code&gt;?

&lt;ul&gt;
&lt;li&gt;The result we expect!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What is &lt;code&gt;$actual&lt;/code&gt;?

&lt;ul&gt;
&lt;li&gt;Result we actually get&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What is the difference between &lt;code&gt;$expected&lt;/code&gt; and &lt;code&gt;$actual&lt;/code&gt;?

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$expected&lt;/code&gt; is hardcoded, you just enter a number, a string, a result&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$actual&lt;/code&gt; is a method that returns the actual result&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the order of loading test settings
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.testing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;phpunit.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;system environment variables&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to make stuff available to all tests?
&lt;/h2&gt;

&lt;p&gt;Add it to &lt;code&gt;tests/TestCase.php&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When and why should I use &lt;code&gt;PHPUnit\Framework\TestCase&lt;/code&gt; directly?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When Laravel tests features are not needed&lt;/li&gt;
&lt;li&gt;May boost speed when 1000s of tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to structure tests in the &lt;code&gt;feature&lt;/code&gt; folder?
&lt;/h2&gt;

&lt;p&gt;Just mimic the &lt;code&gt;app&lt;/code&gt; folder&lt;/p&gt;

&lt;h2&gt;
  
  
  How to name Dusk (= BDD) tests?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Give it the name of the feature you test, i.e. &lt;code&gt;GithubLinksTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No need to mimic the folder structure of your app&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to customize Dusk's settings?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;.env.dusk.local&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Make your Dusk specific settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to generate tests with subfolders?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;php artisan make:test Http/Controllers/HomeControllerTest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;No leading &lt;code&gt;app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No trailing &lt;code&gt;.php&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to name factories?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ModelnameFactory&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;e.g. &lt;code&gt;UserFactory&lt;/code&gt; (&lt;code&gt;php artisan make:factory UserFactory&lt;/code&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function() {
  return $this;

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to filter &lt;code&gt;php artisan route:list&lt;/code&gt; for entries containing &lt;code&gt;invoice&lt;/code&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;php artisan route:list --name invoice&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to test whether the right view gets loaded?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertViewIs('invoice.create')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the &lt;em&gt;happy path&lt;/em&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Testing when the subject is working as expected&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to check in controller if column &lt;code&gt;expired&lt;/code&gt; with timestamp is not set?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Model::whereNull('expired')-&amp;gt;get()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to put sth like a coupon in the session cookie?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$request-&amp;gt;session()-&amp;gt;put('name', 'value')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to name general controller tests?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;it_does_this_and_that()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;e.g. &lt;code&gt;it_stores_coupon_and_redirects()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to check whether data exists in a session?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assertSessionHas('key', 'value');&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to get the full error message in Laravel tests?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$this-&amp;gt;withoutExceptionHandling();&lt;/code&gt; in test method&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How many sad paths should you test?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Enough to feel confident&lt;/li&gt;
&lt;li&gt;There are potentially unlimited sad paths&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to assert that sth is not in a session?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertSessionMissing('key', 'value');&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's the running order in a test?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Arrange&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$response = $this-&amp;gt;get(route('name'));&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assert…();&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to mark test incomplete so it gets skipped when running the test suite?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;markTestIncomplete();&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to test that user is logged in (and not redirected)?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertAuthenticatedAs($user);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Do not assert on &lt;code&gt;$response&lt;/code&gt; but on global state &lt;code&gt;$this&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to assert that a view has a variable &lt;code&gt;now_playing&lt;/code&gt; with value &lt;code&gt;1&lt;/code&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assertViewHas('now_playing', 1);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to fake a heading or title?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$faker-&amp;gt;sentence&lt;/code&gt; or &lt;code&gt;$faker-&amp;gt;word(3, true)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;true&lt;/code&gt; as 2nd argument in &lt;code&gt;$faker-&amp;gt;word&lt;/code&gt; to get words, otherwise you get an array&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to fake an ID?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$faker-&amp;gt;md5&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to assert the model data you already have in your test?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Goal: Refresh user record, because it go changed&lt;/li&gt;
&lt;li&gt;Not using: &lt;code&gt;$this-&amp;gt;assertDatabaseHas()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$user-&amp;gt;refresh();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Assert properties of model&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;$this-&amp;gt;assertEquals(1, $user-&amp;gt;last_viewed_vidoe_id)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to add &lt;code&gt;$faker&lt;/code&gt; to your test?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;use WithFaker;&lt;/code&gt; trait to your test class&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create a password hash?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Hash::make('STRING')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to assert two hashes?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;NOT: &lt;code&gt;$this-&amp;gt;assertEquals(Hash::make($password, $user-&amp;gt;password);&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;BUT: &lt;code&gt;$this-&amp;gt;assertTrue(Hash::check($password, $user-&amp;gt;password);&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the difference between asserting &lt;code&gt;Hash::check()&lt;/code&gt; and hardcoding a password value?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Hash:check&lt;/code&gt;: tie test to the implementation of the HASH function&lt;/li&gt;
&lt;li&gt;Hardcoding: Setting a sample value is more flexible but also more error prone&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to check if session contains error 'name'?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assertSessionHasErrors('name');&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why do form requests not auto redirect back and how to work around that?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;They send referrer URL&lt;/li&gt;
&lt;li&gt;These are fresh with every request =&amp;gt; no history available&lt;/li&gt;
&lt;li&gt;Instead: Set the referrer URL manually in the setup&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;from(route('user.edit'))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to avoid writing dozens of assertions in form validations?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use Form Requests&lt;/li&gt;
&lt;li&gt;Assert that Form Request gets used by the controller&lt;/li&gt;
&lt;li&gt;Use Jason McCreary's Laravel Test Asserts for that
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

// In test method
$this-&amp;gt;assertActionUsesFormRequest(
  UsersController::class, // Controller
  'update', // Method
  UserUpdateRequest::class); // Form Request
);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to find incomplete tests?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;phpunit -v&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to directly assert non-auth cannot access?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertForbidden();&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to manually set response 'forbidden' on controller?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;abort(403)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to get &lt;code&gt;Product::STARTER&lt;/code&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This is a constant in the product model&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is a mock?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stand-in replacement for real object&lt;/li&gt;
&lt;li&gt;Emulates &lt;code&gt;echo&lt;/code&gt; behaviour
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// What is the simplest mock you can create?
class ExampleTest extends \PHPUnit\Framework\TestCase
{
  public function testMocking()
  {
    $mock = \Mockery::mock();
    $mock-&amp;gt;shouldReceive('foo') // method name
      -&amp;gt;with('bar') // arg
      -&amp;gt;andReturn('baz'); // arg
    $this-&amp;gt;assertEquals('baz', $mock-&amp;gt;foo('bar'));
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What are mocks great for?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Testing integratin with 3rd party libraries without calling them&lt;/li&gt;
&lt;li&gt;Control testing in complex situations, because you break down problems in small chunks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When will mocks fail?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If not set&lt;/li&gt;
&lt;li&gt;If it does not have an expectation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is a spy?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It secretly captures behavior&lt;/li&gt;
&lt;li&gt;Returns null if not setup at all&lt;/li&gt;
&lt;li&gt;More forgiving than mock&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's the easiest spy you can write?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function testSpying()
{
  $spy = Mockery::spy();
  $this-&amp;gt;assertNull($spy-&amp;gt;quix());

  // assert behavior
  $spy-&amp;gt;shouldHaveReceived('quix')-&amp;gt;once();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What are test doubles?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Replace production object for testing purposes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why are facades easy to test in Laravel?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every facade has mocks &amp;amp; spies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to return nothing (do nothing after a request)?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;return response(null, 204)&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to mock Laravel's &lt;code&gt;Log&lt;/code&gt; facade?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$mock = \Mockery::mock();
$mock-&amp;gt;shouldReceive('info') // method name
  -&amp;gt;once()
  -&amp;gt;with('video.watched', [$video-&amp;gt;id]);
Log::swap($mock);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What is the difficulty with shared facades?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Facades like &lt;code&gt;Event&lt;/code&gt; or &lt;code&gt;Log&lt;/code&gt; get used all over Laravel&lt;/li&gt;
&lt;li&gt;If you swap them in your test, they get swapped everywhere&lt;/li&gt;
&lt;li&gt;This may cause trouble&lt;/li&gt;
&lt;li&gt;You can use &lt;code&gt;Event::fake()&lt;/code&gt; instead of &lt;code&gt;Event::swap()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Example: To check if event was fired: &lt;code&gt;$event-&amp;gt;assertDispatched();&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to do instead of mocks?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When you can't fake or don't want to create dozens of mock classes&lt;/li&gt;
&lt;li&gt;Wrape it and decouple from tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What happens in this mock?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The real &lt;code&gt;Log::&lt;/code&gt; class gets swapped by the mock&lt;/li&gt;
&lt;li&gt;The mock tells what should happen as a result&lt;/li&gt;
&lt;li&gt;As there is an expectation (= log vars), you need no extra assertion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why do I need the &lt;code&gt;Log::&lt;/code&gt; facade at all?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It's the original code&lt;/li&gt;
&lt;li&gt;It would go untested otherwise&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why do you use &lt;code&gt;-&amp;gt;once()&lt;/code&gt; in a mock?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Otherwise the test will pass if the double in the real code is not called at all&lt;/li&gt;
&lt;li&gt;i.e. only with &lt;code&gt;-&amp;gt;once()&lt;/code&gt;, you can make sure that the facade got used in the real code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is a shortcut for &lt;code&gt;$mock-&amp;gt;shouldReceive('info')-&amp;gt;once()&lt;/code&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$mock-&amp;gt;expects('info');&lt;/code&gt; // method name&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create a setup method that runs for all tests in a file?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected function setUp(): void
{
  parent::setUp();
  $this-&amp;gt;subject = new UserUpdateRequest();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Use it with &lt;code&gt;$this-&amp;gt;subject&lt;/code&gt; in the tests&lt;/p&gt;

&lt;h2&gt;
  
  
  How to run a validation in an unit test?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$subject = new UserUpdateRequest();
// will call the file App\Http\Requests\UserUpdateRequest;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to create a coverage report
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You need xdebug&lt;/li&gt;
&lt;li&gt;You can use a docker image with xdebug&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;phpunit --coverage-html report&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Spin up a PHP server to view reports with &lt;code&gt;php -S 0:8080 -t report/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Lessons Learnt: PHPUnit for Beginners</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Mon, 08 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/martin_betz/lessons-learnt-phpunit-for-beginners-4p36</link>
      <guid>https://dev.to/martin_betz/lessons-learnt-phpunit-for-beginners-4p36</guid>
      <description>&lt;p&gt;I took the course &lt;a href="https://laraveldaily.teachable.com/p/laravel-phpunit-testing-for-beginners"&gt;PHPUnit for Beginners by Laravel Daily&lt;/a&gt;. It is suitable for total testing beginners and walks you through a simple CRUD application.&lt;/p&gt;

&lt;p&gt;Here are my takeaways in the format of question and answer. They are sorted by occurence in the course but you can use whatever you need for your application and testing – not everything is related to testing:&lt;/p&gt;

&lt;h2&gt;
  
  
  Why choose &lt;code&gt;@forelse … @empty … @endforelse&lt;/code&gt; for loops?
&lt;/h2&gt;

&lt;p&gt;It covers the case where there is no data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@forelse ($users as $user)
     &amp;lt;li&amp;gt;{{ $user-&amp;gt;name }}&amp;lt;/li&amp;gt;
@empty
    &amp;lt;p&amp;gt;No users&amp;lt;/p&amp;gt;
@endforelse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to create content with custom values with Eloquent
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$product = Product:create([
  'name' =&amp;gt; 'Product 1',
  'price' =&amp;gt; 99.99
]);

// in your test
$response-&amp;gt;assertSee($product-&amp;gt;name);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to setup test database?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;phpunit.xml&lt;/code&gt; overwrites &lt;code&gt;.env.testing&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Edit &lt;code&gt;DB_CONNECTION&lt;/code&gt; for &lt;code&gt;MySQL/sqlite&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Change value of &lt;code&gt;DB_DATABASE&lt;/code&gt; into &lt;code&gt;value=":memory:"&lt;/code&gt; to get fast in memory store&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What does &lt;code&gt;RefreshDatabase&lt;/code&gt; trait do?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It Runs migrations&lt;/li&gt;
&lt;li&gt;Creates a fresh database&lt;/li&gt;
&lt;li&gt;Usage

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;use Illuminate\Foundation\Testing\RefreshDatabase;&lt;/code&gt; above class&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;use RefreshDatabase;&lt;/code&gt; in class, not single test&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When should you use a MySQL test database?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When you use raw MySQL statements for the following features:

&lt;ul&gt;
&lt;li&gt;Date formatting&lt;/li&gt;
&lt;li&gt;String functions&lt;/li&gt;
&lt;li&gt;Date differences&lt;/li&gt;
&lt;li&gt;Geospatial features&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to set up a MySQL test database in &lt;code&gt;phpunit.xml&lt;/code&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;server name="DB_CONNECTION" value="MySQL"/&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;server name="DB_DATABASE" value="name_of_db"/&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why to test data and not visuals (assertSee)?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To avoid false positives because of incomplete results&lt;/li&gt;
&lt;li&gt;Example

&lt;ul&gt;
&lt;li&gt;Blade: show product name &lt;code&gt;{{ $product-&amp;gt;name }}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Data: &lt;code&gt;['name' =&amp;gt; 'Product 1000]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Visual test: &lt;code&gt;$response-&amp;gt;assertSee('Product 1')&lt;/code&gt; would turn green and create a false positive&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to get view data of e.g. $products to test?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$view = $response-&amp;gt;viewData('products') // was passed to view in controller
$this-&amp;gt;assertEquals($product-&amp;gt;name, $view-&amp;gt;first()-&amp;gt;name);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What do unit tests capture?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Internal logic&lt;/li&gt;
&lt;li&gt;No Endpoint&lt;/li&gt;
&lt;li&gt;Data processing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create a Laravel service to translate currency
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create service in &lt;code&gt;app\services&lt;/code&gt; -&amp;gt; &lt;code&gt;CurrencyService.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Import using &lt;code&gt;use App\Services\CurrencyService&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;new CurrencyService()-&amp;gt;convert();&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No changes in database needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create temporary database/accessor field (e.g. dynamic price in another currency)?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This is also called accessor&lt;/li&gt;
&lt;li&gt;On model &lt;code&gt;Product.php&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function getPriceEurAttribute() {
    return $this-&amp;gt;price*0.8;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to create an unit test?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;art make:test NAME --unit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to paginate in controller and view?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;(In Controller): &lt;code&gt;$products = Product::paginate(10);&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In View: &lt;code&gt;{{ $products-&amp;gt;links() }}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to call factories?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;factory(Product::class, 10)-&amp;gt;create();&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to echo variable result into log?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Call &lt;code&gt;info($var)&lt;/code&gt; in your code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to test if login works?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create user&lt;/li&gt;
&lt;li&gt;Post login data and set response
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$response = $this-&amp;gt;post('login', [
  'email' =&amp;gt; 'EMAIL',
  'password' =&amp;gt; 'PW'
]);
// assert where you expect to be redirected to, e.g. home
$response-&amp;gt;assertRedirect('/home');
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to quickly log in for tests?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;actingAs($user)-&amp;gt;get('/')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to protect a route via auth?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Route::get('/')-&amp;gt;middleware('auth')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Easiest way to add admin?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add field to user model: &lt;code&gt;is_admin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add to fillable in model&lt;/li&gt;
&lt;li&gt;Create middleware &lt;code&gt;app\Http\Middleware\IsAdmin&lt;/code&gt; (see following snippet)&lt;/li&gt;
&lt;li&gt;Add middleware to &lt;code&gt;App\Kernel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add middleware to your route &lt;code&gt;Route::middleware('auth', 'is_admin')&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function handle($request, Closure $next) 
{
  if (! auth()-&amp;gt;user()-&amp;gt;is_admin) 
  {
    abort(403);
  }
  return $next($request);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Which visual assertions are usual?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assertSee()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assertDontSee()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create simple factory states?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;is_admin&lt;/code&gt;, yes/no&lt;/li&gt;
&lt;li&gt;Create private function with factory and optional parameter in it
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private function create_user(is_admin = 0)
{
  $this-&amp;gt;user = factory(User::class)-&amp;gt;create([
    'is_admin' =&amp;gt; $is_admin,
  ]);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  How to store everything you get via form?
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Controller

public function store(Request $request)
{
    Product::create($request-&amp;gt;all());
    return redirect()-&amp;gt;route('home');
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to test a POST request with parameter &lt;code&gt;name = 'Test 1'&lt;/code&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;post('products', ['name' =&amp;gt; 'Test 1', 'price' =&amp;gt; 99.99]);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to assert that something is in the database? (db side)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertDatabaseHas('products', ['name' =&amp;gt; 'Test 1', 'price' =&amp;gt; 99.99]);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to test whether saved data gets returned?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$product = Product::orderBy('id', 'desc')-&amp;gt;first();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertEquals('String', $product-&amp;gt;name);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertEquals('price', $product-&amp;gt;price);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to check whether data for edit is available in view?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$product = Product::first();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assertSee('value="' . $product-&amp;gt;price . '"');&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to update all data from a request?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function update(Product $product, UpdateProductRequest $request)
{
  $product-&amp;gt;update($request-&amp;gt;all());
  return redirect()-&amp;gt;route('products.index');
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Where and how to create a form request?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app/Http/Requests/UpdateProductRequest.php&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public rules() {
  return [
    'name' =&amp;gt; 'required',
    'price' =&amp;gt; 'required',
  ];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to test an update request?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;$response = $this-&amp;gt;put('/products/' . $product-&amp;gt;id, ['name' =&amp;gt; 'Test']);&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to test for session error on 'name'?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;$response-&amp;gt;assertSessionHasErrors(['name']);&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to update as json API call?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$response = $this-&amp;gt;actingAs($this-&amp;gt;user)
  -&amp;gt;put('/products/' . $product-&amp;gt;id,
  [
    'name' =&amp;gt; 'Test',
    'price' =&amp;gt; 99.99,
  ],
  [
   'Accept' =&amp;gt; 'Application/json', 
  ]);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to create a delete item view?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form action={{ route('products.destroy' . $product-&amp;gt;id) }} method="POST" onsubmit="confirm('Sure?')"&amp;gt;
&amp;lt;input type="hidden" name="_method" value="DELETE"&amp;gt;
&amp;lt;input type="hidden" name="_token" value="{{ csrf_token() }}"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to delete item in controller?
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function destroy(Product $product) {
  $product-&amp;gt;delete();
  return redirect()-&amp;gt;route('products.index');
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How to assert that data gets deleted?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create product with factory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertEquals(1, Product::all())&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$response = $this-&amp;gt;actingAs($this-&amp;gt;user)-&amp;gt;delete('products/' . $product-&amp;gt;id);&lt;/code&gt; (Route missing?)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$response-&amp;gt;assertStatus(302)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$this-&amp;gt;assertEquals(0, Product::count());&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>How to protect URLs with a PIN code in Laravel</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Tue, 26 May 2020 16:10:15 +0000</pubDate>
      <link>https://dev.to/martin_betz/how-to-protect-urls-with-a-pin-code-in-laravel-3fkp</link>
      <guid>https://dev.to/martin_betz/how-to-protect-urls-with-a-pin-code-in-laravel-3fkp</guid>
      <description>&lt;p&gt;Here is the user story for this post: As a website owner I only want to allow access to my website for visitors who enter the correct PIN.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the minimum version will work
&lt;/h2&gt;

&lt;p&gt;When you enter the page for the first time, you will just see an input to enter a PIN. When you enter the wrong PIN, it fails silently and just reloads the page. If you enter the right PIN, it will save a cookie &lt;code&gt;access&lt;/code&gt; and shows you the welcome page. If you try more than 3 times within a minute, you get a message &lt;code&gt;Too Many Requests&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And here is how it will look in the browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/img/articles/pin-access-demo.gif" class="article-body-image-wrapper"&gt;&lt;img class="border-2 rounded border-grey shadow-inline" src="/assets/img/articles/pin-access-demo.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The tests
&lt;/h2&gt;

&lt;p&gt;I will first create the sad path where I cannot access the welcome page as I did not enter the right PIN. Then I will simulate that I previously entered the right PIN and have a cookie that lets me pass. Then I will test that actual entering of the PIN and check whether I get a cookie. Lastly I check that I get banned if I enter three wrong PINs in a very short time:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Support\Facades\Config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Tests\TestCase&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;WelcomeTest&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="cd"&gt;/** @test */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;can_not_access_welcome_page_without_pin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'root'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pin.create'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/** @test */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;can_access_welcome_page_with_pin_cookie&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;withCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'access'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'pass'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'root'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertStatus&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="cd"&gt;/** @test */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;can_enter_pin_and_access_root_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'settings.PIN'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'5678'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pin.store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'pin'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'5678'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]));&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'access'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'pass'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/** @test */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;blocks_for_one_minute_after_three_attemps&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="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pin.store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'pin'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'1'&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="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pin.store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'pin'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'2'&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="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pin.store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'pin'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]));&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pin.store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'pin'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]));&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&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;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;I wrote the tests first and added the code one error after another. You may replicate by just running the tests above and go through the errors yourself.&lt;/p&gt;

&lt;p&gt;Here's the files you need with a short explanation what they do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;routes/web.php&lt;/code&gt;: for adding the routes, adding the middleware to restrict access and limit the trials&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/Http/Middleware/CheckPin.php&lt;/code&gt;: this is the middleware that checks whether you have a cookie that allows you to enter the welcome page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/Http/Kernel.php&lt;/code&gt;: this is were you register the custom middleware&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/Http/Controllers/PinController.php&lt;/code&gt;: this is were you check the PIN entered and create the cookie on success&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resources/views/create.blade.php&lt;/code&gt;: the view for entering the PIN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resources/views/welcome.blade.php&lt;/code&gt;: the view with the protected content&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;config/settings.php&lt;/code&gt;: you define the PIN setting here to get the value from the &lt;code&gt;.env&lt;/code&gt; file and provide a fallback value&lt;/li&gt;
&lt;li&gt;`&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are the important sections of the files. I marked omissions with &lt;code&gt;(…)&lt;/code&gt;. You can find the full source code on &lt;a href="https://github.com/minthemiddle/pin-tutorial"&gt;https://github.com/minthemiddle/pin-tutorial&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
// routes/web.php&lt;br&gt;
&amp;lt;?php&lt;/p&gt;

&lt;p&gt;use Illuminate\Support\Facades\Route;&lt;/p&gt;

&lt;p&gt;Route::get('/', function () {&lt;br&gt;
    return view('welcome');&lt;br&gt;
})-&amp;gt;name('root')-&amp;gt;middleware('pin');&lt;/p&gt;

&lt;p&gt;Route::get('pin/create', function () {&lt;br&gt;
    return view('create');&lt;br&gt;
})-&amp;gt;name('pin.create');&lt;/p&gt;

&lt;p&gt;Route::post('pin/store', 'PinController@store')-&amp;gt;name('pin.store')-&amp;gt;middleware('throttle:3,1');&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
// app/Http/Middleware/CheckPin.php&lt;br&gt;
&amp;lt;?php&lt;/p&gt;

&lt;p&gt;namespace App\Http\Middleware;&lt;/p&gt;

&lt;p&gt;use Closure;&lt;/p&gt;

&lt;p&gt;class CheckPin&lt;br&gt;
{&lt;br&gt;
    public function handle($request, Closure $next)&lt;br&gt;
    {&lt;br&gt;
        if ($request-&amp;gt;cookie('access') === 'pass') {&lt;br&gt;
            return $next($request);&lt;br&gt;
        }&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    return redirect(route('pin.create'));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
// app/Http/Kernel.php&lt;br&gt;
&amp;lt;?php&lt;/p&gt;

&lt;p&gt;namespace App\Http;&lt;/p&gt;

&lt;p&gt;use App\Http\Middleware\CheckPin;&lt;br&gt;
use Illuminate\Foundation\Http\Kernel as HttpKernel;&lt;/p&gt;

&lt;p&gt;class Kernel extends HttpKernel&lt;br&gt;
{&lt;br&gt;
    (…)&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected $routeMiddleware = [
    (…)
    \App\Http\Middleware\CheckPin::class,
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
// app/Http/Controllers/PinController.php&lt;br&gt;
&amp;lt;?php&lt;/p&gt;

&lt;p&gt;namespace App\Http\Controllers;&lt;/p&gt;

&lt;p&gt;use Illuminate\Http\Request;&lt;br&gt;
use Illuminate\Support\Facades\Config;&lt;/p&gt;

&lt;p&gt;class PinController extends Controller&lt;br&gt;
{&lt;br&gt;
    public function store(Request $request)&lt;br&gt;
    {&lt;br&gt;
        if ($request-&amp;gt;pin === Config::get('settings.PIN')) {&lt;br&gt;
            return redirect(route('root'))-&amp;gt;withCookie('access', 'pass', 60);&lt;br&gt;
        }&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    return redirect(route('pin.create'));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`html&lt;br&gt;
// resources/views/create.blade.php&lt;br&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    Enter PIN&lt;br&gt;
&lt;br&gt;



    @csrf
    
    Save




&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
// resources/views/welcome.blade.php&lt;br&gt;
// I just used the standard welcome page that ships with Laravel&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;php&lt;br&gt;
// config/settings.php&lt;br&gt;
&amp;lt;?php&lt;/p&gt;

&lt;p&gt;return [&lt;br&gt;
    'PIN' =&amp;gt; env('PIN', '1234'),&lt;br&gt;
];&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;yaml&lt;/p&gt;

&lt;h1&gt;
  
  
  .env
&lt;/h1&gt;

&lt;p&gt;(…)&lt;br&gt;
PIN=5678&lt;br&gt;
(…)&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>route</category>
    </item>
    <item>
      <title>Testing mails in Laravel</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Tue, 28 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/martin_betz/testing-mails-in-laravel-5f7c</link>
      <guid>https://dev.to/martin_betz/testing-mails-in-laravel-5f7c</guid>
      <description>&lt;h2&gt;
  
  
  The case: Test that users can send mails to other users
&lt;/h2&gt;

&lt;p&gt;Imagine a simple social network where users can send emails to other users. We will use Laravel and test driven development to create an app that does exactly this.&lt;/p&gt;

&lt;p&gt;An user visits the profile of another user and when he clicks on "Message" he can send a customized email to the other user via the system. He can even give a custom subject.&lt;/p&gt;

&lt;p&gt;I know that for such a simple use case we could just use &lt;code&gt;&amp;lt;a href="mailto:name@domain.com"&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt; but I want to show you how to use and test email in Laravel.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;You just need a fresh Laravel app. At the time of writing this article this was v7.8.1, but anything after v5.6 should be 80% matching (please report issues). For a minimal setup, remove all lines starting with &lt;code&gt;DB_&lt;/code&gt; in your &lt;code&gt;.env&lt;/code&gt;, add &lt;code&gt;DB_CONNECTION=sqlite&lt;/code&gt;, create a file called &lt;code&gt;database.sqlite&lt;/code&gt; in the &lt;code&gt;/database&lt;/code&gt; folder and run &lt;code&gt;php artisan migrate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The test
&lt;/h2&gt;

&lt;p&gt;We will first right an automated test. This will fail and we will add code step by step to fix the problems to finally get a test that gives us confidence that the code works as intended.&lt;/p&gt;

&lt;p&gt;Let's create the test: &lt;code&gt;php artisan make:test ContactUserTest&lt;/code&gt;. I will show you how my initial test looks like, but please be aware that I spent around 10 minute into thinking "How should this work?". Writing the test is when you define how you wish your app should work. We are first testing the expected action (&lt;code&gt;it_does_send_a_mail_from_one_user_to_another&lt;/code&gt;). This is called the happy path. We will later check that unexpected behavior does not happen – the sad path.&lt;/p&gt;

&lt;p&gt;I'll explain the details after the code, but I left some problems in there so you can see how test driven development (TDD) works. Write a failing test and fix one problem after the other until you get a passing test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Tests\Feature;

use App\User;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;

class ContactUserTest extends TestCase
{
    /** @test */
    public function it_does_send_a_mail_from_one_user_to_another()
    {
        $user_from = factory(User::class)-&amp;gt;create();
        $user_to = factory(User::class)-&amp;gt;create();

        Mail::fake();

        $response = $this-&amp;gt;post(route('contactUserMail'), [
            'user_to' =&amp;gt; $user_to,
            'subject' =&amp;gt; 'My subject',
            'body' =&amp;gt; 'My body',
        ]);

        $response-&amp;gt;assertSuccessful();

        Mail::assertSent(ContactUserMail::class);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I first create two users, the sender and the receiver (&lt;code&gt;$user_to&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;We will use the logged in user as the sender, so we don't need to send this info with the request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Mail::fake()&lt;/code&gt; will swap the actual &lt;code&gt;Mail&lt;/code&gt; class with a test library. No real mails will be sent and we can make assertions on what should happen&lt;/li&gt;
&lt;li&gt;I decided that sending a mail should be a &lt;code&gt;POST&lt;/code&gt; request from a form and have &lt;code&gt;user_to&lt;/code&gt;, &lt;code&gt;subject&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; arguments. I will get the &lt;code&gt;user_from&lt;/code&gt; automatically from the currently logged in user to prevent that you can send in someone else's name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$response-&amp;gt;assertSuccessful()&lt;/code&gt; will check whether the &lt;code&gt;POST&lt;/code&gt; request was successful&lt;/li&gt;
&lt;li&gt;Finally, I check whether the Mail class &lt;code&gt;ContactUserMail&lt;/code&gt; was sent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As expected, there are a couple of errors, but let &lt;code&gt;phpunit&lt;/code&gt; tell us what's wrong…&lt;/p&gt;

&lt;p&gt;Just run &lt;code&gt;phpunit&lt;/code&gt; within your project - with Laravel 7+ you can also use &lt;code&gt;php artisan test&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 01: No database being used
&lt;/h2&gt;

&lt;p&gt;The error: &lt;code&gt;SQLSTATE[HY000]: General error: 1 no such table: users&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Our test is not using the database yet, let's add the &lt;code&gt;RefreshDatabase&lt;/code&gt; trait to solve this.&lt;/p&gt;

&lt;p&gt;Note: I will show git diffs for solving the problems. This diff compares before &lt;code&gt;a/&lt;/code&gt; and after &lt;code&gt;b/&lt;/code&gt;. A &lt;code&gt;+&lt;/code&gt; means that something was added, a &lt;code&gt;-&lt;/code&gt; shows deleted lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/tests/Feature/ContactUserTest.php b/tests/Feature/ContactUserTest.php
index 89de017..a611b89 100644
--- a/tests/Feature/ContactUserTest.php
+++ b/tests/Feature/ContactUserTest.php
@@ -3,11 +3,14 @@
 namespace Tests\Feature;

 use App\User;
+use Illuminate\Foundation\Testing\RefreshDatabase;
 use Illuminate\Support\Facades\Mail;
 use Tests\TestCase;

 class ContactUserTest extends TestCase
 {
+ use RefreshDatabase;
+
     /** @test */
     public function it_does_send_a_mail_from_one_user_to_another()
     {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Problem 02: Route not defined
&lt;/h2&gt;

&lt;p&gt;The error: &lt;code&gt;Symfony\Component\Routing\Exception\RouteNotFoundException: Route [contactUserMail] not defined.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Well, we called a route that does not exist yet. Let's create it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/routes/web.php b/routes/web.php
index b130397..4ecc7b7 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -16,3 +16,7 @@ use Illuminate\Support\Facades\Route;
 Route::get('/', function () {
     return view('welcome');
 });
+
+Route::post('contactUserMail', function() {
+ return true;
+})-&amp;gt;name('contactUserMail');
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This route may seem stupid, because I just return &lt;code&gt;true&lt;/code&gt;, but for now it is just important to solve the error that &lt;code&gt;phpunit&lt;/code&gt; showed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 03: Mail was not sent
&lt;/h2&gt;

&lt;p&gt;The error: &lt;code&gt;The expected [Tests\Feature\ContactUserMail] mailable was not sent.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ok, let's create the email first and leave as is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php art make:mail ContactUserMail -m emails.contactUserMail&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create the mail class and a markdown template.&lt;/p&gt;

&lt;p&gt;We have to update the route to actually send the mail with &lt;code&gt;Mail::to('test@test.com')-&amp;gt;send(new ContactUserMail);&lt;/code&gt;. Again, the goal is not to be right, but to get the test passing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/routes/web.php b/routes/web.php
index 4ecc7b7..9ed75ee 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -1,5 +1,7 @@
 &amp;lt;?php

+use App\Mail\ContactUserMail;
+use Illuminate\Support\Facades\Mail;
 use Illuminate\Support\Facades\Route;

 /*
@@ -18,5 +20,6 @@ Route::get('/', function () {
 });

 Route::post('contactUserMail', function() {
+ Mail::to('test@test.com')-&amp;gt;send(new ContactUserMail);
     return true;
 })-&amp;gt;name('contactUserMail');
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Lastly, we need to import the Mail class to the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/tests/Feature/ContactUserTest.php b/tests/Feature/ContactUserTest.php
index a611b89..4d208a6 100644
--- a/tests/Feature/ContactUserTest.php
+++ b/tests/Feature/ContactUserTest.php
@@ -2,6 +2,7 @@

 namespace Tests\Feature;

+use App\Mail\ContactUserMail;
 use App\User;
 use Illuminate\Foundation\Testing\RefreshDatabase;
 use Illuminate\Support\Facades\Mail;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;phpunit&lt;/code&gt; again and… &lt;code&gt;✔ It does send a mail from one user to another&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Congratulations, our test is passing, we are sending the mail as expected.&lt;/p&gt;

&lt;p&gt;But wait, we did not check that &lt;code&gt;user_from&lt;/code&gt; and &lt;code&gt;user_to&lt;/code&gt; are right. Our test is incomplete.&lt;/p&gt;

&lt;p&gt;This is also a common case, so no worries. Just add more assertions to your test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/tests/Feature/ContactUserTest.php b/tests/Feature/ContactUserTest.php
index fb6532d..64df550 100644
--- a/tests/Feature/ContactUserTest.php
+++ b/tests/Feature/ContactUserTest.php
@@ -28,6 +28,10 @@ class ContactUserTest extends TestCase

         $response-&amp;gt;assertSuccessful();

- Mail::assertSent(ContactUserMail::class);
+ Mail::assertSent(ContactUserMail::class, function($mail) use ($user_from, $user_to) {
+ $mail-&amp;gt;build();
+ $this-&amp;gt;assertEquals($user_from-&amp;gt;email, $mail-&amp;gt;from[0]['address']);
+ $this-&amp;gt;assertTrue($mail-&amp;gt;hasTo($user_to-&amp;gt;email));
+ return true;
+ });
     }
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;phpunit&lt;/code&gt; again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 04: From is not right
&lt;/h2&gt;

&lt;p&gt;Error: &lt;code&gt;ErrorException: Trying to get property 'address' of non-object&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ok, we did not set the sender yet. Let's do this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/app/Mail/ContactUserMail.php b/app/Mail/ContactUserMail.php
index 017b66c..0577a18 100644
--- a/app/Mail/ContactUserMail.php
+++ b/app/Mail/ContactUserMail.php
@@ -28,6 +28,6 @@ class ContactUserMail extends Mailable
      */
     public function build()
     {
- return $this-&amp;gt;markdown('emails.contactUserMail');
+ return $this-&amp;gt;from('sender@test.com')-&amp;gt;markdown('emails.contactUserMail');
     }
 }

diff --git a/tests/Feature/ContactUserTest.php b/tests/Feature/ContactUserTest.php
index d47f85f..947757c 100644
--- a/tests/Feature/ContactUserTest.php
+++ b/tests/Feature/ContactUserTest.php
@@ -15,7 +15,9 @@ class ContactUserTest extends TestCase
     /** @test */
     public function it_does_send_a_mail_from_one_user_to_another()
     {
- $user_from = factory(User::class)-&amp;gt;create();
+ $user_from = factory(User::class)-&amp;gt;create([
+ 'email' =&amp;gt; 'sender@test.com',
+ ]);
         $user_to = factory(User::class)-&amp;gt;create();
     }
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Problem 05: From is not right
&lt;/h2&gt;

&lt;p&gt;Error: &lt;code&gt;Failed asserting that false is true&lt;/code&gt;(&lt;code&gt;ContactUserTest.php:36&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;So, now the &lt;code&gt;to&lt;/code&gt; is not correct. Of course, we did not specify the email in the factory, so we have differing emails. Let's fix this!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/tests/Feature/ContactUserTest.php b/tests/Feature/ContactUserTest.php
index 9f2b79d..3f72373 100644
--- a/tests/Feature/ContactUserTest.php
+++ b/tests/Feature/ContactUserTest.php
@@ -18,7 +18,9 @@ class ContactUserTest extends TestCase
         $user_from = factory(User::class)-&amp;gt;create([
             'email' =&amp;gt; 'sender@test.com',
         ]);
- $user_to = factory(User::class)-&amp;gt;create();
+ $user_to = factory(User::class)-&amp;gt;create([
+ 'email' =&amp;gt; 'test@test.com',
+ ]);

         Mail::fake();

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



&lt;p&gt;Run &lt;code&gt;phpunit&lt;/code&gt; again and boom, &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt; work as expected!&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;subject&lt;/code&gt; is still missing. Add an assertion to the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/tests/Feature/ContactUserTest.php b/tests/Feature/ContactUserTest.php
index 3f72373..9840e1b 100644
--- a/tests/Feature/ContactUserTest.php
+++ b/tests/Feature/ContactUserTest.php
@@ -36,6 +36,7 @@ class ContactUserTest extends TestCase
             $mail-&amp;gt;build();
             $this-&amp;gt;assertEquals($user_from-&amp;gt;email, $mail-&amp;gt;from[0]['address']);
             $this-&amp;gt;assertTrue($mail-&amp;gt;hasTo($user_to-&amp;gt;email));
+ $this-&amp;gt;assertEquals('My subject', $mail-&amp;gt;subject);
             return true;
         });
     }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Problem 05: Subject not working
&lt;/h2&gt;

&lt;p&gt;Error: &lt;code&gt;TypeError: Argument 2 passed to PHPUnit\Framework\Assert::assertTrue() must be of the type string, null given&lt;/code&gt; (&lt;code&gt;ContactUserTest.php:39&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;This simply means that &lt;code&gt;$mail-&amp;gt;subject&lt;/code&gt; is empty.&lt;/p&gt;

&lt;p&gt;Let's solve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/app/Mail/ContactUserMail.php b/app/Mail/ContactUserMail.php
index 0577a18..1e7258f 100644
--- a/app/Mail/ContactUserMail.php
+++ b/app/Mail/ContactUserMail.php
@@ -28,6 +28,6 @@ class ContactUserMail extends Mailable
      */
     public function build()
     {
- return $this-&amp;gt;from('sender@test.com')-&amp;gt;markdown('emails.contactUserMail');
+ return $this-&amp;gt;from('sender@test.com')-&amp;gt;subject('My subject')-&amp;gt;markdown('emails.contactUserMail');
     }
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;phpunit&lt;/code&gt; again and yay, the test is passing. You can be confident now that an email is sent with the expected &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;to&lt;/code&gt; and &lt;code&gt;subject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's call it a day for now and tap yourself on the shoulder, this was massive.&lt;/p&gt;

&lt;p&gt;There will be a part 2 because, to be honest, we did not completely solve it. Right now, all the values are hard coded and not coming from a user's request. We will tackle this soon.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>tdd</category>
      <category>email</category>
    </item>
    <item>
      <title>Premium Laravel courses and books</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Mon, 27 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/martin_betz/premium-laravel-courses-and-books-5b1h</link>
      <guid>https://dev.to/martin_betz/premium-laravel-courses-and-books-5b1h</guid>
      <description>&lt;p&gt;There are many premium paid video courses (📺) and books (📘) for Laravel.&lt;br&gt;&lt;br&gt;
I also list content that is not released yet (🚧).&lt;br&gt;&lt;br&gt;
The list is sorted alphabetically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📺 &lt;a href="https://course.buildachatbot.io/"&gt;Build A Chatbot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘 &lt;a href="https://buildanapi.com/"&gt;Build an API with Laravel&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;📺 &lt;a href="https://confidentlaravel.com/"&gt;Confident Laravel&lt;/a&gt; (📺)&lt;/li&gt;
&lt;li&gt;📺, 🚧 &lt;a href="https://eloquent-course.reinink.ca/"&gt;Eloquent Performance Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📺, 🚧 &lt;a href="https://indepthlaravel.com/"&gt;In Depth Laravel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📺 &lt;a href="https://laravelcoreadventures.com/"&gt;Laravel Core Adventures&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘, 🚧 &lt;a href="https://laravelsecrets.com/"&gt;Laravel Secrets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘 &lt;a href="https://laravelupandrunning.com/"&gt;Laravel Up &amp;amp; Running&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📺, 🚧 &lt;a href="https://multitenancy.dev/"&gt;Multi Tenancy with Laravel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📺 &lt;a href="https://laraveldaily.teachable.com/"&gt;Online Courses by Laravel Daily&lt;/a&gt; 📺&lt;/li&gt;
&lt;li&gt;📺 &lt;a href="https://phppackagedevelopment.com/"&gt;PHP Package Development&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘 &lt;a href="https://adamwathan.me/refactoring-to-collections/"&gt;Refactoring to Collections&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📺 &lt;a href="https://serverlesslaravelcourse.com/"&gt;Serverless Laravel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📺 &lt;a href="https://course.testdrivenlaravel.com/"&gt;Test Driven Laravel&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know more resources, please email me 👇.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Only allow owners to update their user profile in Laravel with a policy</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Fri, 10 Apr 2020 11:33:43 +0000</pubDate>
      <link>https://dev.to/martin_betz/only-allow-owners-to-update-their-user-profile-in-laravel-with-a-policy-2el1</link>
      <guid>https://dev.to/martin_betz/only-allow-owners-to-update-their-user-profile-in-laravel-with-a-policy-2el1</guid>
      <description>&lt;h2&gt;
  
  
  The problem: Only owners should be allowed to edit their profiles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You have a website that lists the profile of Laravel developers&lt;/li&gt;
&lt;li&gt;The profile is just an extension of the &lt;code&gt;User&lt;/code&gt; model, so you have extra fields&lt;/li&gt;
&lt;li&gt;For sake of simplicity, you have only one field in your profile that is the numbers of years you've been coding with Laravel&lt;/li&gt;
&lt;li&gt;Developers listed should only be able to edit their own profile and not foreign profiles&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The solution: Use a policy for the User model
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We will write a &lt;a href="https://laravel.com/docs/7.x/authorization#creating-policies"&gt;policy&lt;/a&gt; that will be triggered when a user updates a profile&lt;/li&gt;
&lt;li&gt;The policy checks whether you are the owner of the user profile&lt;/li&gt;
&lt;li&gt;If you are, you can update the profile&lt;/li&gt;
&lt;li&gt;If you are not the owner, your request will be denied&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The step by step explanation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I will show you how to add this policy test-driven&lt;/li&gt;
&lt;li&gt;I assume that you already created a fresh Laravel app and set up your database&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Write a failing test &lt;code&gt;user_can_update_own_profile&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a test for the User model: &lt;code&gt;php artisan make:test Http/Controllers/UserControllerTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We will write a test with how we wish our app should work if we are the owner of a profile&lt;/li&gt;
&lt;li&gt;This is called the &lt;em&gt;Happy Path&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;// tests/Feature/Http/Controllers/UserControllerTest.php

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;App\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Foundation\Testing\RefreshDatabase&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;UserControllerTest&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;RefreshDatabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/** @test */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;user_can_update_own_profile&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="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&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="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;actingAs&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="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user.profile.update'&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="s1"&gt;'experience_years'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertSuccessful&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="na"&gt;refresh&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="na"&gt;assertEquals&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="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;experience_years&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;ul&gt;
&lt;li&gt;This test will fail for many reasons

&lt;ul&gt;
&lt;li&gt;We do not have a route named &lt;code&gt;user.profile.update&lt;/code&gt; that we can send a &lt;code&gt;POST&lt;/code&gt; request to&lt;/li&gt;
&lt;li&gt;We do not have a &lt;code&gt;experience_years&lt;/code&gt; property on the &lt;code&gt;User&lt;/code&gt; model&lt;/li&gt;
&lt;li&gt;We do not have a User controller that actually updates the model&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;In a normal test-driven process, I would solve this error by error&lt;/li&gt;
&lt;li&gt;As this tutorial is about policies, I will just solve all problems at once to get to the policy part&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Fix the test to assert that you can update your own profile
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The solution: Update your migration, &lt;code&gt;User&lt;/code&gt; model, &lt;code&gt;web.php&lt;/code&gt; routes file and create a &lt;code&gt;UserController&lt;/code&gt; with an &lt;code&gt;update&lt;/code&gt; method that updates with everything passed with a request&lt;/li&gt;
&lt;li&gt;I marked all new files with a &lt;code&gt;// ADD:&lt;/code&gt; comment&lt;/li&gt;
&lt;li&gt;I deleted all comments and unneccessary lines
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;// Migration: database/migrations/2014_10_12_000000_create_users_table.php
// Your date in the filename should differ

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Database\Migrations\Migration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Database\Schema\Blueprint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Support\Facades\Schema&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;CreateUsersTable&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Migration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;create&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="nx"&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="na"&gt;id&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="na"&gt;string&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;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;string&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;unique&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="na"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'experience_years'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ADD: nullable integer&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="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email_verified_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="na"&gt;nullable&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="na"&gt;string&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="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;rememberToken&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="na"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;dropIfExists&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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





&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;// User Model: app/User.php

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Contracts\Auth\MustVerifyEmail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Foundation\Auth\User&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Authenticatable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Notifications\Notifiable&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;User&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Authenticatable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Notifiable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'experience_years'&lt;/span&gt; &lt;span class="c1"&gt;// ADD: 'experience_years'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$hidden&lt;/span&gt; &lt;span class="o"&gt;=&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="s1"&gt;'remember_token'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$casts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'email_verified_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'datetime'&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;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;// Routes: routes/web.php

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Support\Facades\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/{user}/profile/update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'UserController@update'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user.profile.update'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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





&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;// Controller: app/Http/Controllers/UserController.php

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;App\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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="nx"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="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="na"&gt;update&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="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can now run the tests with &lt;code&gt;php artisan test&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You should see two passing example tests and a passing test: &lt;code&gt;✓ user can update own profile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Let's try to update someone else's years of experience:&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Try to update someone else's profile – and fail
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/** @test */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;user_cannot_update_foreign_profile&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="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&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="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$foreign_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&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="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'experience_years'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;actingAs&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="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user.profile.update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$foreign_user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'experience_years'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertForbidden&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$foreign_user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;refresh&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="na"&gt;assertEquals&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="nv"&gt;$foreign_user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;experience_years&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;ul&gt;
&lt;li&gt;This test will fail &lt;code&gt;Asserting that 5 is 2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;This means: Yes, we can change someone else's profile&lt;/li&gt;
&lt;li&gt;Not good!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Add a policy to disallow changing someone else's profile
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Solution: Add a policy to stopp this&lt;/li&gt;
&lt;li&gt;Create the policy: &lt;code&gt;php artisan make:policy UserPolicy&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;// Policy: app/Policies/UserPolicy.php

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;App\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Auth\Access\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Auth\Access\HandlesAuthorization&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;UserPolicy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;HandlesAuthorization&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="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user_model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$user_model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;deny&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;ul&gt;
&lt;li&gt;Policies always have the current user passed via &lt;code&gt;User $user&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The second argument is the model that we want to protect&lt;/li&gt;
&lt;li&gt;Because we want to protect the user model, we need to pass it twice with differing names&lt;/li&gt;
&lt;li&gt;Interpretation of the command: If the ID of the currently logged in user is the same as the id of the user model that is being tried to update, allow the update. If not, reject the update&lt;/li&gt;
&lt;li&gt;Because we named the policy like the model, Laravel automatically finds it&lt;/li&gt;
&lt;li&gt;We only need to apply the policy on the route
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;// Routes with policy: routes/web.php

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Support\Facades\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/{user}/profile/update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'UserController@update'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user.profile.update'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'can:update,user'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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



&lt;p&gt;The &lt;code&gt;-&amp;gt;middleware('can:update,user)&lt;/code&gt; means: Authorize the &lt;code&gt;update()&lt;/code&gt; action and pass the &lt;code&gt;user&lt;/code&gt; URL parameter to the policy (that's our &lt;code&gt;$user_model&lt;/code&gt; in the policy).&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo and extension
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you have problems following the code, check out the repo on &lt;a href="https://github.com/minthemiddle/200410-listing"&gt;Github&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you want to extend this functionality, try to add an exception for admins: They should be able to change every profile&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>policy</category>
      <category>authorization</category>
    </item>
    <item>
      <title>Only allow owner to update their user profile in Laravel with a policy</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Fri, 10 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/martin_betz/only-allow-owner-to-update-their-user-profile-in-laravel-with-a-policy-a89</link>
      <guid>https://dev.to/martin_betz/only-allow-owner-to-update-their-user-profile-in-laravel-with-a-policy-a89</guid>
      <description>&lt;h2&gt;
  
  
  The problem: Only owners should be allowed to edit their profiles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You have a website that lists the profile of Laravel developers&lt;/li&gt;
&lt;li&gt;The profile is just an extension of the &lt;code&gt;User&lt;/code&gt; model, so you have extra fields&lt;/li&gt;
&lt;li&gt;For sake of simplicity, you have only one field in your profile that is the numbers of years you've been coding with Laravel&lt;/li&gt;
&lt;li&gt;Developers listed should only be able to edit their own profile and not foreign profiles&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The solution: Use a policy for the User model
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We will write a &lt;a href="https://laravel.com/docs/7.x/authorization#creating-policies"&gt;policy&lt;/a&gt; that will be triggered when a user updates a profile&lt;/li&gt;
&lt;li&gt;The policy checks whether you are the owner of the user profile&lt;/li&gt;
&lt;li&gt;If you are, you can update the profile&lt;/li&gt;
&lt;li&gt;If you are not the owner, your request will be denied&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The step by step explanation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I will show you how to add this policy test-driven&lt;/li&gt;
&lt;li&gt;I assume that you already created a fresh Laravel app and set up your database&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Write a failing test &lt;code&gt;user_can_update_own_profile&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a test for the User model: &lt;code&gt;php artisan make:test Http/Controllers/UserControllerTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We will write a test with how we wish our app should work if we are the owner of a profile&lt;/li&gt;
&lt;li&gt;This is called the &lt;em&gt;Happy Path&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tests/Feature/Http/Controllers/UserControllerTest.php

&amp;lt;?php

namespace Tests\Feature\Http\Controllers;

use App\User;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserControllerTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function user_can_update_own_profile()
    {
        $user = factory(User::class)-&amp;gt;create();
        $response = $this-&amp;gt;actingAs($user)-&amp;gt;post(route('user.profile.update', $user), [
            'experience_years' =&amp;gt; 5,
        ]);

        $response-&amp;gt;assertSuccessful();
        $user-&amp;gt;refresh();
        $this-&amp;gt;assertEquals(5, $user-&amp;gt;experience_years);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This test will fail for many reasons

&lt;ul&gt;
&lt;li&gt;We do not have a route named &lt;code&gt;user.profile.update&lt;/code&gt; that we can send a &lt;code&gt;POST&lt;/code&gt; request to&lt;/li&gt;
&lt;li&gt;We do not have a &lt;code&gt;experience_years&lt;/code&gt; property on the &lt;code&gt;User&lt;/code&gt; model&lt;/li&gt;
&lt;li&gt;We do not have a User controller that actually updates the model&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;In a normal test-driven process, I would solve this error by error&lt;/li&gt;
&lt;li&gt;As this tutorial is about policies, I will just solve all problems at once to get to the policy part&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Fix the test to assert that you can update your own profile
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The solution: Update your migration, &lt;code&gt;User&lt;/code&gt; model, &lt;code&gt;web.php&lt;/code&gt; routes file and create a &lt;code&gt;UserController&lt;/code&gt; with an &lt;code&gt;update&lt;/code&gt; method that updates with everything passed with a request&lt;/li&gt;
&lt;li&gt;I marked all new files with a &lt;code&gt;// ADD:&lt;/code&gt; comment&lt;/li&gt;
&lt;li&gt;I deleted all comments and unneccessary lines
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Migration: database/migrations/2014_10_12_000000_create_users_table.php
// Your date in the filename should differ

&amp;lt;?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table-&amp;gt;id();
            $table-&amp;gt;string('name');
            $table-&amp;gt;string('email')-&amp;gt;unique();
            $table-&amp;gt;integer('experience_years')-&amp;gt;nullable(); // ADD: nullable integer
            $table-&amp;gt;timestamp('email_verified_at')-&amp;gt;nullable();
            $table-&amp;gt;string('password');
            $table-&amp;gt;rememberToken();
            $table-&amp;gt;timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('users');
    }
}


// User Model: app/User.php

&amp;lt;?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;

    protected $fillable = [
        'name', 'email', 'password', 'experience_years' // ADD: 'experience_years'
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    protected $casts = [
        'email_verified_at' =&amp;gt; 'datetime',
    ];
}


// Routes: routes/web.php

&amp;lt;?php

use Illuminate\Support\Facades\Route;

Route::post('/{user}/profile/update', 'UserController@update')-&amp;gt;name('user.profile.update');


// Controller: app/Http/Controllers/UserController.php

&amp;lt;?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function update(Request $request, User $user)
    {
        $user-&amp;gt;update($request-&amp;gt;all());
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can now run the tests with &lt;code&gt;php artisan test&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You should see two passing example tests and a passing test: &lt;code&gt;✓ user can update own profile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Let's try to update someone else's years of experience:&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Try to update someone else's profile – and fail
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/** @test */
    public function user_cannot_update_foreign_profile()
    {
        $user = factory(User::class)-&amp;gt;create();
        $foreign_user = factory(User::class)-&amp;gt;create([
            'experience_years' =&amp;gt; 2,
        ]);
        $response = $this-&amp;gt;actingAs($user)-&amp;gt;post(route('user.profile.update', $foreign_user), [
            'experience_years' =&amp;gt; 5,
        ]);

        $response-&amp;gt;assertForbidden();
        $foreign_user-&amp;gt;refresh();
        $this-&amp;gt;assertEquals(2, $foreign_user-&amp;gt;experience_years);
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This test will fail &lt;code&gt;Asserting that 5 is 2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;This means: Yes, we can change someone else's profile&lt;/li&gt;
&lt;li&gt;Not good!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Add a policy to disallow changing someone else's profile
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Solution: Add a policy to stopp this&lt;/li&gt;
&lt;li&gt;Create the policy: &lt;code&gt;php artisan make:policy UserPolicy&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Policy: app/Policies/UserPolicy.php

&amp;lt;?php

namespace App\Policies;

use App\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Auth\Access\HandlesAuthorization;

class UserPolicy
{
    use HandlesAuthorization;

    public function update(User $user, User $user_model)
    {
        return $user-&amp;gt;id === $user_model-&amp;gt;id ? Response::allow() : Response::deny();
    }
}

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



&lt;ul&gt;
&lt;li&gt;Policies always have the current user passed via &lt;code&gt;User $user&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The second argument is the model that we want to protect&lt;/li&gt;
&lt;li&gt;Because we want to protect the user model, we need to pass it twice with differing names&lt;/li&gt;
&lt;li&gt;Interpretation of the command: If the ID of the currently logged in user is the same as the id of the user model that is being tried to update, allow the update. If not, reject the update&lt;/li&gt;
&lt;li&gt;Because we named the policy like the model, Laravel automatically finds it&lt;/li&gt;
&lt;li&gt;We only need to apply the policy on the route
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Routes with policy: routes/web.php

&amp;lt;?php

use Illuminate\Support\Facades\Route;

Route::post('/{user}/profile/update', 'UserController@update')-&amp;gt;name('user.profile.update')-&amp;gt;middleware('can:update,user');

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



&lt;p&gt;The &lt;code&gt;-&amp;gt;middleware('can:update,user)&lt;/code&gt; means: Authorize the &lt;code&gt;update()&lt;/code&gt; action and pass the &lt;code&gt;user&lt;/code&gt; URL parameter to the policy (that's our &lt;code&gt;$user_model&lt;/code&gt; in the policy).&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo and extension
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you have problems following the code, check out the repo on &lt;a href="https://github.com/minthemiddle/200410-listing"&gt;Github&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you want to extend this functionality, try to add an exception for admins: They should be able to change every profile&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Laravel blogs to follow via RSS</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Mon, 06 Jan 2020 13:15:04 +0000</pubDate>
      <link>https://dev.to/martin_betz/laravel-blogs-to-follow-via-rss-1hm0</link>
      <guid>https://dev.to/martin_betz/laravel-blogs-to-follow-via-rss-1hm0</guid>
      <description>&lt;p&gt;There are many high quality blogs on Laravel and related topics, such as Tailwind, Livewire, AlpineJS and VueJS. There are some well-known bloggers, such as Freek and Matt Stauffer, but also some lesser-known yet excellent ones.&lt;/p&gt;

&lt;p&gt;Here are the direct links to the RSS feeds, the list is sorted alphabetically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amitmerchant.com/feed"&gt;Amit Merchant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benfurfie.co.uk/feed"&gt;Ben Furfie's Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://calebporzio.com/feed/"&gt;Caleb Porzio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://christoph-rumpel.com/feed.xml"&gt;Christoph Rumpel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/feeds/videos.xml?channel_id=UCQI-Ym2rLZx52vEoqlPQMdg"&gt;Coder's Tape&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://daylerees.com/feed/"&gt;Dayle Rees&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://divinglaravel.com/feed"&gt;Diving Laravel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://driesvints.com/blog/feed.atom"&gt;Dries Vints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dyrynda.com.au/blog/feed"&gt;Dyrynda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://murze.be/feed/"&gt;freek.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jasonmccreary.me/feed.atom"&gt;Jason McCreary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reinink.ca/rss"&gt;Jonathan Reinink&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://laraveldaily.com/feed/"&gt;Laravel Daily&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://feedpress.me/laravel-links"&gt;Laravel News Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://feed.laravel-news.com/"&gt;Laravel News&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.larashout.com/feed"&gt;LaraShout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.laravel-tricks.com/feed"&gt;Laravel-Tricks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://martinbetz.eu/blog/feed.atom"&gt;Martin Betz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://matthewdaly.co.uk/rss.xml"&gt;Matthew Daly's Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ma.ttias.be/blog/index.xml"&gt;Matthias Geniar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mattstauffer.co/blog/feed.atom"&gt;MattStauffer.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mauricius.dev/index.xml"&gt;Maurizio Bonani&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://themsaid.com/feed"&gt;Mohamed Said&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ohseemedia.com/feed"&gt;Oh See Media&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://feeds2.feedburner.com/Paulundcouk"&gt;Paulund&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pociot.dev/feed"&gt;pociot.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sebastiandedeyne.com/index.xml"&gt;Sebastian De Deyne&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://shawnmc.cool/feed"&gt;Shawn McCool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.stitcher.io/https://www.stitcher.io/rss"&gt;stitcher.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tighten.co/blog/feed.atom"&gt;Tighten Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://timacdonald.me/feed.xml"&gt;Tim MacDonald&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know more Laravel blogs to follow, just write a comment and I'll add them.&lt;/p&gt;

&lt;p&gt;Updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;20-01-13: Fixed Jonathan Reinink, added Matthias Geniar and LaraShout&lt;/li&gt;
&lt;li&gt;20-01-08: Fixed link for Caleb Porzio&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>rss</category>
      <category>follower</category>
      <category>blog</category>
    </item>
    <item>
      <title>Simple user roles in Laravel</title>
      <dc:creator>Martin Betz</dc:creator>
      <pubDate>Fri, 27 Dec 2019 15:23:28 +0000</pubDate>
      <link>https://dev.to/martin_betz/simple-user-roles-in-laravel-4bpa</link>
      <guid>https://dev.to/martin_betz/simple-user-roles-in-laravel-4bpa</guid>
      <description>&lt;p&gt;If you do only have roles for your users – such as admin, contributor and user – and you want to restrict access to routes only, advanced (and excellent) packages may be too heavy for you.&lt;br&gt;
Let me show you how to solve this authorization problem very easily.&lt;/p&gt;

&lt;p&gt;Your user model needs an extra field to store the role of every user. Let's add a string field which will hold values such as &lt;code&gt;user&lt;/code&gt;, &lt;code&gt;manager&lt;/code&gt; or &lt;code&gt;admin&lt;/code&gt;. Every user needs a role, so this field is not nullable and has a default of &lt;code&gt;user&lt;/code&gt;. Of course you have more fields in your user model, I'll add an email field to the user for demonstration purposes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create migration&lt;/span&gt;
&lt;span class="c1"&gt;// create_users_table.php&lt;/span&gt;

&lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;create&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="nx"&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="o"&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="na"&gt;string&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;unique&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="na"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's create a test user, using Laravel's tinker app, test it's default role and upgrade it to &lt;code&gt;admin&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;php artisan tinker&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create test user&lt;/span&gt;
&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;App\User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test01@test.test'&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'user'&lt;/span&gt;

&lt;span class="c1"&gt;// Upgrade user to admin&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="na"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'admin'&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="na"&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;Until now, the user role is just a string and does not do anything. Let's change this by generating a custom middleware. Middlewares can be attached to routes and control who has access to those routes.&lt;/p&gt;

&lt;p&gt;For example, to restrict the access to &lt;code&gt;/logged-in-users-only&lt;/code&gt; to logged in users, you would create the following function in your routes file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// routes/web.php&lt;/span&gt;
&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'logged-in-users-only'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'Only logged in users can see this'&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="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'auth'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can restrict routes to user roles with a custom middleware:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:middleware UserRoles&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create a middleware file that we can customize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Http/Middleware/UserRoles&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&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="nx"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$roles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$roles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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="na"&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&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;This &lt;code&gt;handle()&lt;/code&gt; method will only allow people access the route if their role is in the list of allowed roles in the protected route.&lt;/p&gt;

&lt;p&gt;Here is the whole &lt;code&gt;return&lt;/code&gt; one-liner in natural language:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the collection of rules contains the logged in user's role, then allow and process the request, otherwise redirect the user back.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;...$roles&lt;/code&gt; allows to pass multiple roles at once, the resulting &lt;code&gt;$roles&lt;/code&gt; is an array with all parameters&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;collect()&lt;/code&gt; I create a collection out of the array, so I can use collection methods and chain them, such as &lt;code&gt;contains()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contains()&lt;/code&gt; will check whether the role is in the collection&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return CONDITION ? THEN : ELSE&lt;/code&gt; is called a ternary operator and a shorter version of &lt;code&gt;if (CONDITION) { then } else { }&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make use of this middleware, we need to register it in the kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Http/Kernel.php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Middleware\UserRoles&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$routeMiddleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="s1"&gt;'roles'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;UserRoles&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To only allow users with role &lt;code&gt;admin&lt;/code&gt; to a route, you create it like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// routes/web.php&lt;/span&gt;
&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'types'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'Access granted'&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test.roles'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'roles:admin'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And because we allow to pass more than one role (remember the &lt;code&gt;...$roles&lt;/code&gt;) to the middleware, we can allow several roles to access the same route. Let's also give the &lt;code&gt;manager&lt;/code&gt; access to this route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// routes/web.php&lt;/span&gt;
&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'types'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'Access granted'&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test.roles'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'roles:admin,manager'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// no space after comma!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One risk with this approach is that you pass roles around as strings. You always need to remember which roles you have and how you named them. A small typo such as &lt;code&gt;adnin&lt;/code&gt; instead of &lt;code&gt;admin&lt;/code&gt; will be hard to spot and renaming a role (e.g. &lt;code&gt;manager&lt;/code&gt; to become &lt;code&gt;editor&lt;/code&gt;) can easily break your system.&lt;/p&gt;

&lt;p&gt;In the next iteration of this article, I will introduce &lt;code&gt;Enums&lt;/code&gt; to help reducing this risk, but for now this solution is lean and will solve your basic needs.&lt;/p&gt;

&lt;p&gt;P.S. If you have suggestions on refactoring or improving, please leave a comment&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>authorization</category>
      <category>roles</category>
    </item>
  </channel>
</rss>
