<?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: Muhammad Hassan</title>
    <description>The latest articles on DEV Community by Muhammad Hassan (@muhamadhhassan).</description>
    <link>https://dev.to/muhamadhhassan</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%2F72061%2Fa85648c1-973c-4b2a-ae28-35f5ccb961f2.jpg</url>
      <title>DEV Community: Muhammad Hassan</title>
      <link>https://dev.to/muhamadhhassan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muhamadhhassan"/>
    <language>en</language>
    <item>
      <title>PHP Attributes and Metaprogramming</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Tue, 20 May 2025 21:05:18 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/php-attributes-and-metaprogramming-f5g</link>
      <guid>https://dev.to/muhamadhhassan/php-attributes-and-metaprogramming-f5g</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Attributes were introduced in PHP 8 around four years ago. As outlined in the &lt;a href="https://wiki.php.net/rfc/attributes_v2" rel="noopener noreferrer"&gt;&lt;strong&gt;RFC&lt;/strong&gt;&lt;/a&gt;, attributes provide a structured and syntactic way to add metadata to declarations such as classes, properties, functions, methods, parameters, and constants. Previously, developers relied on &lt;strong&gt;DocBlocks'&lt;/strong&gt; annotations for &lt;a href="https://www.doctrine-project.org/projects/doctrine-annotations/en/stable/index.html" rel="noopener noreferrer"&gt;this purpose&lt;/a&gt;. The syntax of Attributes is as follows:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;#[Attribute]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleAttribute&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="na"&gt;#[ExampleAttribute('This is a custom attribute for a class')]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;#[ExampleAttribute('This is a custom attribute for a method')]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;myMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello from myMethod!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But first, how are PHP attributes different from decorators in Python? Or, Java’s Aspect-oriented Programming (AOP) annotations?&lt;/p&gt;

&lt;h1&gt;
  
  
  Metaprogramming
&lt;/h1&gt;

&lt;p&gt;The concept that is fundamentally common across Aspect-Oriented Programming (AOP), attributes, and decorators is metaprogramming. Metaprogramming is the practice of writing code that generates, manipulates, or modifies other code. Essentially, it's code that writes code. This can be done at compile-time or runtime, depending on the language and use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decorator
&lt;/h2&gt;

&lt;p&gt;Decorator is a behavioral design pattern where a function or class is wrapped with additional behavior without modifying its structure. Achieved using higher-order functions (in Python, JavaScript) or annotations (in TypeScript).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 This is different from the &lt;a href="https://refactoring.guru/design-patterns/decorator" rel="noopener noreferrer"&gt;stackable decorator classes&lt;/a&gt; implementation of the decorator pattern.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following is a simple example of a logging decorator in Python.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_function_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Calling function: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; returned &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@log_function_call&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="c1"&gt;# Usage
&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;log_function_call&lt;/code&gt; is a &lt;strong&gt;decorator function&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@log_function_call&lt;/code&gt; applies that decorator to the &lt;code&gt;add&lt;/code&gt; function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;wrapper&lt;/code&gt; is a nested function that wraps the original function, adding extra behavior before and after it runs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output of this code will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Calling &lt;span class="k"&gt;function&lt;/span&gt;: add
Function add returned 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Aspect-Oriented Programming
&lt;/h2&gt;

&lt;p&gt;Aspect-Oriented Programming (AOP) is a paradigm that allows you to modularize concerns (like logging, security, or transaction management) that cut across the typical divisions of responsibility (such as methods or classes) by encapsulating them into reusable modules called aspects, improving separation of concerns and making the codebase easier to maintain and extend.&lt;/p&gt;

&lt;p&gt;Let’s take another logging example but this time implemented in AOP to explain its core concept:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.demo.aspect&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.aspectj.lang.JoinPoint&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.aspectj.lang.annotation.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Component&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Aspect&lt;/span&gt;
&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoggingAspect&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"execution(* com.example.demo.service.*.*(..))"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;logBefore&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JoinPoint&lt;/span&gt; &lt;span class="n"&gt;joinPoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Method called: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;joinPoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSignature&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toShortString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code defines a &lt;strong&gt;cross-cutting concern&lt;/strong&gt; — specifically, &lt;strong&gt;logging&lt;/strong&gt; — and &lt;strong&gt;separates&lt;/strong&gt; it from the main business logic of the application (like the &lt;code&gt;service&lt;/code&gt; classes).&lt;br&gt;&lt;br&gt;
Instead of adding &lt;code&gt;System.out.println&lt;/code&gt; statements inside every service method, &lt;strong&gt;you modularized&lt;/strong&gt; this behavior into a &lt;strong&gt;separate aspect&lt;/strong&gt;: &lt;code&gt;LoggingAspect&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Aspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Declares this class as an &lt;strong&gt;aspect&lt;/strong&gt; (a modular unit of a cross-cutting concern).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Component&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tells Spring to manage this class as a &lt;strong&gt;bean&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Before(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A &lt;strong&gt;pointcut&lt;/strong&gt; and &lt;strong&gt;advice&lt;/strong&gt;: it says "Before any method in &lt;code&gt;com.example.demo.service.*&lt;/code&gt; package is called, run &lt;code&gt;logBefore()&lt;/code&gt;."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;JoinPoint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gives details about the method being intercepted (like its name).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;logBefore()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is the &lt;strong&gt;advice method&lt;/strong&gt; where the logging action happens.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In essence, metaprogramming is the conceptual thread that ties AOP, attributes, and decorators together—they’re all ways to step outside the normal flow of code execution and define how code should behave beyond its immediate implementation.&lt;/p&gt;
&lt;h1&gt;
  
  
  Reflection API
&lt;/h1&gt;

&lt;p&gt;Both the new first-class citizen attributes and the dockblocks implementation depend on the reflection API for inspecting the attributes at runtime. &lt;a href="https://www.php.net/manual/en/intro.reflection.php" rel="noopener noreferrer"&gt;Reflection AP&lt;/a&gt; is another, much older, example of metaprogramming in PHP. It introduced the ability to introspect classes, interfaces, functions, methods and extensions. It can also retrieve the doc comments for functions, classes and methods.&lt;/p&gt;

&lt;p&gt;If you are not familiar with it, here is a simple example where the properties of the &lt;code&gt;User&lt;/code&gt; class can be accessed programmatically regardless of their access modifier:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Use ReflectionClass to inspect the User class&lt;/span&gt;
&lt;span class="nv"&gt;$reflection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'User'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get the public, protected, and private properties &lt;/span&gt;
&lt;span class="nv"&gt;$properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflection&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Attributes
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Syntax
&lt;/h2&gt;

&lt;p&gt;Attributes are classes annotated with the base &lt;code&gt;#[Attribute]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Attribute(Attribute::TARGET_METHOD)]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Log&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Method called'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attributes are configured by passing a &lt;a href="https://en.wikipedia.org/wiki/Mask_(computing)#:~:text=In%20computer%20science%2C%20a%20mask,in%20a%20single%20bitwise%20operation." rel="noopener noreferrer"&gt;bitmask&lt;/a&gt; as its first argument, It can be used to restrict the types that an attribute can be applied to. In the above example, the &lt;code&gt;Log&lt;/code&gt; attribute can only be applied to methods. The available types are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TARGET_CLASS&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TARGET_FUNCTION&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TARGET_METHOD&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TARGET_PROPERTY&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TARGET_CLASS_CONSTANT&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TARGET_PARAMETER&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TARGET_ALL&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, an attribute can be used once per declaration. to change this behavior, specify it in the bitmask of the &lt;code&gt;#[Attribute]&lt;/code&gt; declaration using the &lt;code&gt;Attribute::IS_REPEATABLE&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Log&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Method called'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a class that uses the &lt;code&gt;Log&lt;/code&gt; attribute:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;#[Log("Creating a new account")]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Account created for &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Log("Deleting an account")]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;deleteAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Account deleted for &lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;helperFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This won't be logged."&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&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;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a logger proxy function to call the methods with logging:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;callWithLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$refMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReflectionMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$refMethod&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cd"&gt;/** @var Log $log */&lt;/span&gt;
        &lt;span class="nv"&gt;$log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;newInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[LOG] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$log&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&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;$refMethod&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;invokeArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&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;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Client Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AccountService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;callWithLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'createAccount'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'alice'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nf"&gt;callWithLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'deleteAccount'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'bob'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nf"&gt;callWithLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'helperFunction'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// No log, no attribute&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of this code will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;LOG] Creating a new account
Account created &lt;span class="k"&gt;for &lt;/span&gt;alice
&lt;span class="o"&gt;[&lt;/span&gt;LOG] Deleting an account
Account deleted &lt;span class="k"&gt;for &lt;/span&gt;bob
This won&lt;span class="s1"&gt;'t be logged.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Real-Life Example
&lt;/h1&gt;

&lt;p&gt;Let’s take a real-life example of attributes. &lt;strong&gt;Laravel 11&lt;/strong&gt; introduced &lt;a href="https://laravel.com/docs/12.x/container#contextual-attributes" rel="noopener noreferrer"&gt;contextual attributes&lt;/a&gt; and for our example we will be using the &lt;a href="https://github.com/laravel/framework/blob/12.x/src/Illuminate/Container/Attributes/Config.php" rel="noopener noreferrer"&gt;&lt;code&gt;Config&lt;/code&gt;&lt;/a&gt; attribute. The &lt;code&gt;#[Config(...)]&lt;/code&gt; attribute allows you to annotate a constructor or method parameter, so that &lt;strong&gt;Laravel’s&lt;/strong&gt; service container can &lt;strong&gt;resolve and inject&lt;/strong&gt; the corresponding config value at runtime:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Container\Attributes\Config&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;PhotoController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app.timezone'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$timezone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Config Attribute Definition
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Config&lt;/code&gt; attribute definition goes as follows:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Container\Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Attribute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Container\Container&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Container\ContextualAttribute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="na"&gt;#[Attribute(Attribute::TARGET_PARAMETER)]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ContextualAttribute&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Create a new class instance.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Resolve the configuration value.
     *
     * @param  self  $attribute
     * @param  \Illuminate\Contracts\Container\Container  $container
     * @return mixed
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;self&lt;/span&gt; &lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Container&lt;/span&gt; &lt;span class="nv"&gt;$container&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;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'config'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ The &lt;code&gt;ContextualAttribute&lt;/code&gt; is an empty interface in Laravel 12.x.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Resolving &lt;code&gt;Config&lt;/code&gt; Attribute
&lt;/h2&gt;

&lt;p&gt;Contextual attributes resolving start in &lt;code&gt;Illuminate\Container\Container::build($concrete)&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠ Some of the code in &lt;code&gt;Illuminate\Container\Container&lt;/code&gt; will be omitted if it’s not related to the flow of binding a constructor’s config parameter. The full class can be found &lt;a href="https://github.com/laravel/framework/blob/12.x/src/Illuminate/Container/Container.php" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, we create a &lt;code&gt;ReflectionClass&lt;/code&gt; to inspect the &lt;code&gt;$concrete&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$reflector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$concrete&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReflectionException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BindingResolutionException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Target class [&lt;/span&gt;&lt;span class="nv"&gt;$concrete&lt;/span&gt;&lt;span class="s2"&gt;] does not exist."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to get the &lt;code&gt;$concrete&lt;/code&gt; constructor method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// returns a ReflectionMethod instance&lt;/span&gt;
&lt;span class="nv"&gt;$constructor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflector&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getConstructor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, if the class does not have a constructor, the service container returns a new instance of &lt;code&gt;$concrete&lt;/code&gt;. But, that is not the case in our &lt;code&gt;PhotoController&lt;/code&gt;, so that, it gets a list of the &lt;code&gt;$constructor&lt;/code&gt; method parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// returns an array of ReflectionParameter[]&lt;/span&gt;
&lt;span class="nv"&gt;$dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$constructor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getParameters&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;resolveDependencies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dependencies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BindingResolutionException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;array_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buildStack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method &lt;code&gt;Container::resolveDependencies($dependencies)&lt;/code&gt; loops over the &lt;code&gt;$dependencies&lt;/code&gt; array, and returns an array of the constructor parameters. One execution flow is when the &lt;code&gt;$dependency&lt;/code&gt; has a contextual parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dependencies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$dependency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Util&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getContextualAttributeFromDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dependency&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;resolveFromAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in &lt;code&gt;Container::resolveFromAttribute(ReflectionAttribute $attribute)&lt;/code&gt;, There are two scenarios for resolving the value of the attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;resolveFromAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ReflectionAttribute&lt;/span&gt; &lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;contextualAttributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;newInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;method_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'resolve'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BindingResolutionException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Contextual binding attribute [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$attribute&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] has no registered handler."&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;$handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If there is a custom handler function (or callable) for the &lt;code&gt;$attribute&lt;/code&gt; name defined in the &lt;code&gt;App\Providers\AppServiceProvider::boot()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Container\Attributes\Config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * Bootstrap any application services.
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;contextualAttributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Africa/Cairo'&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;p&gt;The callable &lt;code&gt;fn() =&amp;gt; 'Africa/Cairo'&lt;/code&gt; is invoked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the &lt;code&gt;$handler&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;, and the &lt;code&gt;Illuminate\Container\Attributes\Config::resolve()&lt;/code&gt; method exists in the attribute definition, it will be invoked.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Attributes Misuse
&lt;/h1&gt;

&lt;p&gt;Metaprogramming allows code to generate or modify other code dynamically, offering flexibility and reduced boilerplate, but it comes with significant downsides. It can reduce readability and maintainability, make debugging harder, and introduce performance overhead.&lt;/p&gt;

&lt;p&gt;To minimize the negative side effects of attributes, they should not be used beyond their described purpose as metadata providers. Misuse examples includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Embedding logic&lt;/strong&gt; or &lt;strong&gt;side effects&lt;/strong&gt; within attributes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For example, having an attribute that &lt;em&gt;modifies global state&lt;/em&gt; or &lt;em&gt;performs operations&lt;/em&gt; at runtime just by being present.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Replacing business logic&lt;/strong&gt; with attribute logic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E.g., putting application logic or decisions into attribute classes, rather than keeping that logic in controllers or services.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Overloading attribute meaning&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When attributes are overloaded with too many responsibilities or become a place to "hide" logic, it becomes harder to understand or maintain code.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Using attributes for code that should remain in configuration files&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E.g., trying to implement environment configuration through attributes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In conclusion, PHP attributes provide a powerful and expressive way to add metadata to your code, making it easier to build more declarative and maintainable applications. From &lt;a href="https://www.php.net/manual/en/reserved.attributes.php" rel="noopener noreferrer"&gt;core language features&lt;/a&gt; like &lt;code&gt;#[Deprecated]&lt;/code&gt;, &lt;code&gt;#[Override]&lt;/code&gt;, and &lt;code&gt;#[Attribute]&lt;/code&gt;, to &lt;a href="https://docs.phpunit.de/en/10.5/attributes.html" rel="noopener noreferrer"&gt;PHPUnit-specific&lt;/a&gt; attributes such as &lt;code&gt;#[Test]&lt;/code&gt;, &lt;code&gt;#[Before]&lt;/code&gt;, &lt;code&gt;#[After]&lt;/code&gt;, and &lt;code&gt;#[Depends]&lt;/code&gt;, attributes help streamline testing and application behavior without relying on verbose annotations or docblocks. As attributes continue to evolve in PHP, they open up cleaner integration points for frameworks and tooling. Whether you're writing application logic or unit tests, leveraging built-in and custom attributes can greatly improve the readability and structure of your codebase.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>PHP Generics in Laravel 11</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Tue, 22 Oct 2024 23:11:31 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/php-generics-in-laravel-11-3hng</link>
      <guid>https://dev.to/muhamadhhassan/php-generics-in-laravel-11-3hng</guid>
      <description>&lt;p&gt;If you are a web applications builder with Laravel and happens to use &lt;a href="https://muhamadhhassan.me/laravel-static-code-analysis-with-phpstan" rel="noopener noreferrer"&gt;PHPStan&lt;/a&gt; for static code analysis, you will start seeing new errors when you upgrade to &lt;strong&gt;Laravel&lt;/strong&gt; &lt;strong&gt;11.x&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a fresh Laravel install with &lt;strong&gt;PHPStan&lt;/strong&gt;, the first time running &lt;code&gt;./vendor/bin/phpstan&lt;/code&gt; the following error get thrown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-----------------------------------------------------------------------------------&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Line&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;app\Models\User.php&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="o"&gt;------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-----------------------------------------------------------------------------------&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kr"&gt;Class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Models&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;uses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;generic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;trait&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nc"&gt;Illuminate&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Eloquent&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Factories&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;HasFactory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;but&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;does&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;specify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;its&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nc"&gt;TFactory&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-----------------------------------------------------------------------------------&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what was changed? In Laravel 11, the &lt;code&gt;HasFactory&lt;/code&gt; trait now has a &lt;strong&gt;PHPDoc&lt;/strong&gt; with the &lt;code&gt;@template&lt;/code&gt; tag which is one of the reserved generics tags. As you may already have guessed, generics are being used in many parts of the framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */&lt;/span&gt;
&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;HasFactory&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mf"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although it is not recommended, this category of errors can be ignored by simply adding these lines of code to your &lt;code&gt;phpstan.neon&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ignoreErrors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt;
            &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;missingType.generics&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, generics are not that hard to understand so let’s get started!&lt;/p&gt;

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

&lt;p&gt;Generics in programming refer to a feature that allows you to write code that can work with multiple data types. Instead of writing separate code for each data type, you can write a single, generic piece of code that can operate on various types while maintaining type safety, unlike using general types like &lt;code&gt;mixed&lt;/code&gt; or &lt;code&gt;object&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Take the &lt;code&gt;Illuminate\Database\Concerns\BuildsQueries::first&lt;/code&gt; method from &lt;strong&gt;Laravel&lt;/strong&gt; 10, it can return an instance of &lt;code&gt;Model&lt;/code&gt;, a general &lt;code&gt;object&lt;/code&gt;, an instance of the class using it like &lt;code&gt;Illuminate\Database\Eloquent\Builder&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Execute the query and get the first result.
 *
 * @param  array|string  $columns
 * @return \Illuminate\Database\Eloquent\Model|object|static|null
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generics Syntax
&lt;/h2&gt;

&lt;p&gt;Generics are not supported in PHP as a &lt;a href="https://stitcher.io/blog/generics-in-php-3" rel="noopener noreferrer"&gt;first-class citizen&lt;/a&gt;, to have them we use the &lt;strong&gt;PHPDocs&lt;/strong&gt; tags &lt;code&gt;@template&lt;/code&gt;, &lt;code&gt;@template-covariant&lt;/code&gt;, &lt;code&gt;@template-contravariant&lt;/code&gt;, &lt;code&gt;@extends&lt;/code&gt;, &lt;code&gt;@implements&lt;/code&gt;, and &lt;code&gt;@use&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The rules of the generic types are defined using &lt;em&gt;type parameters.&lt;/em&gt; In &lt;strong&gt;PHPDocs&lt;/strong&gt; we annotate them with the &lt;code&gt;@template&lt;/code&gt; tag. The type parameter name can be anything, as long as you don’t use an existing class name. You can also limit which types can be used in place of the type parameter with an upper bound using the &lt;code&gt;of&lt;/code&gt; keyword. This is called &lt;em&gt;bounded type parameter.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Database\Eloquent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 *
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Builder&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;BuilderContract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Types of PHP Generics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Generic Function
&lt;/h3&gt;

&lt;p&gt;A generic function is exactly like a normal function, however, it has type parameters. This allows the generic method to be used in a more general way.&lt;/p&gt;

&lt;p&gt;Take the &lt;code&gt;Illuminate\Support\ValidatedInput::enum&lt;/code&gt; method as an example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It defines a type parameter &lt;code&gt;TEnum&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;$enumClass&lt;/code&gt; parameter is of the pseudo type &lt;code&gt;class-string&lt;/code&gt; and bounded to the same type parameter &lt;code&gt;TEnum&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The return type also can either be of &lt;code&gt;TEnum&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @template TEnum
 *
 * @param string $key
 * @param class-string&amp;lt;TEnum&amp;gt; $enumClass
 * @return TEnum|null
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$enumClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isNotFilled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nf"&gt;enum_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$enumClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;method_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$enumClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'tryFrom'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$enumClass&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;tryFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&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;If you then call &lt;code&gt;$request→validated()→enum(‘status‘, OrderStatus::class)&lt;/code&gt;, &lt;strong&gt;PHPStan&lt;/strong&gt; will know that you’re getting an &lt;code&gt;OrderStatus&lt;/code&gt; object or null!&lt;/p&gt;

&lt;h3&gt;
  
  
  Generic Class
&lt;/h3&gt;

&lt;p&gt;Generic classes allows for creating classes that can operate on any data type while ensuring type safety. They enable a class to be defined with a placeholder for a specific type, which can later be substituted when the class is instantiated.&lt;/p&gt;

&lt;p&gt;A good example from &lt;strong&gt;Laravel&lt;/strong&gt; source code would be the &lt;code&gt;Illuminate\Database\Eloquent\Builder&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Database\Eloquent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cd"&gt;/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Builder&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;BuilderContract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @param  array  $attributes
     * @return TModel
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;newModelInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A type parameter &lt;code&gt;TModel&lt;/code&gt; is defined and bounded to any sub-class of &lt;code&gt;Illuminate\Database\Eloquent\Model&lt;/code&gt;. The same type parameter is used as a return type of the method &lt;code&gt;make&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another example would be if we have an &lt;code&gt;Order&lt;/code&gt; model, which has a local scope to filter orders based on their status. The scope method should specify the &lt;code&gt;TModel&lt;/code&gt; type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @param  Builder&amp;lt;Order&amp;gt;  $query
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;scopeWithStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Builder&lt;/span&gt; &lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;OrderStatus&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&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;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;info&lt;/strong&gt;: All the &lt;strong&gt;Eloquent&lt;/strong&gt; relations classes in namespace &lt;code&gt;Illuminate\Database\Eloquent\Relations&lt;/code&gt; like &lt;code&gt;BelongsTo&lt;/code&gt; and &lt;code&gt;HasOne&lt;/code&gt; are now generic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Generic Interface
&lt;/h3&gt;

&lt;p&gt;Generic interfaces are not so different. The &lt;code&gt;Illuminate\Contracts\Support\Arrayable&lt;/code&gt; is an example of a generic interface&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @template TKey of array-key
 * @template TValue
 */&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Arrayable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Get the instance as an array.
     *
     * @return array&amp;lt;TKey, TValue&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interface defines two type parameters: &lt;code&gt;TKey&lt;/code&gt; of type &lt;code&gt;array-key&lt;/code&gt; (it can be &lt;code&gt;int&lt;/code&gt; or &lt;code&gt;string&lt;/code&gt;) and &lt;code&gt;TValue&lt;/code&gt;. Theses two parameters are used to define the return type of the &lt;code&gt;toArray&lt;/code&gt; function. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @implements Arrayable&amp;lt;int, string&amp;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="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Arrayable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * @return array&amp;lt;int, string&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user class implements the &lt;code&gt;Arrayable&lt;/code&gt; interface and specify the &lt;code&gt;Tkey&lt;/code&gt; type as an &lt;code&gt;int&lt;/code&gt; and the &lt;code&gt;TValue&lt;/code&gt; as a &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generic Trait
&lt;/h3&gt;

&lt;p&gt;We came across the &lt;code&gt;Illuminate\Database\Eloquent\Factories\HasFactory&lt;/code&gt; trait in the error at the beginning of this post. Let’s have a closer look:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Illuminate\Database\Eloquent\Factories&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */&lt;/span&gt;
&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;HasFactory&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Create a new factory instance for the model.
     *
     * @return TFactory|null
     */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;newFactory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$factory&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="k"&gt;static&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$factory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;HasFactory&lt;/code&gt; defines a type parameter &lt;code&gt;TFactory&lt;/code&gt; bounded to the sub-classes of &lt;code&gt;Illuminate\Database\Eloquent\Factories\Factory&lt;/code&gt;. So how can that error be fixed?&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TFactory&lt;/code&gt; type must be specified when the trait is being used. So, the &lt;code&gt;use&lt;/code&gt; statement of the &lt;code&gt;HasFactory&lt;/code&gt; trait needs to be annotated with the &lt;strong&gt;PHPDocs&lt;/strong&gt; &lt;code&gt;@use&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Database\Factories\UserFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Auth\User&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&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="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @use HasFactory&amp;lt;UserFactory&amp;gt; */&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;HasFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Preserving Genericness
&lt;/h2&gt;

&lt;p&gt;When extending a class, implementing an interface, or using a trait it is possible to maintain the genericness in the sub-class.&lt;/p&gt;

&lt;p&gt;Preserving the genericness is implemented by defining the same type parameters above the child class and passing it to &lt;code&gt;@extends&lt;/code&gt;, &lt;code&gt;@implements&lt;/code&gt; and &lt;code&gt;@use&lt;/code&gt; tags.&lt;/p&gt;

&lt;p&gt;We will use the &lt;code&gt;Illuminate\Database\Concerns\BuildsQueries&lt;/code&gt; generic trait as an example,&lt;/p&gt;

&lt;p&gt;it defines a type parameter &lt;code&gt;TValue&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @template TValue
 *
 */&lt;/span&gt;
&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;BuildsQueries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mf"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Illuminate\Database\Eloquent\Builder&lt;/code&gt; class uses this trait but keeps its genericness by passing the &lt;code&gt;TModel&lt;/code&gt; parameter type to it. It is now left to the client code to specify the type of &lt;code&gt;TModel&lt;/code&gt; and consequently &lt;code&gt;TValue&lt;/code&gt; in the &lt;code&gt;BuildsQueries&lt;/code&gt; trait.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Builder&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;BuilderContract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @use \Illuminate\Database\Concerns\BuildsQueries&amp;lt;TModel&amp;gt; */&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;BuildsQueries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ForwardsCalls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;QueriesRelationships&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;BuildsQueries&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sole&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;baseSole&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;In conclusion, while PHP does not natively support generics in the same way as some other programming languages, the introduction of advanced type hints and tools like &lt;strong&gt;PHPStan&lt;/strong&gt; allows developers to implement generics-like functionality in their code. By leveraging &lt;strong&gt;PHPDocs&lt;/strong&gt;, parameterized classes, and interfaces, you can create more flexible and type-safe applications that promote code reusability and maintainability. As PHP continues to evolve, the community's growing focus on type safety and static analysis will likely lead to more robust solutions for implementing generics. Embracing these practices not only enhances your coding skills but also contributes to the development of high-quality software that stands the test of time.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>codequality</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Creating Refresh Tokens with Laravel Sanctum</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Sat, 03 Jun 2023 12:19:04 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/creating-refresh-tokens-with-laravel-sanctum-268d</link>
      <guid>https://dev.to/muhamadhhassan/creating-refresh-tokens-with-laravel-sanctum-268d</guid>
      <description>&lt;p&gt;Laravel Sanctum is a lightweight authentication package for SPA applications and APIs. It was released in 2020 and became available out of the box since Laravel 8. Unlike JWT self-contained tokens, Sanctum uses a reference token.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Reference Token?
&lt;/h2&gt;

&lt;p&gt;A reference token is a type of authentication token that contains a reference to the actual data stored on the server side in some data storage. This reference can be used to look up the actual data and verify the authenticity of the token.&lt;br&gt;
Sanctum uses the database as its storage, and if we take a look at the Sanctum &lt;code&gt;personal_access_tokens&lt;/code&gt; database table, we notice that it contains information about the eloquent model that is being authenticated, the token abilities when it was last used and its expiration timestamp.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'personal_access_tokens'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;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="nf"&gt;morphs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tokenable'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'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="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'token'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abilities'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'last_used_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="nf"&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="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'expires_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="nf"&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="nf"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advantages of Reference Tokens
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reference tokens can be preferred in scenarios where the token payload is too large to be included directly in the token.&lt;/li&gt;
&lt;li&gt;Since reference tokens do not include all the necessary data, the risk of data breaches is reduced.&lt;/li&gt;
&lt;li&gt;The token data can be updated or changed without having to invalidate the old token and issue a new one to the client. This can also lead to better scalability since the number of issued and managed tokens is reduced.&lt;/li&gt;
&lt;li&gt;Being smaller in size compared to self-contained tokens, they can be transmitted and processed faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Refresh Tokens Are Needed?
&lt;/h2&gt;

&lt;p&gt;The purpose of Refresh Tokens is to obtain long-term access to an API on behalf of the user which provides a better user experience as users do not need to re-enter their credentials every time their access token expires.&lt;/p&gt;

&lt;p&gt;So, why do not we issue access tokens with a long time-to-live (TTL)? While extending the TTL of an access token may seem like a simple solution, it can increase the risk of security breaches. The longer an access token is valid, the longer a compromised token can be used to access the user's data until it expires.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issuing Refresh Tokens with Sanctum
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Configure Time-to-Live Values
&lt;/h3&gt;

&lt;p&gt;There is a difference in the time-to-live between access tokens and refresh tokens but Sanctum has only one configuration for expiration in &lt;code&gt;config/sanctum.php&lt;/code&gt;. Let's start by adding another configuration for refresh tokens expiration named &lt;code&gt;rt_expiration&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="mf"&gt;.&lt;/span&gt;
    &lt;span class="mf"&gt;.&lt;/span&gt;
    &lt;span class="mf"&gt;.&lt;/span&gt;
    &lt;span class="s1"&gt;'expiration'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// One hour&lt;/span&gt;
    &lt;span class="s1"&gt;'rt_expiration'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 7 Days&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Overriding Sanctum Service Provider
&lt;/h3&gt;

&lt;p&gt;Although the new &lt;code&gt;rt_expiration&lt;/code&gt; configuration to create the refresh tokens, Sanctum will always use the expiration value to check on the token validity. In &lt;code&gt;Laravel\Sanctum\SanctumServiceProvider&lt;/code&gt;, the request guard is created using the default expiration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Register the guard.
 *
 * @param  \Illuminate\Contracts\Auth\Factory  $auth
 * @param  array  $config
 * @return RequestGuard
 */&lt;/span&gt;
&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createGuard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$config&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RequestGuard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sanctum.expiration'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'provider'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createUserProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'provider'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TTL value should be selected based on the incoming request. First, let’s define a new configuration for the refresh token URL pattern:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'rt_url_pattern'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SANCTUM_RT_URL_PATTERN'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*/auth/refresh-token'&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;Then, create a new service provider:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This provider will extend the package’s provider and it will have the new implementation of the &lt;code&gt;createGuard&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Auth\RequestGuard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Auth\Factory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Laravel\Sanctum\Guard&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;SanctumServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Laravel\Sanctum\SanctumServiceProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Register the guard.
     *
     * @param  Factory  $auth
     * @param  array&amp;lt;string, mixed&amp;gt;  $config
     */&lt;/span&gt;
    &lt;span class="na"&gt;#[\Override]&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createGuard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;RequestGuard&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$expiration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sanctum.rt_url_pattern'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sanctum.rt_expiration'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sanctum.expiration'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RequestGuard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$expiration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'provider'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createUserProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'provider'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step is to tell Laravel not to load the package’s service provider. In &lt;code&gt;composer.json&lt;/code&gt;, update the the &lt;code&gt;extra&lt;/code&gt; property as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"extra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"laravel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"dont-discover"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"laravel/sanctum"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Define Token Abilities
&lt;/h3&gt;

&lt;p&gt;The refresh token should have one ability, which is issuing new access tokens. One way to do this is by creating an enumeration for token abilities at &lt;code&gt;app\Enums\TokenAbility.php&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;TokenAbility&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;ISSUE_ACCESS_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'issue-access-token'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;ACCESS_API&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'access-api'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when a user login two tokens will be issued&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Enums\TokenAbility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/auth/login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Credentials check should go here.&lt;/span&gt;

    &lt;span class="nv"&gt;$accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'access_token'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TokenAbility&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ACCESS_API&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sanctum.expiration'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nv"&gt;$refreshToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'refresh_token'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TokenAbility&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ISSUE_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sanctum.rt_expiration'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$accessToken&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;plainTextToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'refresh_token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$refreshToken&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;plainTextToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use the token abilities in protecting routes, we need to add Sanctum abilities middlewares. In &lt;strong&gt;Laravel 10.X&lt;/strong&gt; and prior, the middlewares should be added to the $middlewareAliases property in &lt;code&gt;app/Http/Kernel.php&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'abilities'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;\Laravel\Sanctum\Http\Middleware\CheckAbilities&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s1"&gt;'ability'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;\Laravel\Sanctum\Http\Middleware\CheckForAnyAbility&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting from &lt;strong&gt;Laravel 11.X&lt;/strong&gt;, middlewares configuration is part of the application bootstrap file at &lt;code&gt;./bootstrap/app.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basePath&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withRouting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../routes/web.php'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../routes/api.php'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;commands&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../routes/console.php'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'/up'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Middleware&lt;/span&gt; &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'abilities'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;\Laravel\Sanctum\Http\Middleware\CheckAbilities&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'ability'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;\Laravel\Sanctum\Http\Middleware\CheckForAnyAbility&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Assign the Ability Middleware to Routes
&lt;/h3&gt;

&lt;p&gt;Finally, the route for issuing a new access token should be protected by the ability middleware&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Enums\TokenAbility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/auth/refresh-token'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'access_token'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TokenAbility&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ACCESS_API&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sanctum.expiration'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$accessToken&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;plainTextToken&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'auth:sanctum'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ability:'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TokenAbility&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ISSUE_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&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;In summary, refresh tokens can make your application more secure but because they are powerful authentication artifacts, they should be kept secure. You can learn more about securing refresh tokens from this &lt;a href="https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/#Keeping-Refresh-Tokens-Secure" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>auth</category>
    </item>
    <item>
      <title>Using ULID in Laravel Framework</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Sat, 20 May 2023 16:10:06 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/using-ulid-in-laravel-framework-4gck</link>
      <guid>https://dev.to/muhamadhhassan/using-ulid-in-laravel-framework-4gck</guid>
      <description>&lt;p&gt;In a previous &lt;a href="https://dev.to/muhamadhhassan/using-unique-identifiers-as-primary-key-in-mysql-5h1k"&gt;post&lt;/a&gt;, we talked about how ULID can be a better choice for primary keys in MySQL than UUIDs. In this tutorial, we will go over how to use ULID in Laravel Framework.&lt;/p&gt;

&lt;p&gt;ULID has been supported in Laravel since &lt;a href="https://github.com/laravel/framework/releases/tag/v9.30.1" rel="noopener noreferrer"&gt;v9.30.1&lt;/a&gt; and has received some improvements in later releases So no third-party packages are needed to use it.&lt;/p&gt;

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

&lt;p&gt;Let's take an &lt;code&gt;Article&lt;/code&gt; model as an example. First, we create the article's model and migration file as we normally do&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;up&lt;/code&gt; method inside the migration file, the table's primary key will be defined using the &lt;code&gt;ulid&lt;/code&gt; method followed by the primary method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ulid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'body'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the &lt;code&gt;[ulid](https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Schema/Blueprint.php#L1288)&lt;/code&gt; method does is create a column of type &lt;code&gt;CHAR&lt;/code&gt; and set its length to 26 bytes instead of the 36 bytes needed for UUIDs.&lt;/p&gt;

&lt;p&gt;Then in the &lt;code&gt;Article&lt;/code&gt; eloquent model, the &lt;code&gt;Illuminate\Database\Eloquent\Concerns\HasUlids&lt;/code&gt; trait will be added&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Concerns\HasUlids&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Factories\HasFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&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;Article&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;HasFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HasUlids&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;Laravel also has a method in the &lt;code&gt;Illuminate\Database\Schema\Blueprint&lt;/code&gt; class for creating foreign keys that references a table with ULID primary key.&lt;/p&gt;

&lt;p&gt;In our example, we can add a &lt;code&gt;Comment&lt;/code&gt; model and each comment belongs to one &lt;code&gt;Article&lt;/code&gt;. The foreign key of the articles table is defined using the &lt;code&gt;foreignUlid&lt;/code&gt; method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'comments'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'body'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreignUlid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'article_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;constrained&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the last method is &lt;code&gt;ulidMorphs&lt;/code&gt; that create the columns needed for a polymorphic relation. Let's add another &lt;code&gt;Tag&lt;/code&gt; model that can be linked to many models not just &lt;code&gt;Article&lt;/code&gt;. The &lt;code&gt;taggables&lt;/code&gt; table can be defined like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'taggables'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreignUlid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tag_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;constrained&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ulidMorphs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'taggable'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Str Facade
&lt;/h3&gt;

&lt;p&gt;ULID can be created anywhere in your app using the &lt;code&gt;ulid&lt;/code&gt; method in the &lt;code&gt;Illuminate\Support\Str&lt;/code&gt; facade.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Str&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;ulid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toBase32&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above statement returns the ULID and it will look something like this &lt;code&gt;01H0WXWP3XGAX0ZJVG7Q2E70FC&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, if you are interested in the implementation being used to generate ULID, check out the &lt;a href="https://github.com/symfony/uid" rel="noopener noreferrer"&gt;Symfony UID&lt;/a&gt; component that Laravel uses.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>mysql</category>
      <category>php</category>
    </item>
    <item>
      <title>Using Unique Identifiers as Primary Key in MySQL</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Sun, 30 Apr 2023 21:06:02 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/using-unique-identifiers-as-primary-key-in-mysql-5h1k</link>
      <guid>https://dev.to/muhamadhhassan/using-unique-identifiers-as-primary-key-in-mysql-5h1k</guid>
      <description>&lt;h1&gt;
  
  
  Using Unique Identifiers as Primary Key in MySQL
&lt;/h1&gt;

&lt;p&gt;Unique identifiers are used to distinguish one object from another. They are commonly used to identify entities such as users, files, processes, network devices, and other objects. Unique identifiers are often implemented using a numerical or alphanumeric string that is assigned to an object when it is created and they have many types like UUID, ULID, &lt;a href="https://en.wikipedia.org/wiki/Snowflake_ID" rel="noopener noreferrer"&gt;Snowflake ID&lt;/a&gt;, &lt;a href="https://betterexplained.com/articles/the-quick-guide-to-guids/" rel="noopener noreferrer"&gt;GUID&lt;/a&gt; and more.&lt;/p&gt;

&lt;p&gt;Using integers for tables’ primary key is the go-to approach when working with MySQL and other RDBMS. But, using unique identifiers instead of auto-incremented integers can have some benefits like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unique identifiers have a low probability of collision even across tables and databases.&lt;/li&gt;
&lt;li&gt;They can be generated by the application without a centralized authority.&lt;/li&gt;
&lt;li&gt;And since they are pseudo-random, they can be sent safely to the client side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But as with any tech or tool there are some tradeoffs that come with using unique identifier.&lt;/p&gt;

&lt;h1&gt;
  
  
  UUIDs
&lt;/h1&gt;

&lt;p&gt;UUID stands for Universally Unique Identifier, which is a standard for generating unique identifiers that are widely used in computer systems and software applications. UUID consists of two parts: a time-based component and a random component, and there are officially 5 versions of UUID, each with different algorithm for generating the random and time-based components. The 128-bit value of a UUID is usually represented as a string of 36 characters, consisting of 32 hexadecimal digits separated by hyphens in the form of &lt;code&gt;8-4-4-4-12&lt;/code&gt;. For example, a UUID might look like this: &lt;code&gt;245dffb2-7068-405f-b759-88c3ef8bcf3d&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  UUIDs are Pseudo Random
&lt;/h2&gt;

&lt;p&gt;The negative impact of using UUID as primary key comes from how MySQL’s default engine, &lt;code&gt;InnoDB&lt;/code&gt;, stores the data. &lt;code&gt;InnoDB&lt;/code&gt; by default creates a b-tree for the table’s primary key and stores the rows data in the leaf nodes of the same b-tree which is called a clustered index. In other words, when a table has a clustered index, the data is physically stored on the disk in the same order as the index.&lt;/p&gt;

&lt;p&gt;When a new row with a random UUID needs to be inserted, &lt;code&gt;InnoDB&lt;/code&gt; needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checks whether the page is already in the &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html" rel="noopener noreferrer"&gt;buffer pool&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;If the page is not in the buffer pool, &lt;code&gt;InnoDB&lt;/code&gt; reads the page from disk.&lt;/li&gt;
&lt;li&gt;Write the page to the buffer pool.&lt;/li&gt;
&lt;li&gt;Insert the new row.&lt;/li&gt;
&lt;li&gt;At some point, the page will be flushed back to the disk.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Normally when a page is frequently accessed and modified it becomes a hot page, and the buffer pool gives it higher priority to stay in memory as long as possible. This can result in performance gains in terms of latency and throughput. But, when the primary key is random, it is unlikely for a page to become frequently accessed thus each insert will mostly require an extra disk I/O. &lt;/p&gt;

&lt;p&gt;Additionally, inserting rows with random primary key can cause more page splits. A page split occurs when an &lt;code&gt;InnoDB&lt;/code&gt; page becomes full and cannot accommodate the new data. thus it needs to be divided into two or more smaller pages. This operation is costly in terms of performance as it requires many disk I/O operations to read and write data. &lt;/p&gt;

&lt;p&gt;Random primary keys can also lead to page low filling factor. According to &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-physical-structure.html" rel="noopener noreferrer"&gt;MySQL documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When new records are inserted into an &lt;code&gt;InnoDB&lt;/code&gt; clustered index, &lt;code&gt;InnoDB&lt;/code&gt; tries to leave 1/16 of the page free for future insertions and updates of the index records. If index records are inserted in a sequential order (ascending or descending), the resulting index pages are about 15/16 full. If records are inserted in a random order, the pages are from 1/2 to 15/16 full.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  UUIDs Size
&lt;/h2&gt;

&lt;p&gt;UUIDs have a size of 128 bits and their hexadecimal form (&lt;code&gt;8-4-4-4-12&lt;/code&gt;) can be stored in a &lt;code&gt;CHAR(36)&lt;/code&gt; column because each hexadecimal digit represents 4 bits so it will 32. However, since each character in a CHAR column in MySQL is represented by one byte of storage, 36 characters (32 for the digits and 4 for the hyphens) in a &lt;code&gt;CHAR(36)&lt;/code&gt; column will require 36 bytes of storage.&lt;/p&gt;

&lt;p&gt;Having 36 bytes for the primary key does not seem to be a lot at first glance and to put it into perspective lets assume a table with a UUID primary key and 4 secondary indexes. Considering that each secondary index store the primary key of its row, the UUID will be stored 5 times for each row. If the table has 1 million rows the storage required will be&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;6 x 36 = 216 bytes of storage per row&lt;/li&gt;
&lt;li&gt;For the 10M rows:
10,000,000 rows x 216 bytes/row = 2,160,000,000 bytes&lt;/li&gt;
&lt;li&gt;To convert this to gigabytes, we divide by 100,000,000 (the number of bytes in a gigabyte):
2,160,000,000 bytes / 1,000,000,000 bytes/GB = 2.16 GB&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  ULIDs
&lt;/h1&gt;

&lt;p&gt;ULID stands for Universally Unique Lexicographically Sortable Identifier and it tries to solve some of UUIDs limitations. ULIDs are 26 characters long and consist of two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A 10-character timestamp, measured in milliseconds since Unix epoch time (January 1, 1970, 00:00:00 UTC). This provides the chronological ordering of ULIDs.&lt;/li&gt;
&lt;li&gt;A 16-character random value, encoded using a &lt;a href="https://www.crockford.com/base32.html" rel="noopener noreferrer"&gt;Crockford's&lt;/a&gt; base32 encoding. This value ensures that each ULID is unique even if generated at the same time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Additionally, according to the ULID spec, it can be superior to UUIDs given that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has &lt;code&gt;1.21 X 10^24&lt;/code&gt; possible values per millisecond.&lt;/li&gt;
&lt;li&gt;Lexicographically sortable&lt;/li&gt;
&lt;li&gt;Canonically encoded as a 26-character string, as opposed to the 36-character UUID&lt;/li&gt;
&lt;li&gt;Case insensitive&lt;/li&gt;
&lt;li&gt;URL safe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In conclusion, ULID can solve the performance issues resulting from the randomness of UUID and it is more efficient in terms of storage. So it would be a better alternative to integer primary key than UUIDs. It is also implemented in many programming language&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>performance</category>
    </item>
    <item>
      <title>Sending Laravel Logs to Mattermost Channels</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Sat, 24 Sep 2022 09:44:53 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/sending-laravel-logsto-mattermost-channels-3iob</link>
      <guid>https://dev.to/muhamadhhassan/sending-laravel-logsto-mattermost-channels-3iob</guid>
      <description>&lt;p&gt;&lt;a href="https://mattermost.com/" rel="noopener noreferrer"&gt;Mattermost&lt;/a&gt; is an open-source platform for communication and collaboration with integrations with many tools. It is mostly considered as an open-source alternative to Slack and Microsoft Teams.&lt;/p&gt;

&lt;p&gt;Although Laravel does not have an official &lt;a href="https://laravel.com/docs/9.x/logging#available-channel-drivers" rel="noopener noreferrer"&gt;log channel driver&lt;/a&gt; for Mattermost, we can build a custom &lt;a href="https://github.com/Seldaek/monolog" rel="noopener noreferrer"&gt;Monolog&lt;/a&gt; handler that can be easily configured in Laravel apps.&lt;/p&gt;

&lt;p&gt;I have created a small &lt;a href="https://github.com/muhamadhhassan/laramost" rel="noopener noreferrer"&gt;package&lt;/a&gt; for this purpose that, unlike the existing Mattermost handlers, format the message according to Mattermost &lt;a href="https://developers.mattermost.com/integrate/webhooks/incoming/#parameters" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;composer require muhamadhhassan/laramost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;config/logging.php&lt;/code&gt; file, add the &lt;code&gt;mattermost&lt;/code&gt; channel to the &lt;code&gt;channels&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;LaraMost\Formatter\MattermostFormatter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;LaraMost\Handler\MattermostWebhookHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="s1"&gt;'channels'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'mattermost'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'driver'&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'monolog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'handler'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;MattermostWebhookHandler&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'formatter'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;MattermostFormatter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'with'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'hook'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'https://your-mattermost.com/hooks/random-string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'level'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can follow the steps &lt;a href="https://developers.mattermost.com/integrate/webhooks/incoming/#create-an-incoming-webhook" rel="noopener noreferrer"&gt;here&lt;/a&gt; to create an incoming webhook for your channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Levels
&lt;/h3&gt;

&lt;p&gt;Monolog levels are used to set the message color and icon&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level Name&lt;/th&gt;
&lt;th&gt;Level Value&lt;/th&gt;
&lt;th&gt;Color&lt;/th&gt;
&lt;th&gt;Emoji&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DEBUG&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;#91C4EB&lt;/td&gt;
&lt;td&gt;🔍&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;#91C4EB&lt;/td&gt;
&lt;td&gt;ℹ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NOTICE&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;#99cc33&lt;/td&gt;
&lt;td&gt;📝&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;td&gt;#ffcc00&lt;/td&gt;
&lt;td&gt;⚠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ERROR&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;#cc3300&lt;/td&gt;
&lt;td&gt;🐛&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;#cc3300&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EMERGENCY&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;td&gt;#cc3300&lt;/td&gt;
&lt;td&gt;🚨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Simply, using Laravel &lt;code&gt;Log&lt;/code&gt; facade&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mattermost'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Something went wrong'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will send the following message to your mattermost channel:&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;⚠ &lt;strong&gt;Warning&lt;/strong&gt;: When you log to the &lt;code&gt;mattermost&lt;/code&gt; channel make sure that the level is greater than or equals the one defined in &lt;code&gt;config/logging.php&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And there you have it! A simple implementation to send log records to a Mattermost channel.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>mattermost</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Preventing User Enumeration Attack in Laravel Apps</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Fri, 13 May 2022 13:42:30 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/preventing-user-enumeration-attack-in-laravel-apps-b77</link>
      <guid>https://dev.to/muhamadhhassan/preventing-user-enumeration-attack-in-laravel-apps-b77</guid>
      <description>&lt;p&gt;User enumeration is a brute-force technique that is used to collect or verify valid users' credentials. It belongs to the &lt;strong&gt;Identification and Authentication Failures&lt;/strong&gt; category (AKA broken authentication) which came in 7th place on the &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;Top 10 Web Application Security Risks 2021&lt;/a&gt; by OWASP down from the 2nd place in the 2017 version. It can also be part of phishing attack or other brute-force attacks like &lt;a href="https://owasp.org/www-community/attacks/Credential_stuffing" rel="noopener noreferrer"&gt;credential stuffing&lt;/a&gt; and &lt;a href="https://owasp.org/www-community/attacks/Password_Spraying_Attack" rel="noopener noreferrer"&gt;password spraying&lt;/a&gt;.&lt;br&gt;
Bear in mind that user enumeration vulnerabilities are not exclusive for web applications, it can be found in any system that requires authentication.&lt;/p&gt;
&lt;h4&gt;
  
  
  Attacking Scenarios
&lt;/h4&gt;

&lt;p&gt;The malicious actor will be basically looking for differences in the authentication server's response, in terms of response time and body, based on the authenticity of submitted credentials.  This can happen while using one of the following functionalities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Registration&lt;/li&gt;
&lt;li&gt;Password Reset&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Laravel Authentication
&lt;/h4&gt;

&lt;p&gt;Laravel provide us with robust solutions and starter kits for authentication so let's start by creating a new Laravel 9 project and install &lt;a href="https://jetstream.laravel.com" rel="noopener noreferrer"&gt;Jetstram&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;laravel new user-enum

composer require laravel/jetstream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and for simplicity we will use SQLite &lt;code&gt;3.36.0&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE="[PROJECT_PATH]/user-enum/database/database.sqlite"
DB_USERNAME=root
DB_PASSWORD=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Login
&lt;/h4&gt;

&lt;p&gt;Out of the box, the error message is consistent whether you entered an incorrect email or password.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Password Reset
&lt;/h4&gt;

&lt;p&gt;Here, the error message discloses that a user doesn't exist in the system so, as we mentioned, we need to make the response message and time consistent.&lt;/p&gt;

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

&lt;p&gt;Moreover, a malicious user can validate user email address existence by sending the reset password request twice. If the email address is valid,  on the second attempt a different error message is returned&lt;/p&gt;

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

&lt;p&gt;Under the hood, Jetstream is using &lt;a href="https://laravel.com/docs/9.x/fortify" rel="noopener noreferrer"&gt;Fortify&lt;/a&gt; which is a frontend-agnostic authentication implementation. Our first stop will be the controller registered by Fortify for password reset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan route:list
  ...
  POST  forgot-password ............. password.email › Laravel&lt;span class="se"&gt;\F&lt;/span&gt;ortify › PasswordResetLinkController@store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what the method &lt;code&gt;Laravel\Fortify\PasswordResetLinkController::store&lt;/code&gt; do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, it validates the submitted email address.&lt;/li&gt;
&lt;li&gt;Then the password broker tries to send the reset email to the user of the submitted email address.&lt;/li&gt;
&lt;li&gt;Based on the return value of the &lt;code&gt;\Illuminate\Contracts\Auth\PasswordBroker::sendResetLink()&lt;/code&gt; method, the response is determined hence the user information is disclosed.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Responsable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;Fortify&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&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="s1"&gt;'required|email'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// We will send the password reset link to this user. Once we have attempted&lt;/span&gt;
    &lt;span class="c1"&gt;// to send the link, we will examine the response then see the message we&lt;/span&gt;
    &lt;span class="c1"&gt;// need to show to the user. Finally, we'll send out a proper response.&lt;/span&gt;
    &lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendResetLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Fortify&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;email&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;$status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RESET_LINK_SENT&lt;/span&gt;
                &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SuccessfulPasswordResetLinkRequestResponse&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FailedPasswordResetLinkRequestResponse&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$status&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 fix this, we will create our controller at &lt;code&gt;App\Http\Controller\Auth\PasswordResetLinkController&lt;/code&gt; that will extend Fortify's controller. The difference here is that instead of returning the invalid email address error, we will log it and return the same &lt;code&gt;SuccessfulPasswordResetLinkRequestResponse&lt;/code&gt; message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Responsable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;Fortify&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&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="s1"&gt;'required|email'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Fortify&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendResetLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nc"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RESET_LINK_SENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="s1"&gt;'en'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SuccessfulPasswordResetLinkRequestResponse&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RESET_LINK_SENT&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;Then we need to define our &lt;code&gt;reset-password&lt;/code&gt; route in &lt;code&gt;routes/web.php&lt;/code&gt; that will point to the above controller&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'reset-password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'App\Http\Controllers\Auth\PasswordResetLinkController@store'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password.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="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'guest'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the response message will be the same regardless of the email validity. But, what about the response time? as you can see in the below screenshot, the first request, with an invalid email, took less than a second, while the one with a valid email took over 6 seconds!&lt;/p&gt;

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

&lt;p&gt;One way to reduce the gap between the two scenarios is to make the &lt;code&gt;Illuminate\Auth\Notifications\ResetPassword&lt;/code&gt; notification queueable. So, again we will create our version of this notification at &lt;code&gt;App\Notifications\ResetPassword&lt;/code&gt; and make it so. Check the Laravel docs for more information on &lt;a href="https://laravel.com/docs/9.x/notifications#queueing-notifications" rel="noopener noreferrer"&gt;queuing notifications&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Auth\Notifications\ResetPassword&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;CoreResetPassword&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Bus\Queueable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Queue\ShouldQueue&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;ResetPassword&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CoreResetPassword&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShouldQueue&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Queueable&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;Then we will override the &lt;code&gt;Illuminate\Auth\Passwords\CanResetPassword::sendPasswordResetNotification()&lt;/code&gt; method in the &lt;code&gt;App\Models\User&lt;/code&gt; model&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sendPasswordResetNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ResetPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Registration
&lt;/h4&gt;

&lt;p&gt;I think you already know the answer to this. Yes, the registration response will disclose whether the user email exist or not.&lt;/p&gt;

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

&lt;p&gt;To make the response consistent, we will &lt;a href="https://laravel.com/docs/9.x/verification#model-preparation" rel="noopener noreferrer"&gt;enable user email verification&lt;/a&gt; so that an email is sent in both scenarios&lt;/p&gt;

&lt;p&gt;Then publish Fortify resources so that its actions become editable. Specifically &lt;code&gt;App\Actions\Fortify\CreateNewUser&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan vendor:publish &lt;span class="nt"&gt;--provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Laravel&lt;/span&gt;&lt;span class="se"&gt;\F&lt;/span&gt;&lt;span class="s2"&gt;ortify&lt;/span&gt;&lt;span class="se"&gt;\F&lt;/span&gt;&lt;span class="s2"&gt;ortifyServiceProvider"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The changes is quite simple, first, we remove the &lt;code&gt;unique&lt;/code&gt; rule from the &lt;code&gt;email&lt;/code&gt; input. Then, if a user with the submitted email address exist, an email will be sent to notify him/her.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;?User&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Validator&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'max:255'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'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="s1"&gt;'max:255'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;passwordRules&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="s1"&gt;'terms'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Jetstream&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;hasTermsAndPrivacyPolicyFeature&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;span class="s1"&gt;'accepted'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;whereEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="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="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AlreadyHaveAccount&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$input&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$input&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Hash&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the &lt;code&gt;App\Notifications\AlreadyHaveAccount&lt;/code&gt; notification will be&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Bus\Queueable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Queue\ShouldQueue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Notifications\Messages\MailMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Notifications\Notification&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Lang&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;AlreadyHaveAccount&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShouldQueue&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Queueable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$notifiable&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'mail'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;toMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$notifiable&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;MailMessage&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MailMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'New Registration Attempt with Your Email Address'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'You are receiving this email because we received a registration request with your registered email address.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Login Instead'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Lang&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'If you did not try to register a new account, no further action is required.'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will create a job that accept &lt;code&gt;CreateNewUser&lt;/code&gt; action and the submitted input to make the response time consistent&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Auth\Events\Registered&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Bus\Queueable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Queue\ShouldQueue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Bus\Dispatchable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Queue\InteractsWithQueue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Queue\SerializesModels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Laravel\Fortify\Contracts\CreatesNewUsers&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;RegisterUser&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShouldQueue&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Dispatchable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InteractsWithQueue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Queueable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SerializesModels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;CreatesNewUsers&lt;/span&gt; &lt;span class="nv"&gt;$creator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;creator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Registered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, create a controller for registration, like we did with resetting passwords, and make the &lt;code&gt;register&lt;/code&gt; route point to it&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Http\Responses\RegisterResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Jobs\RegisterUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Laravel\Fortify\Contracts\CreatesNewUsers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Laravel\Fortify\Http\Controllers\RegisteredUserController&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;FortifyRegisteredUserController&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;RegisteredUserController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FortifyRegisteredUserController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;CreatesNewUsers&lt;/span&gt; &lt;span class="nv"&gt;$creator&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;RegisterResponse&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;RegisterUser&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$creator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegisterResponse&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'register'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'App\Http\Controllers\Auth\RegisteredUserController@store'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'guest'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now login, reset password and registration will never disclose existing users information and our app is protected against user enumeration attacks ✌.&lt;/p&gt;

</description>
      <category>security</category>
      <category>laravel</category>
      <category>tutorial</category>
      <category>php</category>
    </item>
    <item>
      <title>Adding PHPUnit Test Log and Coverage to GitLab CI/CD Pipeline</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Fri, 22 Apr 2022 22:33:34 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/adding-phpunit-test-log-and-coverage-to-gitlab-cicd-33b5</link>
      <guid>https://dev.to/muhamadhhassan/adding-phpunit-test-log-and-coverage-to-gitlab-cicd-33b5</guid>
      <description>&lt;p&gt;In this tutorial we are going to setup a GitLab CI/CD job that can run your &lt;code&gt;PHPUnit&lt;/code&gt; test suite and extract a testing report plus the overall coverage. First, we need to setup our server and install the required tools. &lt;code&gt;DigitalOcean&lt;/code&gt; has many useful tutorials and we are going to use some of them for the initial setup.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;Ubuntu 20.04&lt;/code&gt; server setup by following this &lt;a href="https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-20-04" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;Docker&lt;/code&gt; following this &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Finally, installing &lt;code&gt;Docker Compose&lt;/code&gt; by following this &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-20-04" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server Setup
&lt;/h2&gt;

&lt;p&gt;Now that the server’s initial setup is complete, our next steps will be: installing GitLab runner, register a runner for your project and create a user for deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing GitLab Runner
&lt;/h3&gt;

&lt;p&gt;1- Adding the official &lt;code&gt;gitlab-runner&lt;/code&gt; repo and inspecting the security of the installing script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; script.deb.sh
   less script.deb.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2- Running the installer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;bash script.deb.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3- Install &lt;code&gt;gitlab-runner&lt;/code&gt; service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;gitlab-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4- Check the service status&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   systemctl status gitlab-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should be something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   Output
   ● gitlab-runner.service - GitLab Runner
      Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/etc/systemd/system/gitlab-runner.service&lt;span class="p"&gt;;&lt;/span&gt; enabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
      Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Mon 2020-06-01 09:01:49 UTC&lt;span class="p"&gt;;&lt;/span&gt; 4s ago
    Main PID: 16653 &lt;span class="o"&gt;(&lt;/span&gt;gitlab-runner&lt;span class="o"&gt;)&lt;/span&gt;
       Tasks: 6 &lt;span class="o"&gt;(&lt;/span&gt;limit: 1152&lt;span class="o"&gt;)&lt;/span&gt;
      CGroup: /system.slice/gitlab-runner.service
              └─16653 /usr/lib/gitlab-runner/gitlab-runner run &lt;span class="nt"&gt;--working-directory&lt;/span&gt; /home/gitlab-runner &lt;span class="nt"&gt;--config&lt;/span&gt; /etc/gitla

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Register a Runner for Your GitLab Project
&lt;/h3&gt;

&lt;p&gt;1- In your GitLab project, navigate to &lt;strong&gt;Settings &amp;gt; CI/CD &amp;gt; Runners&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;2- In the &lt;strong&gt;Specific Runners&lt;/strong&gt; section, you’ll find the &lt;strong&gt;registration token&lt;/strong&gt; and the GitLab URL. Copy both as we’ll need them for the next command.&lt;/p&gt;

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

&lt;p&gt;3- Now in the terminal, register the runner by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;gitlab-runner register &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--url&lt;/span&gt; https://your_gitlab.com &lt;span class="nt"&gt;--registration-token&lt;/span&gt; project_token &lt;span class="nt"&gt;--executor&lt;/span&gt; shell &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Staging Shell Runner"&lt;/span&gt; &lt;span class="nt"&gt;--tag-list&lt;/span&gt; deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This seems like a lot of options but they’re pretty easy to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-n&lt;/code&gt; executes the register command non-interactively.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--url&lt;/code&gt; is the GitLab URL from step 2.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--registration-token&lt;/code&gt; is the token you copied from the runners page in step 2.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--executor&lt;/code&gt; is the executor type, we are using &lt;code&gt;shell&lt;/code&gt; executer here which is a simple executor that you use to execute builds locally on the machine where GitLab Runner is installed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--description&lt;/code&gt; is the runner’s description, which will show up in GitLab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--tag-list&lt;/code&gt; is a list of tags assigned to the runner. Tags can be used in a pipeline configuration to select specific runners for a CI/CD job. The &lt;code&gt;deployment&lt;/code&gt; tag will allow you to refer to this specific runner to execute the deployment job.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4- The output of the above command will return an output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   Output
   Runner registered successfully. Feel free to start it, but &lt;span class="k"&gt;if &lt;/span&gt;it&lt;span class="s1"&gt;'s running already the config should be automatically reloaded!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the runner will show up in your project’s &lt;strong&gt;Settings &amp;gt; CI/CD &amp;gt; Runners&lt;/strong&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Create Deployment User
&lt;/h3&gt;

&lt;p&gt;1- Create a new user&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;2- Add user to docker group to permit &lt;code&gt;deployer&lt;/code&gt; to execute the &lt;code&gt;docker&lt;/code&gt; command, which is required to perform the deployment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3- Create SSH key for &lt;code&gt;deployer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Switch to the &lt;code&gt;deployer&lt;/code&gt; user&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then generate a 4096-bit SSH key&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ssh-keygen &lt;span class="nt"&gt;-b&lt;/span&gt; 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; ⚠ Do not choose a password for your key or you will have to enter it with each job. This is not possible since our runner is non-interactive

Add the new key to the authorized keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
cat ~/.ssh/id_rsa.pub &amp;gt;&amp;gt; ~/.ssh/authorized_keys
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4- Storing the private key in a GitLab CI/CD variable&lt;/p&gt;

&lt;p&gt;First, get the private key be executing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the output and navigate to &lt;strong&gt;Settings &amp;gt; CI / CD &amp;gt; Variables&lt;/strong&gt; and click &lt;strong&gt;Add Variable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;fill the variable form like this&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key: &lt;code&gt;ID_RSA&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: Paste your SSH private key from your clipboard (including a line break at the end).&lt;/li&gt;
&lt;li&gt;Type: &lt;strong&gt;File&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Environment &lt;strong&gt;Scope: All (default)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Protect variable: &lt;strong&gt;Checked&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Mask variable: &lt;strong&gt;Unchecked&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create another variable for your server IP address&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key: &lt;code&gt;SERVER_IP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: &lt;code&gt;your_server_IP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Type: &lt;strong&gt;Variable&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Environment scope: &lt;strong&gt;All (default)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Protect variable: &lt;strong&gt;Checked&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Mask variable: &lt;strong&gt;Checked&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the last variable is for the user&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key: &lt;code&gt;SERVER_USER&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value: &lt;code&gt;deployer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Type: &lt;strong&gt;Variable&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Environment scope: &lt;strong&gt;All (default)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Protect variable: &lt;strong&gt;Checked&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Mask variable: &lt;strong&gt;Checked&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; File
&lt;/h2&gt;

&lt;p&gt;Next, we will be prepare the docker file for testing environment, the application service in docker compose file and finally PHPUnit job in &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Docker file
&lt;/h3&gt;

&lt;p&gt;In your app docker file we will need to install &lt;a href="https://xdebug.org/" rel="noopener noreferrer"&gt;XDebug&lt;/a&gt; extension to collect the testing coverage report and create two new files: &lt;code&gt;phpunit-report.xml&lt;/code&gt; and &lt;code&gt;phpunit-coverage.xml&lt;/code&gt; for testing report and testing coverage.&lt;/p&gt;

&lt;p&gt;We will create the file in &lt;code&gt;./docker/testingApp.dockerfile&lt;/code&gt; with minimal configuration. It should be something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; php:8.1.3-fpm-alpine&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /var/www/&lt;/span&gt;

&lt;span class="c"&gt;# Install alpine packages&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="nt"&gt;--update&lt;/span&gt; &lt;span class="c"&gt;# Add your packages&lt;/span&gt;

&lt;span class="c"&gt;# Install php extensions&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;docker-php-ext-install &lt;span class="c"&gt;# Add the PHP extension you need&lt;/span&gt;

&lt;span class="c"&gt;# Install XDebug&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pecl &lt;span class="nb"&gt;install &lt;/span&gt;xdebug &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-php-ext-enable xdebug 

&lt;span class="c"&gt;# Copy existing application directory contents&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=www-data:www-data . .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;phpunit-report.xml phpunit-coverage.xml
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;777 phpunit-report.xml phpunit-coverage.xml

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; www-data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Application Service
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;app&lt;/code&gt; service in &lt;code&gt;./docker/docker-compose-testing.yml&lt;/code&gt; will have two volumes: one for the &lt;code&gt;tests&lt;/code&gt; directory and the other is &lt;code&gt;./docker/php/conf.d/xdebug.ini&lt;/code&gt; that will contain the basic XDebug configuration.&lt;/p&gt;

&lt;p&gt;The app service should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app-testing"&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./docker/testingApp.dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/www&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And xdebug.ini is quite minimal, we just set enable the &lt;code&gt;coverage&lt;/code&gt; mode but you can enable multiple modes at the same time. Learn more about XDebug modes from the &lt;a href="https://xdebug.org/docs/all_settings#mode" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;zend_extension&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;xdebug&lt;/span&gt;

&lt;span class="nn"&gt;[xdebug]&lt;/span&gt;
&lt;span class="py"&gt;xdebug.mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;coverage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PHPUnit Job
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; we will create a job for &lt;code&gt;PHPUnit&lt;/code&gt;  that will have the &lt;code&gt;deployment&lt;/code&gt; tag so that it uses our runner and extract the required artifacts for GitLab to display test reports.&lt;/p&gt;

&lt;p&gt;The job will be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;phpunit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose -p my-project -f docker/docker-compose-testing.yml build&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose -p my-project -f docker/docker-compose-testing.yml up -d&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker exec $CONTAINER_NAME php artisan migrate&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker exec $CONTAINER_NAME php artisan db:seed&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker exec -t $CONTAINER_NAME vendor/bin/phpunit --do-not-cache-result --log-junit phpunit-report.xml --coverage-cobertura phpunit-coverage.xml --coverage-text --colors=never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker cp $CONTAINER_NAME:/var/www/phpunit-report.xml ./&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker cp $CONTAINER_NAME:/var/www/phpunit-coverage.xml ./&lt;/span&gt;
  &lt;span class="na"&gt;after_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose -p my-project -f docker/docker-compose-testing.yml down&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;junit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;phpunit-report.xml&lt;/span&gt;
      &lt;span class="na"&gt;coverage_report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;coverage_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cobertura&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;phpunit-coverage.xml&lt;/span&gt;
  &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/^\s*Lines:\s*\d+.\d+\%/'&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;merge_requests&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should notice that we build our containers using &lt;code&gt;docker-compose-testing.yml&lt;/code&gt;, run the DB migrations and seeder then run our test suit with a few options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt; vendor/bin/phpunit &lt;span class="nt"&gt;--do-not-cache-result&lt;/span&gt; &lt;span class="nt"&gt;--log-junit&lt;/span&gt; phpunit-report.xml &lt;span class="nt"&gt;--coverage-cobertura&lt;/span&gt; phpunit-coverage.xml &lt;span class="nt"&gt;--coverage-text&lt;/span&gt; &lt;span class="nt"&gt;--colors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;never
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--do-not-cache-result&lt;/code&gt; to disable test result caching.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--log-junit phpunit-report.xml&lt;/code&gt; specify the test log format and the output file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--coverage-cobertura phpunit-coverage.xml&lt;/code&gt; specify the coverage full report format and the output file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--coverage-text&lt;/code&gt; generate code coverage report in text format.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--colors=never&lt;/code&gt; disable colors in the output to make it easier to extract the coverage percentage from the command output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we copy the generated reports from inside the container to the pipeline namespace to be used as job artifacts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt;:/var/www/phpunit-report.xml ./
docker &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt;:/var/www/phpunit-coverage.xml ./
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The job will have two artifacts of type &lt;code&gt;reports&lt;/code&gt; the first is the a &lt;code&gt;junit&lt;/code&gt; for test log and a &lt;code&gt;cobertura&lt;/code&gt; report for the test coverage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;junit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;phpunit-report.xml&lt;/span&gt;
      &lt;span class="na"&gt;coverage_report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;coverage_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cobertura&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;phpunit-coverage.xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ The report formats and files’ extensions are specified by GitLab&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Project Configuration
&lt;/h2&gt;

&lt;p&gt;At this point we have created a job for PHPUnit that we run on our &lt;code&gt;Staging Shell Runner&lt;/code&gt; that we registered on the staging server. GitLab will be able to display a test report that include some helpful information like the total execution time of the test suite and the success rate. It will also show the test coverage on the jobs and in the merge request overview.&lt;/p&gt;

&lt;p&gt;To go one step further, we can track the test coverage history and add coverage badge to the project&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Coverage History Using Project Settings (&lt;a href="https://docs.gitlab.com/14.10/ee/ci/pipelines/settings.html#add-test-coverage-results-using-project-settings-deprecated" rel="noopener noreferrer"&gt;Deprecated&lt;/a&gt; in GitLab 14.9)
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Settings &amp;gt; CI/CD &amp;gt; General Pipelines&lt;/strong&gt; and in the &lt;strong&gt;Test Coverage Parsing&lt;/strong&gt; field add the same regular expression that we used in the job &lt;code&gt;^\s*Lines:\s*\d+.\d+\%&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Coverage Badge
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Settings &amp;gt; General Settings &amp;gt; Badges&lt;/strong&gt; and click &lt;strong&gt;Add Badge&lt;/strong&gt; and fill the form as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;strong&gt;PHPUnit Coverage&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Link: &lt;code&gt;https://gitlab.com/[PROJECT_PATH]/-/commits/[BRANCH_NAME]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Badge Image URL: &lt;code&gt;https://gitlab.com/[PROJECT_PATH]/badges/[BRANCH_NAME]/coverage.svg&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;You can see a test report in your pipeline&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Analytics &amp;gt; Repository &amp;gt; Code Coverage Statistics&lt;/strong&gt; to see the history of test coverage&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;The effect of each merge request on the test coverage can be found in the merge request overview page.&lt;/li&gt;
&lt;/ul&gt;

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

</description>
      <category>cicd</category>
      <category>php</category>
      <category>testing</category>
      <category>docker</category>
    </item>
    <item>
      <title>Laravel Static Code Analysis with PHPStan</title>
      <dc:creator>Muhammad Hassan</dc:creator>
      <pubDate>Sat, 26 Feb 2022 12:51:24 +0000</pubDate>
      <link>https://dev.to/muhamadhhassan/laravel-static-code-analysis-with-phpstan-4ehh</link>
      <guid>https://dev.to/muhamadhhassan/laravel-static-code-analysis-with-phpstan-4ehh</guid>
      <description>&lt;p&gt;Code analysis is the process of testing and evaluating a program either statically or dynamically.&lt;/p&gt;

&lt;p&gt;Dynamic analysis is the process of testing and evaluating a program — while software is running. It addresses the diagnosis and correction of bugs, memory issues, and crashes of a program during its execution. While static code analysis is a method of evaluating a program by examining the source code before its execution. It is done by analyzing a set of code against a set of coding rules.&lt;/p&gt;

&lt;p&gt;Static analysis takes place before software testing begins. It guarantees that the code you pass on to testing is the highest quality possible. It also provide an automated feedback loop so the developers will know early on which in turn make it easier, and cheaper, to fix those problems.&lt;/p&gt;

&lt;p&gt;Code analysis is the process of testing and evaluating a program either statically or dynamically.&lt;/p&gt;

&lt;p&gt;Dynamic analysis is the process of testing and evaluating a program — while software is running. It addresses the diagnosis and correction of bugs, memory issues, and crashes of a program during its execution. While static code analysis is a method of evaluating a program by examining the source code before its execution. It is done by analyzing a set of code against a set of coding rules.&lt;/p&gt;

&lt;p&gt;Static analysis takes place before software testing begins. It guarantees that the code you pass on to testing is the highest quality possible. It also provide an automated feedback loop so the developers will know early on which in turn make it easier, and cheaper, to fix those problems.&lt;/p&gt;

&lt;p&gt;In this tutorial we are going to discuss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Code Analysis Jargons

&lt;ul&gt;
&lt;li&gt;Measurements&lt;/li&gt;
&lt;li&gt;Code Structure&lt;/li&gt;
&lt;li&gt;Complexity&lt;/li&gt;
&lt;li&gt;Security Issues&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

What Does PHPStan Bring?

&lt;ul&gt;
&lt;li&gt;Running PHPStan for the First Time&lt;/li&gt;
&lt;li&gt;Rule Levels&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

How to Use PHPStan?

&lt;ul&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Configuration File&lt;/li&gt;
&lt;li&gt;Ignoring Errors&lt;/li&gt;
&lt;li&gt;The Baseline&lt;/li&gt;
&lt;li&gt;Adding PHPStan to your CI/CD&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Limitations of Static Analysis&lt;/li&gt;

&lt;li&gt;Helpful Links&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Analysis Jargons
&lt;/h2&gt;

&lt;p&gt;Before moving to PHPStan, or any other tool, we need to be familiar with the terms that are commonly used in the code analyzation world. You can also think of them as what the tools will be looking for in your software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measurements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;- Naming&lt;/strong&gt;&lt;br&gt;
Checking if variables and methods’ names, are they too short or too long? Do they follow a naming convention like camel-case?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Type Hinting&lt;/strong&gt;&lt;br&gt;
Some tools can suggest a name consistent with the return type. For example a &lt;code&gt;getFoo()&lt;/code&gt; method that returns a &lt;code&gt;boolean&lt;/code&gt; is better be named &lt;code&gt;isFoo()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Lines of Code&lt;/strong&gt;&lt;br&gt;
Measures the line of codes in your class or method against a maximum value. In addition to the number of method's parameter or class' number of public methods and properties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Commented Code&lt;/strong&gt;&lt;br&gt;
Most of the time no commented out block of code will be allowed,  as long as you are using a version control system, you can remove unused code and if needed, it's recoverable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Return Statements&lt;/strong&gt;&lt;br&gt;
How many return statements do you have through out your method? Many return statements make it difficult to understand the method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Return Types&lt;/strong&gt;&lt;br&gt;
Makes sure that return type matches the expected. Having many return types possibilities confuses the analyzers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Code Structure
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;- Dedicated Exceptions&lt;/strong&gt;&lt;br&gt;
Ensure the use of dedicated exceptions, instead of generic run-time exceptions, that can be cached by client code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- No Static Calls&lt;/strong&gt;&lt;br&gt;
Avoid using static calls in your code and instead use dependency injection. Factory methods is the only exception.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- DRY&lt;/strong&gt;&lt;br&gt;
Checks for code duplication either in repeating literal values or whole blocks of code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;Having a lot of control structures in one method AKA the pyramid of doom. Possible fixes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Early return statements&lt;/li&gt;
&lt;li&gt;Merging nested if statements in combination with helper functions that make the condition readable&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Security Issues
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;- Cipher Algorithms&lt;/strong&gt;&lt;br&gt;
Ensure the use cryptographic systems resistant to cryptanalysis, which are not vulnerable to well-known attacks like brute force attacks for example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Cookies&lt;/strong&gt;&lt;br&gt;
Always create sensitive cookies with the “secure” flag so it’s not sent over an unencrypted HTTP request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Dynamic Execution&lt;/strong&gt;&lt;br&gt;
Some APIs allow the execution of dynamic code by providing it as strings at runtime. Most of the time their use is frowned upon as they also increase the risk of code injection.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Does &lt;em&gt;PHPStan&lt;/em&gt; Bring?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Running &lt;em&gt;PHPStan&lt;/em&gt; for the First Time
&lt;/h3&gt;

&lt;p&gt;I have been using &lt;em&gt;SonarQube&lt;/em&gt; for quite long time but when I first came across &lt;em&gt;PHPStan&lt;/em&gt; &lt;a href="https://github.com/phpstan/phpstan" rel="noopener noreferrer"&gt;repo&lt;/a&gt; I found this arguable claim...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;PHPStan&lt;/em&gt; focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of each line of the code can be checked before you run the actual line.&lt;br&gt;
So to put it to the test, I installed &lt;em&gt;PHPStan&lt;/em&gt; in an application that has been analyzed with &lt;em&gt;SonarQube&lt;/em&gt; since day one and the results were impressive&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptzmjgtlmnfdd01rbjfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptzmjgtlmnfdd01rbjfe.png" alt="Image Test results" width="800" height="366"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;PHPStan&lt;/em&gt; has many rule levels, and as you can see, the higher the level we select the more errors we get with a maximum of 516 errors. Now the question is, which level should we select? Well first we need to know what are the rules of each level.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rule Levels
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00&lt;/td&gt;
&lt;td&gt;Basic Checks&lt;/td&gt;
&lt;td&gt;Checks for Unknown classes, unknown functions, unknown methods called on $this, wrong number of arguments passed to those methods and functions, always undefined variables.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;01&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;$this&lt;/code&gt; Unknowns&lt;/td&gt;
&lt;td&gt;Possibly undefined variables, unknown magic methods and properties on classes with &lt;code&gt;__call&lt;/code&gt; and &lt;code&gt;__get&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02&lt;/td&gt;
&lt;td&gt;Methods&lt;/td&gt;
&lt;td&gt;Unknown methods checked on all expressions (not just &lt;code&gt;$this&lt;/code&gt;), validating &lt;em&gt;PHPDocs.&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03&lt;/td&gt;
&lt;td&gt;Types&lt;/td&gt;
&lt;td&gt;Checks for return types, types assigned to properties.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04&lt;/td&gt;
&lt;td&gt;Dead Code&lt;/td&gt;
&lt;td&gt;Basic dead code checking - always false &lt;code&gt;instanceof&lt;/code&gt; and other type checks, dead &lt;code&gt;else&lt;/code&gt; branches, unreachable code after &lt;code&gt;return&lt;/code&gt;; etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;05&lt;/td&gt;
&lt;td&gt;Arguments&lt;/td&gt;
&lt;td&gt;Checking types of arguments passed to methods and functions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;06&lt;/td&gt;
&lt;td&gt;Type Hints&lt;/td&gt;
&lt;td&gt;Reports missing type hints.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;07&lt;/td&gt;
&lt;td&gt;Union Types&lt;/td&gt;
&lt;td&gt;Reports partially wrong union types, if you call a method that only exists on some types in a union type, level 7 starts to report that.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;08&lt;/td&gt;
&lt;td&gt;Nullable Types&lt;/td&gt;
&lt;td&gt;Report calling methods and accessing properties on nullable types.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09&lt;/td&gt;
&lt;td&gt;Mixed Type&lt;/td&gt;
&lt;td&gt;Be very strict about the mixed type, the only allowed operation you can do with it is to pass it to another mixed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  How to Use &lt;em&gt;PHPStan&lt;/em&gt;?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;To use &lt;em&gt;PHPStan&lt;/em&gt; with Laravel we are going to use &lt;a href="https://github.com/nunomaduro/larastan" rel="noopener noreferrer"&gt;Larastan&lt;/a&gt; extension. &lt;a href="https://phpstan.org/user-guide/extension-library#installing-extensions" rel="noopener noreferrer"&gt;Extensions&lt;/a&gt; are useful when there are subjective bugs or to accommodate to a certain framework while taking advantage of &lt;em&gt;PHPStan&lt;/em&gt; capabilities.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First we install the package with composer
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   composer require nunomaduro/larastan:^2.0 &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: This version requires PHP 8.0+ and Laravel 9.0+&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Then you can start analyzing your code with the console command using the default configuration of &lt;em&gt;PHPStan&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ./vendor/bin/phpstan analyse app &lt;span class="nt"&gt;--memory-limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here we specified the path that we want to analyze &lt;code&gt;app&lt;/code&gt; and the memory limit &lt;code&gt;25&lt;/code&gt; MB. You can find all the options of the command line &lt;a href="https://phpstan.org/user-guide/command-line-usage" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuration File
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;PHPStan&lt;/em&gt; uses configuration file, &lt;code&gt;phpstan.neon&lt;/code&gt; or &lt;code&gt;phpstan.neon.dist&lt;/code&gt;, that allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define the paths that will be analyzed.&lt;/li&gt;
&lt;li&gt;Set the rule level.&lt;/li&gt;
&lt;li&gt;Exclude paths.&lt;/li&gt;
&lt;li&gt;Include &lt;em&gt;PHPStan&lt;/em&gt; extensions.&lt;/li&gt;
&lt;li&gt;Ignore errors.&lt;/li&gt;
&lt;li&gt;Define the maximum number of parallel processes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of a simple configuration file which by default lives in the root directory of your application but you can learn more from the configuration &lt;a href="https://phpstan.org/config-reference" rel="noopener noreferrer"&gt;reference&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;includes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vendor/nunomaduro/larastan/extension.neon&lt;/span&gt;

&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;config&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;routes&lt;/span&gt;

    &lt;span class="c1"&gt;# The level 9 is the highest level&lt;/span&gt;
    &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

    &lt;span class="na"&gt;ignoreErrors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#PHPDoc&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tag&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;@var#'&lt;/span&gt;

    &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;maximumNumberOfProcesses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;

    &lt;span class="na"&gt;noUnnecessaryCollectionCall&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;checkMissingIterableValueType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ignoring Errors
&lt;/h3&gt;

&lt;p&gt;Most probably, you are going to need to ignore some errors which is luckily allowed in two different ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inline using &lt;em&gt;PHPDoc&lt;/em&gt; tags
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;   &lt;span class="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="cd"&gt;/** @phpstan-ignore-next-line */&lt;/span&gt;
       &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

       &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt; &lt;span class="cd"&gt;/** @phpstan-ignore-line */&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;From the configuration file and this is actually more clean
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;     &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

         &lt;span class="na"&gt;ignoreErrors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

             &lt;span class="pi"&gt;-&lt;/span&gt;
                 &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Access&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;an&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;undefined&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;property&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[a-zA-Z0-9\_]+::\$foo'&lt;/span&gt;
                 &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;some/dir/someFile.php&lt;/span&gt;
             &lt;span class="pi"&gt;-&lt;/span&gt;
                 &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#Call&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;an&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;undefined&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[a-zA-Z0-9\_]+::doFoo()#'&lt;/span&gt;
                 &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;other/dir/DifferentFile.php&lt;/span&gt;
                 &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# optional, and it will ignore the first two occurances of the error&lt;/span&gt;
         &lt;span class="err"&gt; &lt;/span&gt;&lt;span class="pi"&gt;-&lt;/span&gt;
                 &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#Call&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;an&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;undefined&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[a-zA-Z0-9\_]+::doBar()#'&lt;/span&gt;
                 &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;some/dir/*&lt;/span&gt;
                     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;other/dir/*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Baseline
&lt;/h3&gt;

&lt;p&gt;Introducing &lt;em&gt;PHPStan&lt;/em&gt; to the CI pipeline, increasing strictness level or upgrading to a newer version can be overwhelming. &lt;em&gt;PHPStan&lt;/em&gt; allows you to declare the currently reported list of errors as &lt;em&gt;“the baseline”&lt;/em&gt; and stop reporting them in subsequent runs. It allows you to be interested in violations only in new and changed code.&lt;/p&gt;

&lt;p&gt;If you want to export the current list of errors and use it as the baseline, run &lt;em&gt;PHPStan&lt;/em&gt; with &lt;code&gt;--generate-baseline&lt;/code&gt; option&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/phpstan analyse &lt;span class="nt"&gt;--memory-limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;25 &lt;span class="nt"&gt;--generate-base&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: We dropped the path option from the example in &lt;a href="https://outline.robustastudio.com/doc/laravel-static-code-analysis-with-phpstan-oxyQT0wo3v/edit#h-installation" rel="noopener noreferrer"&gt;installation&lt;/a&gt; as it is now being set in the config file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It will generate the list of errors with the number of occurrences per file and saves it in &lt;code&gt;phpstan-baseline.neon&lt;/code&gt;. Finally we add the baseline file to our &lt;code&gt;includes&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;includes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vendor/nunomaduro/larastan/extension.neon&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;phpstan-baseline.neon&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding &lt;em&gt;PHPStan&lt;/em&gt; to Your CI/CD
&lt;/h3&gt;

&lt;p&gt;Adding &lt;em&gt;PHPStan&lt;/em&gt; to the CI/CD pipeline and running it regularly on merge requests and main branches will increase your code quality. In addition to helping in code review.&lt;/p&gt;

&lt;p&gt;Embed this snippet in your &lt;code&gt;gitlab-ci.yml&lt;/code&gt; file and a code quality report will be generated for any merge request, changes to develop or master branches in addition to release and hotfix branches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;staticanalysis -&lt;/span&gt; 

&lt;span class="na"&gt;phpstan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staticanalysis&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer require nunomaduro/larastan:1.0.2 --dev --no-plugins --no-interaction --no-scripts --prefer-dist --ignore-platform-reqs&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vendor/bin/phpstan analyse --no-progress --error-format gitlab &amp;gt; phpstan.json&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${CI_COMMIT_REF_SLUG}-composer-larastan&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vendor/&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;codequality&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;phpstan.json&lt;/span&gt;
  &lt;span class="na"&gt;allow_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;php-cs-fixer&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;php-cs-fixer&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;merge_requests&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/^release\/[0-9]+.[0-9]+.[0-9]$/&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/^hotfix\/[0-9]+.[0-9]+.[0-9]$/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Limitations of Static Analysis
&lt;/h3&gt;

&lt;p&gt;Static analysis is not a substitute for testing, they are different tools targeting different domains in the development lifecycle, and it has some limitation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No Understanding of Developer Intent
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;  &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculateArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$width&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above function, a static code analysis tool might detect that the returned value does not match the defined type  but it cannot determine that the function is semantically wrong!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some rules are subjective depending on the context.&lt;/li&gt;
&lt;li&gt;False Positives and False Negatives.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Helpful Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nunomaduro/larastan/blob/master/docs/rules.md#NoUnnecessaryCollectionCall" rel="noopener noreferrer"&gt;Laravel-specific rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/nunomaduro/larastan/blob/master/docs/errors-to-ignore.md" rel="noopener noreferrer"&gt;Errors to ignore&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;a href="https://phpstan.org/writing-php-code/phpdocs-basics" rel="noopener noreferrer"&gt;PHPDocs&lt;/a&gt;&lt;/em&gt;&lt;a href="https://phpstan.org/writing-php-code/phpdocs-basics" rel="noopener noreferrer"&gt; usage with &lt;/a&gt;&lt;em&gt;&lt;a href="https://phpstan.org/writing-php-code/phpdocs-basics" rel="noopener noreferrer"&gt;PHPStan&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/analysis-tools-dev" rel="noopener noreferrer"&gt;List of analysis tools for different languages&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>codequality</category>
      <category>tutorial</category>
      <category>php</category>
    </item>
  </channel>
</rss>
