<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Muhamad Hassan's Blog]]></title><description><![CDATA[Muhamad Hassan's Blog]]></description><link>https://muhamadhhassan.me</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1652139373285/QPBYkgMFH.png</url><title>Muhamad Hassan&apos;s Blog</title><link>https://muhamadhhassan.me</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 04:10:15 GMT</lastBuildDate><atom:link href="https://muhamadhhassan.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Partial Password Authentication]]></title><description><![CDATA[Recently, I switched to another bank, and after setting up the online banking credentials and trying to log in for the first time, I found a form similar to this one.


The system requests characters ]]></description><link>https://muhamadhhassan.me/partial-password-authentication</link><guid isPermaLink="true">https://muhamadhhassan.me/partial-password-authentication</guid><category><![CDATA[Security]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Mon, 13 Apr 2026 21:53:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/62769181317fc95a74ca841c/ce02a235-7d85-47af-aabc-542388d1db99.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I switched to another bank, and after setting up the online banking credentials and trying to log in for the first time, I found a form similar to this one.</p>
<img src="https://cdn.hashnode.com/uploads/covers/62769181317fc95a74ca841c/33321948-d0fa-44fe-a533-d87132d62a82.jpg" alt="" style="display:block;margin:0 auto" />

<p>The system requests characters in random positions each time I log in, which is quite interesting. Passwords are supposed to be stored as salted hashes, and with that, only the full password can be verified. So, what is happening here?</p>
<h1>Advantages</h1>
<p>Partial password authentication was adopted mainly in response to a combination of security threats and regulatory pressure, primarily in the U.S. and Europe during the early-to-mid 2000s.</p>
<h2>Keystroke Logging Malware</h2>
<p>Keystroke Logging Malware was a major catalyst due to the rise of keyloggers that recorded every keystroke. If a user entered their full password, attackers could capture it completely. Partial password entry countered this by only requesting certain characters, so even if a keylogger captured them, it wouldn't have the full password, and the next login would require different positions.</p>
<h2>Shoulder Surfing Protection</h2>
<p>Shoulder surfing protection functions similarly. Observers or cameras only capture a few characters per session, requiring multiple observations to track the requested positions each time.</p>
<h2>Phishing Mitigation</h2>
<p>Phishing mitigation is subtle but effective. If a fake site asks for your full password, it gains everything. However, if the real bank only requests partial characters, a phishing site must either ask for the full password, which should alert users, or request a few characters, limiting what they capture. It's not foolproof, but it increases security.</p>
<h2>Backend Implementation</h2>
<p>With standard password authentication, you store a salted hash (e.g., <em>bcrypt</em>) and compare. But hashing is a one-way, all-or-nothing operation — you can't verify the 3rd character of a password from a <em>bcrypt</em> hash. So partial password verification requires a fundamentally different storage and verification strategy.</p>
<div>
<div>💡</div>
<div>The trade off comes down to how much you trust your infrastructure vs. how much you trust your cryptography.</div>
</div>

<h3>1. Encrypted Plaintext Storage</h3>
<p>The most straightforward approach. You store the password encrypted (not hashed) using a symmetric key (e.g., AES-256), managed via an <a href="https://www.fortinet.com/resources/cyberglossary/hardware-security-module#:~:text=A%20hardware%20security%20module%20(HSM,an%20organization's%20digital%20security%20keys.">HSM</a> or a secrets manager.</p>
<img src="https://cdn.hashnode.com/uploads/covers/62769181317fc95a74ca841c/74b4991b-96d8-48c7-9de9-c0640a8895a3.svg" alt="" style="display:block;margin:0 auto" />

<p><strong>Verification flow:</strong></p>
<ol>
<li><p>Server generates a random set of character positions (e.g., positions 2, 5, 8).</p>
</li>
<li><p>User submits those characters.</p>
</li>
<li><p>Server decrypts the stored password, extracts the characters at those positions, and compares.</p>
</li>
<li><p>Plaintext is discarded from memory immediately.</p>
</li>
</ol>
<p><strong>Tradeoffs:</strong></p>
<p>Simple to implement, but the password is technically recoverable. If the encryption key is compromised, all passwords are exposed. This is why the key <em>must</em> live in an HSM with strict access controls. Many UK banks use this model.</p>
<h3>2. Store Individual Character Hashes</h3>
<p>You hash each character (or each character + its position) independently and store them all.</p>
<p>For a password <code>s3cur3</code>, you'd store something like:</p>
<pre><code class="language-plaintext">position_0: hash("s" + salt + "0")
position_1: hash("3" + salt + "1")
position_2: hash("c" + salt + "2")
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/62769181317fc95a74ca841c/a7fe42bd-775f-4eb3-9c3c-f358997ed1df.svg" alt="" style="display:block;margin:0 auto" />

<p><strong>Verification flow:</strong></p>
<ol>
<li><p>Server picks random positions, sends them to the client.</p>
</li>
<li><p>User submits the characters.</p>
</li>
<li><p>Server hashes each submitted character with the corresponding positional salt and compares.</p>
</li>
</ol>
<p><strong>Tradeoffs:</strong></p>
<p>No reversible encryption is needed. However, each character hash has a small keyspace, making brute-force attacks easy unless a costly hash function (like high-cost <em>bcrypt</em> or <em>Argon2</em>) is used per character. Even then, attackers with the database can crack positions offline with some effort. Using an <strong>HSM-held</strong> pepper can make offline attacks infeasible without it.</p>
<div>
<div>❕</div>
<div>With a full-password hash, the password's entropy provides strong defense. Even fast hashes are tough to brute-force against a 40+ bit entropy password. However, hashing individual characters reduces the keyspace to about 95 values. An attacker can quickly try all 95 options for a position with a fast hash like <em>SHA-256</em>. Thus, the hash function's slowness becomes crucial. Each attempt should be costly enough (using high <em>bcrypt </em>cost or <em>Argon2 </em>memory hardness) to make iterating through 95 candidates significantly expensive, ideally taking tens of seconds per position.</div>
</div>

<h3>3. Shamir's Secret Sharing / Threshold Schemes</h3>
<p>A more cryptographically elegant approach. You treat the password (or a key derived from it) as a secret and split it into shares using a threshold scheme.</p>
<p><strong>Setup:</strong></p>
<ol>
<li><p>User registers with full password.</p>
</li>
<li><p>Server derives a secret from the password and splits it into <em>n</em> shares (one per character position) using a (k, n) threshold scheme, where <em>k</em> is the number of characters you'll challenge.</p>
</li>
<li><p>Shares are stored server-side.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/62769181317fc95a74ca841c/b2bf4030-121d-42d5-b3d6-18a2e658bbd7.svg" alt="" style="display:block;margin:0 auto" />

<p><strong>Verification flow:</strong></p>
<ol>
<li><p>Server challenges the user for <em>k</em> positions.</p>
</li>
<li><p>Each correct character allows reconstruction of the corresponding share.</p>
</li>
<li><p>If <em>k</em> valid shares are provided, the secret is reconstructed and verified against a stored hash of the secret.</p>
</li>
</ol>
<p><strong>Tradeoffs:</strong></p>
<p>Mathematically strong — fewer than <em>k</em> correct characters reveal zero information about the secret. But it's complex to implement correctly, and key management during registration is critical.</p>
<h3>4. Pre-computed Challenge-Response Sets</h3>
<p>At registration, you pre-generate all (or many) possible challenge combinations and store a hash for each.</p>
<p>For example, if you always ask for 3 of 10 characters, there are C(10,3) = 120 combinations. For each combination, you concatenate those characters and store a salted hash.</p>
<img src="https://cdn.hashnode.com/uploads/covers/62769181317fc95a74ca841c/326fcd7d-40fa-4a2d-8202-fa3de56475d0.svg" alt="" style="display:block;margin:0 auto" />

<p><strong>Verification flow:</strong></p>
<ol>
<li><p>Server picks a combination, looks up the corresponding hash.</p>
</li>
<li><p>User submits the characters.</p>
</li>
<li><p>Server hashes the submission and compares.</p>
</li>
</ol>
<p><strong>Tradeoffs:</strong></p>
<p>You get proper hashing (<em>bcrypt</em>/<em>Argon2</em>) with no reversibility. But storage grows combinatorially. For 3 of 10, 120 hashes is manageable. For 4 of 20, it's C(20,4) = 4,845 — still feasible but heavier. Each hash needs its own salt, and password changes require regenerating the entire set. This is arguably the best balance of security and functionality for moderate password lengths.</p>
<h2>Is it Still Relevant?</h2>
<p>Honest answer: partial password authentication is a legacy technique that's being actively phased out. It was already niche (primarily UK banks and a few European financial institutions), and the industry has moved decisively past it.</p>
<h3><strong>Why it's dying out</strong></h3>
<p>The fundamental problem is that partial passwords solve a narrow threat (keyloggers capturing the full password in one session) while introducing significant backend complexity and weaker security properties compared to modern alternatives. Every design we discussed requires either storing passwords reversibly, dealing with tiny per-character keyspaces, or managing combinatorial storage — all of which are worse trade-offs than what's now available.</p>
<h3><strong>What replaced it</strong></h3>
<p>The shift is toward eliminating shared secrets entirely. Passwords are responsible for 80% of data breaches, and <a href="https://securityboulevard.com/2026/04/the-complete-guide-to-passwordless-authentication-in-2026-how-it-works-why-it-matters-and-how-to-implement-it/">passwordless authentication</a> removes that attack surface. Here's what the landscape looks like now:</p>
<p><strong>Passkeys (FIDO2/WebAuthn)</strong></p>
<p>The clear winner. They use asymmetric cryptography — a private key stays on the user's device, a public key sits on the server. There's nothing to phish, nothing stored server-side that's useful to an attacker, and nothing for the user to remember. As of Q1 2026, over 340 million banking customers worldwide authenticate using passkeys or other <a href="https://fidoalliance.org/specifications/">FIDO2-compliant</a> methods, with adoption accelerating 180% year-over-year. Major banks have gone all-in: HSBC launched passkey authentication across 14 markets simultaneously, achieving 41 million passkey users — a 60% adoption rate in just six months. Nordea became the first bank to fully deprecate password authentication, and as of January 2026, new customers can only set up passkey authentication.</p>
<p><strong>Regulatory pressure is making this mandatory, not optional.</strong></p>
<p>The UAE Central Bank issued a directive requiring all financial institutions to eliminate SMS and email OTPs by March 2026. NIST's SP 800-63-4 now requires that multi-factor authentication must offer a phishing-resistant option, and <a href="https://pages.nist.gov/800-63-3-Implementation-Resources/63B/AAL/">AAL3</a> requires hardware-backed non-exportable private keys. India, the Philippines, and the EU all have similar deadlines landing in 2026.</p>
<p><strong>Device-bound biometrics</strong> (fingerprint, face recognition) serve as the local unlock for passkeys. The user taps their fingerprint to release the private key — no secret ever crosses the network. Microsoft found that passkey sign-ins take only 8 seconds on average, compared with 69 seconds for traditional password plus second factor.</p>
<p><strong>Adaptive/risk-based authentication</strong> layers on top, evaluating contextual signals like device, location, and behavior patterns to dynamically adjust requirements without adding user friction.</p>
<hr />
<p>Partial password authentication was a clever workaround when keyloggers were a major threat and stronger alternatives were unavailable. Each backend design balanced simplicity, cryptographic rigor, and infrastructure trust, but all shared a weakness: the server held something worth stealing. In 2026, passkeys have rendered this obsolete by eliminating shared secrets at the protocol level—nothing sensitive is stored server-side, nothing useful crosses the network, and nothing needs memorizing. With regulatory mandates enforcing phishing-resistant authentication and over 340 million banking customers using FIDO2/WebAuthn, partial passwords are now a historical curiosity. Today, the solution is passkeys—offering the cryptographic elegance that Design 3 aimed for, but delivered natively.</p>
]]></content:encoded></item><item><title><![CDATA[PHP Attributes and Metaprogramming]]></title><description><![CDATA[Introduction
Attributes were introduced in PHP 8 around four years ago. As outlined in the RFC, attributes provide a structured and syntactic way to add metadata to declarations such as classes, properties, functions, methods, parameters, and constan...]]></description><link>https://muhamadhhassan.me/php-attributes-and-metaprogramming</link><guid isPermaLink="true">https://muhamadhhassan.me/php-attributes-and-metaprogramming</guid><category><![CDATA[PHP]]></category><category><![CDATA[Metaprogramming ]]></category><category><![CDATA[aop]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Fri, 16 May 2025 22:07:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743530980683/ac875b78-de66-4f25-a652-f0dd395180b2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Attributes were introduced in PHP 8 around four years ago. As outlined in the <a target="_blank" href="https://wiki.php.net/rfc/attributes_v2"><strong>RFC</strong></a>, 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 <strong>DocBlocks'</strong> annotations<br />for <a target="_blank" href="https://www.doctrine-project.org/projects/doctrine-annotations/en/stable/index.html">this purpose</a>. The syntax of Attributes is as follows:</p>
<pre><code class="lang-php"> <span class="hljs-meta">&lt;?php</span>

<span class="hljs-comment">#[Attribute]</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExampleAttribute</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $message</span>) </span>{}
}

<span class="hljs-comment">#[ExampleAttribute('This is a custom attribute for a class')]</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span>
</span>{
    <span class="hljs-comment">#[ExampleAttribute('This is a custom attribute for a method')]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myMethod</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">echo</span> <span class="hljs-string">"Hello from myMethod!"</span>; }
}
</code></pre>
<p>But first, how are PHP attributes different from decorators in Python? Or, Java’s Aspect-oriented Programming (AOP) annotations?</p>
<h1 id="heading-metaprogramming">Metaprogramming</h1>
<p>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.</p>
<h2 id="heading-decorator">Decorator</h2>
<p>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).</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This is different from the <a target="_self" href="https://refactoring.guru/design-patterns/decorator">stackable decorator classes</a> implementation of the decorator pattern.</div>
</div>

<p>The following is a simple example of a logging decorator in Python.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">log_function_call</span>(<span class="hljs-params">func</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>(<span class="hljs-params">*args, **kwargs</span>):</span>
        print(<span class="hljs-string">f"Calling function: <span class="hljs-subst">{func.__name__}</span>"</span>)
        result = func(*args, **kwargs)
        print(<span class="hljs-string">f"Function <span class="hljs-subst">{func.__name__}</span> returned <span class="hljs-subst">{result}</span>"</span>)
        <span class="hljs-keyword">return</span> result
    <span class="hljs-keyword">return</span> wrapper

<span class="hljs-meta">@log_function_call</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">a, b</span>):</span>
    <span class="hljs-keyword">return</span> a + b

<span class="hljs-comment"># Usage</span>
add(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>)
</code></pre>
<ul>
<li><p><code>log_function_call</code> is a <strong>decorator function</strong>.</p>
</li>
<li><p><code>@log_function_call</code> applies that decorator to the <code>add</code> function.</p>
</li>
<li><p><code>wrapper</code> is a nested function that wraps the original function, adding extra behavior before and after it runs.</p>
</li>
</ul>
<p>The output of this code will be:</p>
<pre><code class="lang-bash">Calling <span class="hljs-keyword">function</span>: add
Function add returned 7
</code></pre>
<h2 id="heading-aspect-oriented-programming">Aspect-Oriented Programming</h2>
<p>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.</p>
<p>Let’s take another logging example but this time implemented in AOP to explain its core concept:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.demo.aspect;

<span class="hljs-keyword">import</span> org.aspectj.lang.JoinPoint;
<span class="hljs-keyword">import</span> org.aspectj.lang.annotation.*;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;

<span class="hljs-meta">@Aspect</span>
<span class="hljs-meta">@Component</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoggingAspect</span> </span>{

    <span class="hljs-meta">@Before("execution(* com.example.demo.service.*.*(..))")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">logBefore</span><span class="hljs-params">(JoinPoint joinPoint)</span> </span>{
        System.out.println(<span class="hljs-string">"[LOG] Method called: "</span> + joinPoint.getSignature().toShortString());
    }
}
</code></pre>
<p>The code defines a <strong>cross-cutting concern</strong> — specifically, <strong>logging</strong> — and <strong>separates</strong> it from the main business logic of the application (like the <code>service</code> classes).<br />Instead of adding <code>System.out.println</code> statements inside every service method, <strong>you modularized</strong> this behavior into a <strong>separate aspect</strong>: <code>LoggingAspect</code>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Element</td><td>Explanation</td></tr>
</thead>
<tbody>
<tr>
<td><code>@Aspect</code></td><td>Declares this class as an <strong>aspect</strong> (a modular unit of a cross-cutting concern).</td></tr>
<tr>
<td><code>@Component</code></td><td>Tells Spring to manage this class as a <strong>bean</strong>.</td></tr>
<tr>
<td><code>@Before(...)</code></td><td>A <strong>pointcut</strong> and <strong>advice</strong>: it says "Before any method in <code>com.example.demo.service.*</code> package is called, run <code>logBefore()</code>."</td></tr>
<tr>
<td><code>JoinPoint</code></td><td>Gives details about the method being intercepted (like its name).</td></tr>
<tr>
<td><code>logBefore()</code></td><td>This is the <strong>advice method</strong> where the logging action happens.</td></tr>
</tbody>
</table>
</div><p>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.</p>
<h1 id="heading-reflection-api">Reflection API</h1>
<p>Both the new first-class citizen attributes and the dockblocks implementation depend on the reflection API for inspecting the attributes at runtime. <a target="_blank" href="https://www.php.net/manual/en/intro.reflection.php">Reflection AP</a> 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.</p>
<p>If you are not familiar with it, here is a simple example where the properties of the <code>User</code> class can be accessed programmatically regardless of their access modifier:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $name,
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> $age,
        <span class="hljs-keyword">protected</span> <span class="hljs-keyword">string</span> $email
    </span>) </span>{}
}

<span class="hljs-comment">// Use ReflectionClass to inspect the User class</span>
$reflection = <span class="hljs-keyword">new</span> ReflectionClass(<span class="hljs-string">'User'</span>);

<span class="hljs-comment">// Get the public, protected, and private properties </span>
$properties = $reflection-&gt;getProperties();
</code></pre>
<h1 id="heading-attributes">Attributes</h1>
<h2 id="heading-syntax">Syntax</h2>
<p>Attributes are classes annotated with the base <code>#[Attribute]</code>:</p>
<pre><code class="lang-php"><span class="hljs-comment">#[Attribute(Attribute::TARGET_METHOD)]</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Log</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $message = <span class="hljs-string">'Method called'</span></span>) </span>{}
}
</code></pre>
<p>Attributes are configured by passing a <a target="_blank" href="https://en.wikipedia.org/wiki/Mask_\(computing\)#:~:text=In%20computer%20science%2C%20a%20mask,in%20a%20single%20bitwise%20operation.">bitmask</a> as its first argument, It can be used to restrict the types that an attribute can be applied to. In the above example, the <code>Log</code> attribute can only be applied to methods. The available types are:</p>
<ul>
<li><p><code>TARGET_CLASS</code></p>
</li>
<li><p><code>TARGET_FUNCTION</code></p>
</li>
<li><p><code>TARGET_METHOD</code></p>
</li>
<li><p><code>TARGET_PROPERTY</code></p>
</li>
<li><p><code>TARGET_CLASS_CONSTANT</code></p>
</li>
<li><p><code>TARGET_PARAMETER</code></p>
</li>
<li><p><code>TARGET_ALL</code></p>
</li>
</ul>
<p>By default, an attribute can be used once per declaration. to change this behavior, specify it in the bitmask of the <code>#[Attribute]</code> declaration using the <code>Attribute::IS_REPEATABLE</code> flag:</p>
<pre><code class="lang-php"><span class="hljs-comment">#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Log</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $message = <span class="hljs-string">'Method called'</span></span>) </span>{}
}
</code></pre>
<h2 id="heading-usage">Usage</h2>
<ol>
<li><p>Create a class that uses the <code>Log</code> attribute:</p>
<pre><code class="lang-php"> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AccountService</span>
 </span>{
     <span class="hljs-comment">#[Log("Creating a new account")]</span>
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createAccount</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $user</span>)
     </span>{
         <span class="hljs-keyword">echo</span> <span class="hljs-string">"Account created for <span class="hljs-subst">$user</span>"</span> . PHP_EOL;
     }

     <span class="hljs-comment">#[Log("Deleting an account")]</span>
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteAccount</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $user</span>)
     </span>{
         <span class="hljs-keyword">echo</span> <span class="hljs-string">"Account deleted for <span class="hljs-subst">$user</span>"</span> . PHP_EOL;
     }

     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">helperFunction</span>(<span class="hljs-params"></span>)
     </span>{
         <span class="hljs-keyword">echo</span> <span class="hljs-string">"This won't be logged."</span> . PHP_EOL;
     }
 }
</code></pre>
</li>
<li><p>Create a logger proxy function to call the methods with logging:</p>
<pre><code class="lang-php"> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">callWithLogging</span>(<span class="hljs-params"><span class="hljs-keyword">object</span> $object, <span class="hljs-keyword">string</span> $method, <span class="hljs-keyword">array</span> $args = []</span>)
 </span>{
     $refMethod = <span class="hljs-keyword">new</span> ReflectionMethod($object, $method);
     $attributes = $refMethod-&gt;getAttributes(Log::class);

     <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">empty</span>($attributes)) {
         <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> Log $log */</span>
         $log = $attributes[<span class="hljs-number">0</span>]-&gt;newInstance();
         <span class="hljs-keyword">echo</span> <span class="hljs-string">"[LOG] <span class="hljs-subst">{$log-&gt;message}</span>"</span> . PHP_EOL;
     }

     <span class="hljs-keyword">return</span> $refMethod-&gt;invokeArgs($object, $args);
 }
</code></pre>
</li>
</ol>
<h2 id="heading-client-code">Client Code</h2>
<pre><code class="lang-php">$service = <span class="hljs-keyword">new</span> AccountService();

callWithLogging($service, <span class="hljs-string">'createAccount'</span>, [<span class="hljs-string">'alice'</span>]);
callWithLogging($service, <span class="hljs-string">'deleteAccount'</span>, [<span class="hljs-string">'bob'</span>]);
callWithLogging($service, <span class="hljs-string">'helperFunction'</span>); <span class="hljs-comment">// No log, no attribute</span>
</code></pre>
<p>The output of this code will be:</p>
<pre><code class="lang-bash">[LOG] Creating a new account
Account created <span class="hljs-keyword">for</span> alice
[LOG] Deleting an account
Account deleted <span class="hljs-keyword">for</span> bob
This won<span class="hljs-string">'t be logged.</span>
</code></pre>
<h1 id="heading-real-life-example">Real-Life Example</h1>
<p>Let’s take a real-life example of attributes. <strong>Laravel 11</strong> introduced <a target="_blank" href="https://laravel.com/docs/12.x/container#contextual-attributes">contextual attributes</a> and for our example we will be using the <a target="_blank" href="https://github.com/laravel/framework/blob/12.x/src/Illuminate/Container/Attributes/Config.php"><code>Config</code></a> attribute. The <code>#[Config(...)]</code> attribute allows you to annotate a constructor or method parameter, so that <strong>Laravel’s</strong> service container can <strong>resolve and inject</strong> the corresponding config value at runtime:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Container</span>\<span class="hljs-title">Attributes</span>\<span class="hljs-title">Config</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PhotoController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">#[Config(<span class="hljs-params"><span class="hljs-string">'app.timezone'</span></span>)] <span class="hljs-keyword">protected</span> <span class="hljs-keyword">string</span> $timezone</span>)
    </span>{
        <span class="hljs-comment">// ...</span>
    }
}
</code></pre>
<h2 id="heading-config-attribute-definition">Config Attribute Definition</h2>
<p>The <code>Config</code> attribute definition goes as follows:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Container</span>\<span class="hljs-title">Attributes</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Attribute</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">Container</span>\<span class="hljs-title">Container</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">Container</span>\<span class="hljs-title">ContextualAttribute</span>;

<span class="hljs-comment">#[Attribute(Attribute::TARGET_PARAMETER)]</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ContextualAttribute</span>
</span>{
    <span class="hljs-comment">/**
     * Create a new class instance.
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $key, <span class="hljs-keyword">public</span> mixed $default = <span class="hljs-literal">null</span></span>) </span>{}

    <span class="hljs-comment">/**
     * Resolve the configuration value.
     *
     * <span class="hljs-doctag">@param</span>  self  $attribute
     * <span class="hljs-doctag">@param</span>  \Illuminate\Contracts\Container\Container  $container
     * <span class="hljs-doctag">@return</span> mixed
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">resolve</span>(<span class="hljs-params"><span class="hljs-built_in">self</span> $attribute, Container $container</span>)
    </span>{
        <span class="hljs-keyword">return</span> $container-&gt;make(<span class="hljs-string">'config'</span>)-&gt;get($attribute-&gt;key, $attribute-&gt;default);
    }
}
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">The <code>ContextualAttribute</code> is an empty interface in Laravel 12.x.</div>
</div>

<h2 id="heading-resolving-config-attribute">Resolving <code>Config</code> Attribute</h2>
<p>Contextual attributes resolving start in <code>Illuminate\Container\Container::build($concrete)</code>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Some of the code in <code>Illuminate\Container\Container</code> will be omitted if it’s not related to the flow of binding a constructor’s config parameter. The full class can be found <a target="_self" href="https://github.com/laravel/framework/blob/12.x/src/Illuminate/Container/Container.php">here</a></div>
</div>

<p>First, we create a <code>ReflectionClass</code> to inspect the <code>$concrete</code> class:</p>
<pre><code class="lang-php"><span class="hljs-keyword">try</span> {
    $reflector = <span class="hljs-keyword">new</span> ReflectionClass($concrete);
} <span class="hljs-keyword">catch</span> (ReflectionException $e) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> BindingResolutionException(<span class="hljs-string">"Target class [<span class="hljs-subst">$concrete</span>] does not exist."</span>, <span class="hljs-number">0</span>, $e);
}
</code></pre>
<p>The next step is to get the <code>$concrete</code> constructor method:</p>
<pre><code class="lang-php"><span class="hljs-comment">// returns a ReflectionMethod instance</span>
$constructor = $reflector-&gt;getConstructor();
</code></pre>
<p>Then, if the class does not have a constructor, the service container returns a new instance of <code>$concrete</code>. But, that is not the case in our <code>PhotoController</code>, so that, it gets a list of the <code>$constructor</code> method parameters:</p>
<pre><code class="lang-php"><span class="hljs-comment">// returns an array of ReflectionParameter[]</span>
$dependencies = $constructor-&gt;getParameters();

<span class="hljs-keyword">try</span> {
    $instances = <span class="hljs-keyword">$this</span>-&gt;resolveDependencies($dependencies);
} <span class="hljs-keyword">catch</span> (BindingResolutionException $e) {
    array_pop(<span class="hljs-keyword">$this</span>-&gt;buildStack);

    <span class="hljs-keyword">throw</span> $e;
}
</code></pre>
<p>The method <code>Container::resolveDependencies($dependencies)</code> loops over the <code>$dependencies</code> array, and returns an array of the constructor parameters. One execution flow is when the <code>$dependency</code> has a contextual parameter:</p>
<pre><code class="lang-php"><span class="hljs-keyword">foreach</span> ($dependencies <span class="hljs-keyword">as</span> $dependency) {
    $result = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">if</span> (! is_null($attribute = Util::getContextualAttributeFromDependency($dependency))) {
        $result = <span class="hljs-keyword">$this</span>-&gt;resolveFromAttribute($attribute);
    }
}
</code></pre>
<p>Finally, in <code>Container::resolveFromAttribute(ReflectionAttribute $attribute)</code>, There are two scenarios for resolving the value of the attribute:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">resolveFromAttribute</span>(<span class="hljs-params">ReflectionAttribute $attribute</span>)
</span>{
    $handler = <span class="hljs-keyword">$this</span>-&gt;contextualAttributes[$attribute-&gt;getName()] ?? <span class="hljs-literal">null</span>;

    $instance = $attribute-&gt;newInstance();

    <span class="hljs-keyword">if</span> (is_null($handler) &amp;&amp; method_exists($instance, <span class="hljs-string">'resolve'</span>)) {
        $handler = $instance-&gt;resolve(...);
    }

    <span class="hljs-keyword">if</span> (is_null($handler)) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> BindingResolutionException(<span class="hljs-string">"Contextual binding attribute [<span class="hljs-subst">{$attribute-&gt;getName()}</span>] has no registered handler."</span>);
    }

    <span class="hljs-keyword">return</span> $handler($instance, <span class="hljs-keyword">$this</span>);
}
</code></pre>
<ol>
<li><p>If there is a custom handler function (or callable) for the <code>$attribute</code> name defined in the <code>App\Providers\AppServiceProvider::boot()</code>:</p>
<pre><code class="lang-php"> <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Container</span>\<span class="hljs-title">Attributes</span>\<span class="hljs-title">Config</span>;

 <span class="hljs-comment">/**
  * Bootstrap any application services.
  */</span>
 <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boot</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
 </span>{
     <span class="hljs-keyword">$this</span>-&gt;app-&gt;contextualAttributes[Config::class] = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"></span>) =&gt; '<span class="hljs-title">Africa</span>/<span class="hljs-title">Cairo</span>'</span>;
 }
</code></pre>
<p> The callable <code>fn() =&gt; 'Africa/Cairo'</code> is invoked.</p>
</li>
<li><p>If the <code>$handler</code> is <code>null</code>, and the <code>Illuminate\Container\Attributes\Config::resolve()</code> method exists in the attribute definition, it will be invoked.</p>
</li>
</ol>
<h1 id="heading-attributes-misuse">Attributes Misuse</h1>
<p>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.</p>
<p>To minimize the negative side effects of attributes, they should not be used beyond their described purpose as metadata providers. Misuse examples includes:</p>
<ul>
<li><p><strong>Embedding logic</strong> or <strong>side effects</strong> within attributes</p>
<ul>
<li>For example, having an attribute that <em>modifies global state</em> or <em>performs operations</em> at runtime just by being present.</li>
</ul>
</li>
<li><p><strong>Replacing business logic</strong> with attribute logic</p>
<ul>
<li>E.g., putting application logic or decisions into attribute classes, rather than keeping that logic in controllers or services.</li>
</ul>
</li>
<li><p><strong>Overloading attribute meaning</strong></p>
<ul>
<li>When attributes are overloaded with too many responsibilities or become a place to "hide" logic, it becomes harder to understand or maintain code.</li>
</ul>
</li>
<li><p><strong>Using attributes for code that should remain in configuration files</strong></p>
<ul>
<li>E.g., trying to implement environment configuration through attributes.</li>
</ul>
</li>
</ul>
<p>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 <a target="_blank" href="https://www.php.net/manual/en/reserved.attributes.php">core language features</a> like <code>#[Deprecated]</code>, <code>#[Override]</code>, and <code>#[Attribute]</code>, to <a target="_blank" href="https://docs.phpunit.de/en/10.5/attributes.html">PHPUnit-specific</a> attributes such as <code>#[Test]</code>, <code>#[Before]</code>, <code>#[After]</code>, and <code>#[Depends]</code>, 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.</p>
]]></content:encoded></item><item><title><![CDATA[PHP Generics in Laravel 11]]></title><description><![CDATA[If you are a web applications builder with Laravel and happens to use PHPStan for static code analysis, you will start seeing new errors when you upgrade to Laravel 11.x.
In a fresh Laravel install with PHPStan, the first time running ./vendor/bin/ph...]]></description><link>https://muhamadhhassan.me/php-generics-in-laravel-11</link><guid isPermaLink="true">https://muhamadhhassan.me/php-generics-in-laravel-11</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><category><![CDATA[tools]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Tue, 22 Oct 2024 23:16:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729445079737/3313a720-b1fb-4535-b8a4-5fd562dcef65.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you are a web applications builder with Laravel and happens to use <a target="_blank" href="https://muhamadhhassan.me/laravel-static-code-analysis-with-phpstan">PHPStan</a> for static code analysis, you will start seeing new errors when you upgrade to <strong>Laravel</strong> <strong>11.x</strong>.</p>
<p>In a fresh Laravel install with <strong>PHPStan</strong>, the first time running <code>./vendor/bin/phpstan</code> the following error get thrown:</p>
<pre><code class="lang-powershell"> ------ -----------------------------------------------------------------------------------
  Line   app\Models\User.php
 ------ -----------------------------------------------------------------------------------
  <span class="hljs-number">13</span>     <span class="hljs-class"><span class="hljs-keyword">Class</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">User</span> <span class="hljs-title">uses</span> <span class="hljs-title">generic</span> <span class="hljs-title">trait</span>
         <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Factories</span>\<span class="hljs-title">HasFactory</span> <span class="hljs-title">but</span> <span class="hljs-title">does</span> <span class="hljs-title">not</span> <span class="hljs-title">specify</span> <span class="hljs-title">its</span> <span class="hljs-title">types</span>:
         <span class="hljs-title">TFactory</span>
 ------ -----------------------------------------------------------------------------------</span>
</code></pre>
<p>So what was changed? In Laravel 11, the <code>HasFactory</code> trait now has a <strong>PHPDoc</strong> with the <code>@template</code> 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.</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */</span>
<span class="hljs-keyword">trait</span> HasFactory
{
    ...
}
</code></pre>
<p>Although it is not recommended, this category of errors can be ignored by simply adding these lines of code to your <code>phpstan.neon</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">parameters:</span>
    <span class="hljs-attr">ignoreErrors:</span>
        <span class="hljs-bullet">-</span>
            <span class="hljs-attr">identifier:</span> <span class="hljs-string">missingType.generics</span>
</code></pre>
<p>But, generics are not that hard to understand so let’s get started!</p>
<h2 id="heading-what-are-generics">What are Generics?</h2>
<p>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 <code>mixed</code> or <code>object</code>.</p>
<p>Take the <code>Illuminate\Database\Concerns\BuildsQueries::first</code> method from <strong>Laravel</strong> 10, it can return an instance of <code>Model</code>, a general <code>object</code>, an instance of the class using it like <code>Illuminate\Database\Eloquent\Builder</code> or <code>null</code>.</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * Execute the query and get the first result.
 *
 * <span class="hljs-doctag">@param</span>  array|string  $columns
 * <span class="hljs-doctag">@return</span> \Illuminate\Database\Eloquent\Model|object|static|null
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">first</span>(<span class="hljs-params">$columns = [<span class="hljs-string">'*'</span>]</span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;take(<span class="hljs-number">1</span>)-&gt;get($columns)-&gt;first();
}
</code></pre>
<h2 id="heading-generics-syntax">Generics Syntax</h2>
<p>Generics are not supported in PHP as a <a target="_blank" href="https://stitcher.io/blog/generics-in-php-3">first-class citizen</a>, to have them we use the <strong>PHPDocs</strong> tags <code>@template</code>, <code>@template-covariant</code>, <code>@template-contravariant</code>, <code>@extends</code>, <code>@implements</code>, and <code>@use</code>.</p>
<p>The rules of the generic types are defined using <em>type parameters.</em> In <strong>PHPDocs</strong> we annotate them with the <code>@template</code> 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 <code>of</code> keyword. This is called <em>bounded type parameter.</em></p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>;

<span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TModel of \Illuminate\Database\Eloquent\Model
 *
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Builder</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BuilderContract</span>
</span>{
}
</code></pre>
<h2 id="heading-types-of-php-generics">Types of PHP Generics</h2>
<h3 id="heading-generic-function">Generic Function</h3>
<p>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.</p>
<p>Take the <code>Illuminate\Support\ValidatedInput::enum</code> method as an example:</p>
<ul>
<li><p>It defines a type parameter <code>TEnum</code>.</p>
</li>
<li><p>The <code>$enumClass</code> parameter is of the pseudo type <code>class-string</code> and bounded to the same type parameter <code>TEnum</code>.</p>
</li>
<li><p>The return type also can either be of <code>TEnum</code> or <code>null</code>.</p>
</li>
</ul>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TEnum
 *
 * <span class="hljs-doctag">@param</span> string $key
 * <span class="hljs-doctag">@param</span> class-string&lt;TEnum&gt; $enumClass
 * <span class="hljs-doctag">@return</span> TEnum|null
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">enum</span>(<span class="hljs-params">$key, $enumClass</span>)
</span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;isNotFilled($key) ||
        ! enum_exists($enumClass) ||
        ! method_exists($enumClass, <span class="hljs-string">'tryFrom'</span>)) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
    <span class="hljs-keyword">return</span> $enumClass::tryFrom(<span class="hljs-keyword">$this</span>-&gt;input($key));
}
</code></pre>
<p>If you then call <code>$request→validated()→enum(‘status‘, OrderStatus::class)</code>, <strong>PHPStan</strong> will know that you’re getting an <code>OrderStatus</code> object or null!</p>
<h3 id="heading-generic-class">Generic Class</h3>
<p>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.</p>
<p>A good example from <strong>Laravel</strong> source code would be the <code>Illuminate\Database\Eloquent\Builder</code> class:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>;
<span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TModel of \Illuminate\Database\Eloquent\Model
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Builder</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BuilderContract</span>
</span>{
    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span>  array  $attributes
     * <span class="hljs-doctag">@return</span> TModel
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">make</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $attributes = []</span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;newModelInstance($attributes);
    }
}
</code></pre>
<p>A type parameter <code>TModel</code> is defined and bounded to any sub-class of <code>Illuminate\Database\Eloquent\Model</code>. The same type parameter is used as a return type of the method <code>make</code>.</p>
<p>Another example would be if we have an <code>Order</code> model, which has a local scope to filter orders based on their status. The scope method should specify the <code>TModel</code> type</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@param</span>  Builder&lt;Order&gt;  $query
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scopeWithStatus</span>(<span class="hljs-params">Builder $query, OrderStatus $status</span>): <span class="hljs-title">void</span>
</span>{
    $query-&gt;whereStatus($status-&gt;value);
}
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">All the <strong>Eloquent </strong>relations classes in namespace <code>Illuminate\Database\Eloquent\Relations</code> like <code>BelongsTo</code> and <code>HasOne</code> are now generic.</div>
</div>

<h3 id="heading-generic-interface">Generic Interface</h3>
<p>Generic interfaces are not so different. The <code>Illuminate\Contracts\Support\Arrayable</code> is an example of a generic interface</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TKey of array-key
 * <span class="hljs-doctag">@template</span> TValue
 */</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Arrayable</span>
</span>{
    <span class="hljs-comment">/**
     * Get the instance as an array.
     *
     * <span class="hljs-doctag">@return</span> array&lt;TKey, TValue&gt;
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toArray</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>The interface defines two type parameters: <code>TKey</code> of type <code>array-key</code> (it can be <code>int</code> or <code>string</code>) and <code>TValue</code>. Theses two parameters are used to define the return type of the <code>toArray</code> function. Here is an example:</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@implements</span> Arrayable&lt;int, string&gt;
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Arrayable</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> $id;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $name;

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@return</span> array&lt;int, string&gt;
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toArray</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">return</span> [
            <span class="hljs-keyword">$this</span>-&gt;id =&gt; <span class="hljs-keyword">$this</span>-&gt;name,
        ];
    }
}
</code></pre>
<p>The user class implements the <code>Arrayable</code> interface and specify the <code>Tkey</code> type as an <code>int</code> and the <code>TValue</code> as a <code>string</code>.</p>
<h3 id="heading-generic-trait">Generic Trait</h3>
<p>We came across the <code>Illuminate\Database\Eloquent\Factories\HasFactory</code> trait in the error at the beginning of this post. Let’s have a closer look:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Factories</span>;

<span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */</span>
<span class="hljs-keyword">trait</span> HasFactory
{
    <span class="hljs-comment">/**
     * Create a new factory instance for the model.
     *
     * <span class="hljs-doctag">@return</span> TFactory|null
     */</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">newFactory</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">isset</span>(<span class="hljs-built_in">static</span>::$factory)) {
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">static</span>::$factory::new();
        }

        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
}
</code></pre>
<p><code>HasFactory</code> defines a type parameter <code>TFactory</code> bounded to the sub-classes of <code>Illuminate\Database\Eloquent\Factories\Factory</code>. So how can that error be fixed?</p>
<p>The <code>TFactory</code> type must be specified when the trait is being used. So, the <code>use</code> statement of the <code>HasFactory</code> trait needs to be annotated with the <strong>PHPDocs</strong> <code>@use</code>:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Database</span>\<span class="hljs-title">Factories</span>\<span class="hljs-title">UserFactory</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Foundation</span>\<span class="hljs-title">Auth</span>\<span class="hljs-title">User</span> <span class="hljs-title">as</span> <span class="hljs-title">Authenticatable</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Authenticatable</span>
</span>{
    <span class="hljs-comment">/** <span class="hljs-doctag">@use</span> HasFactory&lt;UserFactory&gt; */</span>
    <span class="hljs-keyword">use</span> <span class="hljs-title">HasFactory</span>;
}
</code></pre>
<h2 id="heading-preserving-genericness">Preserving Genericness</h2>
<p>When extending a class, implementing an interface, or using a trait it is possible to maintain the genericness in the sub-class.</p>
<p>Preserving the genericness is implemented by defining the same type parameters above the child class and passing it to <code>@extends</code>, <code>@implements</code> and <code>@use</code> tags.</p>
<p>We will use the <code>Illuminate\Database\Concerns\BuildsQueries</code> generic trait as an example,</p>
<p>it defines a type parameter <code>TValue</code>:</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TValue
 *
 */</span>
<span class="hljs-keyword">trait</span> BuildsQueries
{
    ...
}
</code></pre>
<p>The <code>Illuminate\Database\Eloquent\Builder</code> class uses this trait but keeps its genericness by passing the <code>TModel</code> parameter type to it. It is now left to the client code to specify the type of <code>TModel</code> and consequently <code>TValue</code> in the <code>BuildsQueries</code> trait.</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@template</span> TModel of \Illuminate\Database\Eloquent\Model
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Builder</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BuilderContract</span>
</span>{
    <span class="hljs-comment">/** <span class="hljs-doctag">@use</span> \Illuminate\Database\Concerns\BuildsQueries&lt;TModel&gt; */</span>
    <span class="hljs-keyword">use</span> <span class="hljs-title">BuildsQueries</span>, <span class="hljs-title">ForwardsCalls</span>, <span class="hljs-title">QueriesRelationships</span> {
        <span class="hljs-title">BuildsQueries</span>::<span class="hljs-title">sole</span> <span class="hljs-title">as</span> <span class="hljs-title">baseSole</span>;
    }
}
</code></pre>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>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 <strong>PHPStan</strong> allows developers to implement generics-like functionality in their code. By leveraging <strong>PHPDocs</strong>, 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.</p>
]]></content:encoded></item><item><title><![CDATA[Creating Refresh Tokens with Laravel Sanctum]]></title><description><![CDATA[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.
What is a Reference ...]]></description><link>https://muhamadhhassan.me/creating-refresh-tokens-with-laravel-sanctum</link><guid isPermaLink="true">https://muhamadhhassan.me/creating-refresh-tokens-with-laravel-sanctum</guid><category><![CDATA[Laravel]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Sat, 03 Jun 2023 10:29:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685736751399/caf56d4c-7f26-4052-a4b8-e6f33e8f828e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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.</p>
<h2 id="heading-what-is-a-reference-token">What is a Reference Token?</h2>
<p>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.</p>
<p>Sanctum uses the database as its storage, and if we take a look at the Sanctum <code>personal_access_tokens</code> 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.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
</span>{
    Schema::create(<span class="hljs-string">'personal_access_tokens'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
        $table-&gt;id();
        $table-&gt;morphs(<span class="hljs-string">'tokenable'</span>);
        $table-&gt;string(<span class="hljs-string">'name'</span>);
        $table-&gt;string(<span class="hljs-string">'token'</span>, <span class="hljs-number">64</span>)-&gt;unique();
        $table-&gt;text(<span class="hljs-string">'abilities'</span>)-&gt;nullable();
        $table-&gt;timestamp(<span class="hljs-string">'last_used_at'</span>)-&gt;nullable();
        $table-&gt;timestamp(<span class="hljs-string">'expires_at'</span>)-&gt;nullable();
        $table-&gt;timestamps();
    });
}
</code></pre>
<h2 id="heading-advantages-of-reference-tokens">Advantages of Reference Tokens</h2>
<ul>
<li><p>Reference tokens can be preferred in scenarios where the token payload is too large to be included directly in the token.</p>
</li>
<li><p>Since reference tokens do not include all the necessary data, the risk of data breaches is reduced.</p>
</li>
<li><p>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.</p>
</li>
<li><p>Being smaller in size compared to self-contained tokens, they can be transmitted and processed faster.</p>
</li>
</ul>
<h2 id="heading-why-refresh-tokens-are-needed">Why Refresh Tokens Are Needed?</h2>
<p>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.</p>
<p>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.</p>
<h2 id="heading-issuing-refresh-tokens-with-sanctum">Issuing Refresh Tokens with Sanctum</h2>
<h3 id="heading-1-configure-time-to-live-values">1. Configure Time-to-Live Values</h3>
<p>There is a difference in the time-to-live between access tokens and refresh tokens but Sanctum has only one configuration for expiration in <code>config/sanctum.php</code>. Let's start by adding another configuration for refresh tokens expiration named <code>rt_expiration</code>.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">return</span> [
    .
    .
    .
    <span class="hljs-string">'expiration'</span> =&gt; <span class="hljs-number">60</span>,              <span class="hljs-comment">// One hour</span>
    <span class="hljs-string">'rt_expiration'</span> =&gt; <span class="hljs-number">7</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span>,  <span class="hljs-comment">// 7 Days</span>
];
</code></pre>
<h3 id="heading-2-overriding-sanctum-service-provider">2. Overriding Sanctum Service Provider</h3>
<p>Although the new <code>rt_expiration</code> configuration to create the refresh tokens, <strong>Sanctum</strong> will always use the <code>expiration</code> value to check on the token validity. In <code>Laravel\Sanctum\SanctumServiceProvider</code>, the request guard is created using the default <code>expiration</code>:</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * Register the guard.
 *
 * <span class="hljs-doctag">@param</span>  \Illuminate\Contracts\Auth\Factory  $auth
 * <span class="hljs-doctag">@param</span>  array  $config
 * <span class="hljs-doctag">@return</span> RequestGuard
 */</span>
<span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createGuard</span>(<span class="hljs-params">$auth, $config</span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> RequestGuard(
        <span class="hljs-keyword">new</span> Guard($auth, config(<span class="hljs-string">'sanctum.expiration'</span>), $config[<span class="hljs-string">'provider'</span>]),
        request(),
        $auth-&gt;createUserProvider($config[<span class="hljs-string">'provider'</span>] ?? <span class="hljs-literal">null</span>)
    );
}
</code></pre>
<p>The TTL value should be selected based on the incoming request. First, let’s define a new configuration for the refresh token URL pattern:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">return</span> [
    <span class="hljs-string">'rt_url_pattern'</span> =&gt; env(<span class="hljs-string">'SANCTUM_RT_URL_PATTERN'</span>, <span class="hljs-string">'*/auth/refresh-token'</span>),
];
</code></pre>
<p>Then, create a new service provider:</p>
<pre><code class="lang-bash">php artisan make:provider SanctumServiceProvider
</code></pre>
<p>This provider will extend the package’s provider and it will have the new implementation of the <code>createGuard</code> method:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Providers</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Auth</span>\<span class="hljs-title">RequestGuard</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">Auth</span>\<span class="hljs-title">Factory</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Laravel</span>\<span class="hljs-title">Sanctum</span>\<span class="hljs-title">Guard</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SanctumServiceProvider</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">Laravel</span>\<span class="hljs-title">Sanctum</span>\<span class="hljs-title">SanctumServiceProvider</span>
</span>{
    <span class="hljs-comment">/**
     * Register the guard.
     *
     * <span class="hljs-doctag">@param</span>  Factory  $auth
     * <span class="hljs-doctag">@param</span>  array&lt;string, mixed&gt;  $config
     */</span>
    <span class="hljs-comment">#[\Override]</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createGuard</span>(<span class="hljs-params">$auth, $config</span>): <span class="hljs-title">RequestGuard</span>
    </span>{
        $expiration = request()-&gt;is(config(<span class="hljs-string">'sanctum.rt_url_pattern'</span>))
            ? config(<span class="hljs-string">'sanctum.rt_expiration'</span>)
            : config(<span class="hljs-string">'sanctum.expiration'</span>);

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> RequestGuard(
            <span class="hljs-keyword">new</span> Guard($auth, $expiration, $config[<span class="hljs-string">'provider'</span>]),
            request(),
            $auth-&gt;createUserProvider($config[<span class="hljs-string">'provider'</span>] ?? <span class="hljs-literal">null</span>)
        );
    }
}
</code></pre>
<p>The final step is to tell Laravel not to load the package’s service provider. In <code>composer.json</code>, update the the <code>extra</code> property as follows:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"extra"</span>: {
        <span class="hljs-attr">"laravel"</span>: {
            <span class="hljs-attr">"dont-discover"</span>: [
              <span class="hljs-string">"laravel/sanctum"</span>
            ]
        }
    }
}
</code></pre>
<h3 id="heading-3-define-token-abilities">3. Define Token Abilities</h3>
<p>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 <code>app\Enums\TokenAbility.php</code>.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Enums</span>;

enum TokenAbility: <span class="hljs-keyword">string</span>
{
    <span class="hljs-keyword">case</span> ISSUE_ACCESS_TOKEN = <span class="hljs-string">'issue-access-token'</span>;
    <span class="hljs-keyword">case</span> ACCESS_API = <span class="hljs-string">'access-api'</span>;
}
</code></pre>
<p>Now, when a user login two tokens will be issued.</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Request</span>;
<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Enums</span>\<span class="hljs-title">TokenAbility</span>;

Route::post(<span class="hljs-string">'/auth/login'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Request $request</span>) </span>{
    <span class="hljs-comment">// Credentials check should go here.</span>

    $accessToken = $user-&gt;createToken(<span class="hljs-string">'access_token'</span>, [TokenAbility::ACCESS_API-&gt;value], config(<span class="hljs-string">'sanctum.expiration'</span>));
    $refreshToken = $user-&gt;createToken(<span class="hljs-string">'refresh_token'</span>, [TokenAbility::ISSUE_ACCESS_TOKEN-&gt;value], config(<span class="hljs-string">'sanctum.rt_expiration'</span>))

    <span class="hljs-keyword">return</span> [
        <span class="hljs-string">'token'</span> =&gt; $accessToken-&gt;plainTextToken,
        <span class="hljs-string">'refresh_token'</span> =&gt; $refreshToken-&gt;plainTextToken,
    ];
});
</code></pre>
<p>To use the token abilities in protecting routes, we need to add <strong>Sanctum</strong> abilities middlewares. In Laravel 10.X and prior, the middlewares should be added to the <code>$middlewareAliases</code> property in <code>app/Http/Kernel.php</code> file:</p>
<pre><code class="lang-php"><span class="hljs-string">'abilities'</span> =&gt; \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,
<span class="hljs-string">'ability'</span> =&gt; \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,
</code></pre>
<p>Starting from <strong>Laravel 11.X</strong>, middlewares configuration is part of the application bootstrap file at <code>./bootstrap/app.php</code>:</p>
<pre><code class="lang-php"><span class="hljs-keyword">return</span> Application::configure(basePath: dirname(<span class="hljs-keyword">__DIR__</span>))
    -&gt;withRouting(
        web: <span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/../routes/web.php'</span>,
        api: <span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/../routes/api.php'</span>,
        commands: <span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/../routes/console.php'</span>,
        health: <span class="hljs-string">'/up'</span>,
    )
    -&gt;withMiddleware(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Middleware $middleware</span>) </span>{
        $middleware-&gt;alias([
            <span class="hljs-string">'abilities'</span> =&gt; \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,
            <span class="hljs-string">'ability'</span> =&gt; \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,
        ]);
    })
    -&gt;create();
</code></pre>
<h3 id="heading-4-assign-the-ability-middleware-to-routes">4. Assign the Ability Middleware to Routes</h3>
<p>Finally, the route for issuing a new access token should be protected by the <code>ability</code> middleware.</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Request</span>;
<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Enums</span>\<span class="hljs-title">TokenAbility</span>;

Route::post(<span class="hljs-string">'/auth/refresh-token'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Request $request</span>) </span>{
    $accessToken = $request-&gt;user()-&gt;createToken(<span class="hljs-string">'access_token'</span>, [TokenAbility::ACCESS_API-&gt;value], config(<span class="hljs-string">'sanctum.expiration'</span>));

    <span class="hljs-keyword">return</span> [<span class="hljs-string">'token'</span> =&gt; $accessToken-&gt;plainTextToken];
})-&gt;middleware([
    <span class="hljs-string">'auth:sanctum'</span>,
    <span class="hljs-string">'ability:'</span>.TokenAbility::ISSUE_ACCESS_TOKEN-&gt;value,
]);
</code></pre>
<p>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 <a target="_blank" href="https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/#Keeping-Refresh-Tokens-Secure">article</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Using ULID in Laravel Framework]]></title><description><![CDATA[In a previous post, 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.
ULID has been supported in Laravel since v9.30.1 and has received some i...]]></description><link>https://muhamadhhassan.me/using-ulid-in-laravel-framework</link><guid isPermaLink="true">https://muhamadhhassan.me/using-ulid-in-laravel-framework</guid><category><![CDATA[Laravel]]></category><category><![CDATA[uuid]]></category><category><![CDATA[PHP]]></category><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Sat, 20 May 2023 16:01:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684591626311/b55b47ff-3fb7-44cf-b09e-7ebe6149dd06.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In a previous <a target="_blank" href="https://muhamadhhassan.me/using-unique-identifiers-as-primary-key-in-mysql">post</a>, 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.</p>
<p>ULID has been supported in Laravel since <a target="_blank" href="https://github.com/laravel/framework/releases/tag/v9.30.1">v9.30.1</a> and has received some improvements in later releases So no third-party packages are needed to use it.</p>
<h3 id="heading-eloquent-models">Eloquent Models</h3>
<p>Let's take an <code>Article</code> model as an example. First, we create the article's model and migration file as we normally do</p>
<pre><code class="lang-bash">php artisan make:model Article
</code></pre>
<p>In the <code>up</code> method inside the migration file, the table's primary key will be defined using the <code>ulid</code> method followed by the <code>primary</code> method.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
</span>{
    Schema::create(<span class="hljs-string">'articles'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
        $table-&gt;ulid(<span class="hljs-string">'id'</span>)-&gt;primary();
        $table-&gt;string(<span class="hljs-string">'title'</span>);
        $table-&gt;text(<span class="hljs-string">'body'</span>);
        $table-&gt;timestamps();
    });
}
</code></pre>
<p>What the <a target="_blank" href="https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Schema/Blueprint.php#L1288"><code>ulid</code></a> method does is create a column of type <code>CHAR</code> and set its length to 26 bytes instead of the 36 bytes needed for UUIDs.</p>
<p>Then in the <code>Article</code> eloquent model, the <code>Illuminate\Database\Eloquent\Concerns\HasUlids</code> trait will be added</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Concerns</span>\<span class="hljs-title">HasUlids</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Factories</span>\<span class="hljs-title">HasFactory</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Model</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">HasFactory</span>, <span class="hljs-title">HasUlids</span>;
}
</code></pre>
<p>Laravel also has a method in the <code>Illuminate\Database\Schema\Blueprint</code> class for creating foreign keys that references a table with ULID primary key.</p>
<p>In our example, we can add a <code>Comment</code> model and each comment belongs to one <code>Article</code>. The foreign key of the articles table is defined using the <code>foreignUlid</code> method</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
</span>{
    Schema::create(<span class="hljs-string">'comments'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
        $table-&gt;uuid(<span class="hljs-string">'id'</span>)-&gt;primary();
        $table-&gt;string(<span class="hljs-string">'body'</span>);
        $table-&gt;foreignUlid(<span class="hljs-string">'article_id'</span>)-&gt;constrained();
        $table-&gt;timestamps();
    });
}
</code></pre>
<p>And the last method is <code>ulidMorphs</code> that create the columns needed for a polymorphic relation. Let's add another <code>Tag</code> model that can be linked to many models not just <code>Article</code>. The <code>taggables</code> table can be defined like this:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
</span>{
    Schema::create(<span class="hljs-string">'taggables'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
        $table-&gt;foreignUlid(<span class="hljs-string">'tag_id'</span>)-&gt;constrained();
        $table-&gt;ulidMorphs(<span class="hljs-string">'taggable'</span>);
    });
}
</code></pre>
<h3 id="heading-str-facade">Str Facade</h3>
<p>ULID can be created anywhere in your app using the <code>ulid</code> method in the <code>Illuminate\Support\Str</code> facade.</p>
<pre><code class="lang-php">Str::ulid()-&gt;toBase32()
</code></pre>
<p>The above statement returns the ULID and it will look something like this <code>01H0WXWP3XGAX0ZJVG7Q2E70FC</code>.</p>
<p>Finally, if you are interested in the implementation being used to generate ULID, check out the <a target="_blank" href="https://github.com/symfony/uid">Symfony UID</a> component that Laravel uses.</p>
]]></content:encoded></item><item><title><![CDATA[Using Unique Identifiers as Primary Key in MySQL]]></title><description><![CDATA[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 alphanu...]]></description><link>https://muhamadhhassan.me/using-unique-identifiers-as-primary-key-in-mysql</link><guid isPermaLink="true">https://muhamadhhassan.me/using-unique-identifiers-as-primary-key-in-mysql</guid><category><![CDATA[MySQL]]></category><category><![CDATA[Databases]]></category><category><![CDATA[uuid]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Sun, 30 Apr 2023 20:57:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682886437294/a1ce18e4-f584-421c-848e-4e3f4a454131.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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, <a target="_blank" href="https://en.wikipedia.org/wiki/Snowflake_ID">Snowflake ID</a>, <a target="_blank" href="https://betterexplained.com/articles/the-quick-guide-to-guids/">GUID</a> and more.</p>
<p>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:</p>
<ul>
<li><p>Unique identifiers have a low probability of collision even across tables and databases.</p>
</li>
<li><p>They can be generated by the application without a centralized authority.</p>
</li>
<li><p>And since they are pseudo-random, they can be sent safely to the client side.</p>
</li>
</ul>
<p>But as with any tech or tool, some tradeoffs come with using a unique identifier.</p>
<h1 id="heading-uuids">UUIDs</h1>
<p>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 a 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 <code>8-4-4-4-12</code>. For example, a UUID might look like this: <code>245dffb2-7068-405f-b759-88c3ef8bcf3d</code>.</p>
<h2 id="heading-uuids-are-pseudo-random">UUIDs are Pseudo Random</h2>
<p>The negative impact of using UUID as the primary key comes from how MySQL’s default engine, <code>InnoDB</code>, stores the data. <code>InnoDB</code> 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 disk in the same order as the index.</p>
<p>When a new row with a random UUID needs to be inserted, <code>InnoDB</code> needs to:</p>
<ol>
<li><p>Checks whether the page is already in the <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html">buffer pool</a></p>
</li>
<li><p>If the page is not in the buffer pool, <code>InnoDB</code> reads the page from the disk.</p>
</li>
<li><p>Write the page to the buffer pool.</p>
</li>
<li><p>Insert the new row.</p>
</li>
<li><p>At some point, the page will be flushed back to the disk.</p>
</li>
</ol>
<p>Normally when a page is frequently accessed and modified it becomes a hot page, and the buffer pool gives it a 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.</p>
<p>Additionally, inserting rows with random primary keys can cause more page splits. A page split occurs when an <code>InnoDB</code> 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.</p>
<p>Random primary keys can also lead to a page low filling factor. According to <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/innodb-physical-structure.html">MySQL documentation</a>:</p>
<blockquote>
<p>When new records are inserted into an <code>InnoDB</code> clustered index, <code>InnoDB</code> 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.</p>
</blockquote>
<h2 id="heading-uuids-size">UUIDs Size</h2>
<p>UUIDs have a size of 128 bits and their hexadecimal form (<code>8-4-4-4-12</code>) can be stored in a <code>CHAR(36)</code> 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 <code>CHAR(36)</code> column will require 36 bytes of storage.</p>
<p>Having 36 bytes for the primary key does not seem to be a lot at first glance and to put it into perspective let's assume a table with a UUID primary key and 4 secondary indexes. Considering that each secondary index stores 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:</p>
<ul>
<li><p>6 x 36 = 216 bytes of storage per row</p>
</li>
<li><p>For the 10M rows: 10,000,000 rows x 216 bytes/row = 2,160,000,000 bytes</p>
</li>
<li><p>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</p>
</li>
</ul>
<h1 id="heading-ulids">ULIDs</h1>
<p>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:</p>
<ol>
<li><p>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.</p>
</li>
<li><p>A 16-character random value, encoded using <a target="_blank" href="https://www.crockford.com/base32.html">Crockford's</a> base32 encoding. This value ensures that each ULID is unique even if generated at the same time.</p>
</li>
</ol>
<p>Additionally, according to the ULID spec, it can be superior to UUIDs given that:</p>
<ul>
<li><p>It has <code>1.21 X 10^24</code> possible values per millisecond.</p>
</li>
<li><p>Lexicographically sortable</p>
</li>
<li><p>Canonically encoded as a 26-character string, as opposed to the 36-character UUID</p>
</li>
<li><p>Case insensitive</p>
</li>
<li><p>URL safe</p>
</li>
</ul>
<p>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</p>
]]></content:encoded></item><item><title><![CDATA[Sending Laravel Logs to Mattermost Channels]]></title><description><![CDATA[Mattermost 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.
Although Laravel does not have an official log channel dr...]]></description><link>https://muhamadhhassan.me/sending-laravel-logs-to-mattermost-channels</link><guid isPermaLink="true">https://muhamadhhassan.me/sending-laravel-logs-to-mattermost-channels</guid><category><![CDATA[Laravel]]></category><category><![CDATA[logging]]></category><category><![CDATA[Mattermost]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Fri, 23 Sep 2022 23:06:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663968421134/L6UYL3NMD.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://mattermost.com/">Mattermost</a> 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.</p>
<p>Although Laravel does not have an official <a target="_blank" href="https://laravel.com/docs/9.x/logging#available-channel-drivers">log channel driver</a> for Mattermost, we can build a custom <a target="_blank" href="https://github.com/Seldaek/monolog">Monolog</a> handler that can be easily configured in Laravel apps.</p>
<p>I have created a small <a target="_blank" href="https://github.com/muhamadhhassan/laramost">package</a> for this purpose that, unlike the existing Mattermost handlers, format the message according to Mattermost <a target="_blank" href="https://developers.mattermost.com/integrate/webhooks/incoming/#parameters">docs</a></p>
<h2 id="heading-installation">Installation</h2>
<pre><code class="lang-bash">$ composer require muhamadhhassan/laramost
</code></pre>
<h2 id="heading-configuration">Configuration</h2>
<p>In your <code>config/logging.php</code> file, add the <code>mattermost</code> channel to the <code>channels</code> array:</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">LaraMost</span>\<span class="hljs-title">Formatter</span>\<span class="hljs-title">MattermostFormatter</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">LaraMost</span>\<span class="hljs-title">Handler</span>\<span class="hljs-title">MattermostWebhookHandler</span>;

<span class="hljs-string">'channels'</span> =&gt; [
    <span class="hljs-string">'mattermost'</span> =&gt; [
        <span class="hljs-string">'driver'</span>  =&gt; <span class="hljs-string">'monolog'</span>,
        <span class="hljs-string">'handler'</span> =&gt; MattermostWebhookHandler::class,
        <span class="hljs-string">'formatter'</span> =&gt; MattermostFormatter::class,
        <span class="hljs-string">'with'</span> =&gt; [
            <span class="hljs-string">'hook'</span> =&gt; <span class="hljs-string">'https://your-mattermost.com/hooks/random-string'</span>,
        ],
        <span class="hljs-string">'level'</span> =&gt; <span class="hljs-string">'error'</span>
    ],
],
</code></pre>
<p>You can follow the steps <a target="_blank" href="https://developers.mattermost.com/integrate/webhooks/incoming/#create-an-incoming-webhook">here</a> to create an incoming webhook for your channel.</p>
<h3 id="heading-levels">Levels</h3>
<p>Monolog levels are used to set the message color and icon</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Level Name</td><td>Level Value</td><td>Color</td><td>Emoji</td></tr>
</thead>
<tbody>
<tr>
<td>DEBUG</td><td>100</td><td>#91C4EB</td><td>🔍</td></tr>
<tr>
<td>INFO</td><td>200</td><td>#91C4EB</td><td>ℹ</td></tr>
<tr>
<td>NOTICE</td><td>250</td><td>#99cc33</td><td>📝</td></tr>
<tr>
<td>WARNING</td><td>300</td><td>#ffcc00</td><td>⚠</td></tr>
<tr>
<td>ERROR</td><td>400</td><td>#cc3300</td><td>🐛</td></tr>
<tr>
<td>CRITICAL</td><td>500</td><td>#cc3300</td><td>❌</td></tr>
<tr>
<td>EMERGENCY</td><td>600</td><td>#cc3300</td><td>🚨</td></tr>
</tbody>
</table>
</div><h2 id="heading-usage">Usage</h2>
<p>Simply, using Laravel <code>Log</code> facade</p>
<pre><code class="lang-php">Log::channel(<span class="hljs-string">'mattermost'</span>)-&gt;error(<span class="hljs-string">'Something went wrong'</span>, [<span class="hljs-string">'user_id'</span> =&gt; <span class="hljs-number">5</span>]);
</code></pre>
<p>Will send the following message to your mattermost channel:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663973166282/NGfimPR4F.png" alt="Screenshot 2022-09-23 172832.png" /></p>
<blockquote>
<p>⚠ <strong>Warning</strong>: When you log to the <code>mattermost</code> channel make sure that the level is greater than or equals the one defined in <code>config/logging.php</code></p>
</blockquote>
<p>And there you have it! A simple implementation to send log records to a Mattermost channel.</p>
]]></content:encoded></item><item><title><![CDATA[Preventing User Enumeration Attack in Laravel Apps]]></title><description><![CDATA[User enumeration is a brute-force technique that is used to collect or verify valid users' credentials. It belongs to the Identification and Authentication Failures category (AKA broken authentication) which came in 7th place on the Top 10 Web Applic...]]></description><link>https://muhamadhhassan.me/preventing-user-enumeration-attack-in-laravel-apps</link><guid isPermaLink="true">https://muhamadhhassan.me/preventing-user-enumeration-attack-in-laravel-apps</guid><category><![CDATA[Laravel]]></category><category><![CDATA[Security]]></category><category><![CDATA[authentication]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Fri, 13 May 2022 13:41:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1652132282367/SAFGAo6K2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>User enumeration is a brute-force technique that is used to collect or verify valid users' credentials. It belongs to the <strong>Identification and Authentication Failures</strong> category (AKA broken authentication) which came in 7th place on the <a target="_blank" href="https://owasp.org/www-project-top-ten/">Top 10 Web Application Security Risks 2021</a> 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 <a target="_blank" href="https://owasp.org/www-community/attacks/Credential_stuffing">credential stuffing</a> and <a target="_blank" href="https://owasp.org/www-community/attacks/Password_Spraying_Attack">password spraying</a>.
Bear in mind that user enumeration vulnerabilities are not exclusive for web applications, it can be found in any system that requires authentication.</p>
<h4 id="heading-attacking-scenarios">Attacking Scenarios</h4>
<p>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:</p>
<ul>
<li>Login</li>
<li>Registration</li>
<li>Password Reset</li>
</ul>
<h4 id="heading-laravel-authentication">Laravel Authentication</h4>
<p>Laravel provide us with robust solutions and starter kits for authentication so let's start by creating a new Laravel 9 project and install <a target="_blank" href="https://jetstream.laravel.com">Jetstram</a></p>
<pre><code class="lang-shell">laravel new user-enum

composer require laravel/jetstream
</code></pre>
<p>and for simplicity we will use SQLite <code>3.36.0</code></p>
<pre><code class="lang-env">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=
</code></pre>
<h4 id="heading-login">Login</h4>
<p>Out of the box, the error message is consistent whether you entered an incorrect email or password.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652379051093/RJyoTO8qm.png" alt="New Project.png" class="image--center mx-auto" /></p>
<h4 id="heading-password-reset">Password Reset</h4>
<p>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.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652379698812/1WD8PrMxC.png" alt="Screenshot 2022-05-12 201848.png" class="image--center mx-auto" /></p>
<p>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</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652396739102/Xzj-lKaSz.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Under the hood, Jetstream is using <a target="_blank" href="https://laravel.com/docs/9.x/fortify">Fortify</a> which is a frontend-agnostic authentication implementation. Our first stop will be the controller registered by Fortify for password reset.</p>
<pre><code class="lang-shell">php artisan route:list
  ...
  POST  forgot-password ............. password.email › Laravel\Fortify › PasswordResetLinkController@store
</code></pre>
<p>Let's see what the method <code>Laravel\Fortify\PasswordResetLinkController::store</code> do:</p>
<ol>
<li>First, it validates the submitted email address.</li>
<li>Then the password broker tries to send the reset email to the user of the submitted email address.</li>
<li>Based on the return value of the <code>\Illuminate\Contracts\Auth\PasswordBroker::sendResetLink()</code> method, the response is determined hence the user information is disclosed.</li>
</ol>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">Request $request</span>): <span class="hljs-title">Responsable</span>
</span>{
    $request-&gt;validate([Fortify::email() =&gt; <span class="hljs-string">'required|email'</span>]);

    <span class="hljs-comment">// We will send the password reset link to this user. Once we have attempted</span>
    <span class="hljs-comment">// to send the link, we will examine the response then see the message we</span>
    <span class="hljs-comment">// need to show to the user. Finally, we'll send out a proper response.</span>
    $status = <span class="hljs-keyword">$this</span>-&gt;broker()-&gt;sendResetLink(
        $request-&gt;only(Fortify::email())
    );

    <span class="hljs-keyword">return</span> $status == Password::RESET_LINK_SENT
                ? app(SuccessfulPasswordResetLinkRequestResponse::class, [<span class="hljs-string">'status'</span> =&gt; $status])
                : app(FailedPasswordResetLinkRequestResponse::class, [<span class="hljs-string">'status'</span> =&gt; $status]);
}
</code></pre>
<p>To fix this, we will create our controller at <code>App\Http\Controller\Auth\PasswordResetLinkController</code> 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 <code>SuccessfulPasswordResetLinkRequestResponse</code> message.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">Request $request</span>): <span class="hljs-title">Responsable</span>
</span>{
    $request-&gt;validate([Fortify::email() =&gt; <span class="hljs-string">'required|email'</span>]);
    $email = $request-&gt;only(Fortify::email());
    $status = <span class="hljs-keyword">$this</span>-&gt;broker()-&gt;sendResetLink($email);

    <span class="hljs-keyword">if</span> ($status !== Password::RESET_LINK_SENT) {
        Log::error(__($status, [], <span class="hljs-string">'en'</span>), [<span class="hljs-string">'email'</span> =&gt; $email]);
    }

    <span class="hljs-keyword">return</span> app(SuccessfulPasswordResetLinkRequestResponse::class, [<span class="hljs-string">'status'</span> =&gt; Password::RESET_LINK_SENT]);
}
</code></pre>
<p>Then we need to define our <code>reset-password</code> route in <code>routes/web.php</code> that will point to the above controller</p>
<pre><code class="lang-php">Route::post(<span class="hljs-string">'reset-password'</span>, <span class="hljs-string">'App\Http\Controllers\Auth\PasswordResetLinkController@store'</span>)
    -&gt;name(<span class="hljs-string">'password.email'</span>)
    -&gt;middleware(<span class="hljs-string">'guest'</span>);
</code></pre>
<p>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!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652385742386/zD97UPhIp.png" alt="image.png" class="image--center mx-auto" /></p>
<p>One way to reduce the gap between the two scenarios is to make the <code>Illuminate\Auth\Notifications\ResetPassword</code> notification queueable. So, again we will create our version of this notification at <code>App\Notifications\ResetPassword</code> and make it so. Check the Laravel docs for more information on <a target="_blank" href="https://laravel.com/docs/9.x/notifications#queueing-notifications">queuing notifications</a></p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Notifications</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Auth</span>\<span class="hljs-title">Notifications</span>\<span class="hljs-title">ResetPassword</span> <span class="hljs-title">as</span> <span class="hljs-title">CoreResetPassword</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Bus</span>\<span class="hljs-title">Queueable</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">Queue</span>\<span class="hljs-title">ShouldQueue</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ResetPassword</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">CoreResetPassword</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ShouldQueue</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">Queueable</span>;
}
</code></pre>
<p>Then we will override the <code>Illuminate\Auth\Passwords\CanResetPassword::sendPasswordResetNotification()</code> method in the <code>App\Models\User</code> model</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendPasswordResetNotification</span>(<span class="hljs-params">$token</span>)
</span>{
    <span class="hljs-keyword">$this</span>-&gt;notify(<span class="hljs-keyword">new</span> ResetPassword($token));
}
</code></pre>
<h4 id="heading-registration">Registration</h4>
<p>I think you already know the answer to this. Yes, the registration response will disclose whether the user email exist or not.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652397113712/aWGT44nMM.png" alt="image.png" class="image--center mx-auto" /></p>
<p>To make the response consistent, we will <a target="_blank" href="https://laravel.com/docs/9.x/verification#model-preparation">enable user email verification</a> so that an email is sent in both scenarios</p>
<p>Then publish Fortify resources so that its actions become editable. Specifically <code>App\Actions\Fortify\CreateNewUser</code></p>
<pre><code class="lang-bash">php artisan vendor:publish --provider=<span class="hljs-string">"Laravel\Fortify\FortifyServiceProvider"</span>
</code></pre>
<p>The changes is quite simple, first, we remove the <code>unique</code> rule from the <code>email</code> input. Then, if a user with the submitted email address exist, an email will be sent to notify him/her. </p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $input</span>): ?<span class="hljs-title">User</span>
</span>{
    Validator::make($input, [
        <span class="hljs-string">'name'</span> =&gt; [<span class="hljs-string">'required'</span>, <span class="hljs-string">'string'</span>, <span class="hljs-string">'max:255'</span>],
        <span class="hljs-string">'email'</span> =&gt; [<span class="hljs-string">'required'</span>, <span class="hljs-string">'string'</span>, <span class="hljs-string">'email'</span>, <span class="hljs-string">'max:255'</span>],
        <span class="hljs-string">'password'</span> =&gt; <span class="hljs-keyword">$this</span>-&gt;passwordRules(),
        <span class="hljs-string">'terms'</span> =&gt; Jetstream::hasTermsAndPrivacyPolicyFeature() ? [<span class="hljs-string">'accepted'</span>, <span class="hljs-string">'required'</span>] : <span class="hljs-string">''</span>,
    ])-&gt;validate();

    <span class="hljs-keyword">if</span> ($user = User::whereEmail($input[<span class="hljs-string">'email'</span>])-&gt;first()) {
        $user-&gt;notify(<span class="hljs-keyword">new</span> AlreadyHaveAccount());
        <span class="hljs-keyword">return</span> ;
    }

    <span class="hljs-keyword">return</span> User::create([
        <span class="hljs-string">'name'</span> =&gt; $input[<span class="hljs-string">'name'</span>],
        <span class="hljs-string">'email'</span> =&gt; $input[<span class="hljs-string">'email'</span>],
        <span class="hljs-string">'password'</span> =&gt; Hash::make($input[<span class="hljs-string">'password'</span>]),
    ]);
}
</code></pre>
<p>And the <code>App\Notifications\AlreadyHaveAccount</code> notification will be</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Notifications</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Bus</span>\<span class="hljs-title">Queueable</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">Queue</span>\<span class="hljs-title">ShouldQueue</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Notifications</span>\<span class="hljs-title">Messages</span>\<span class="hljs-title">MailMessage</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Notifications</span>\<span class="hljs-title">Notification</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Facades</span>\<span class="hljs-title">Lang</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AlreadyHaveAccount</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Notification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ShouldQueue</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">Queueable</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"></span>)
    </span>{
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">via</span>(<span class="hljs-params">mixed $notifiable</span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">return</span> [<span class="hljs-string">'mail'</span>];
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toMail</span>(<span class="hljs-params">mixed $notifiable</span>): <span class="hljs-title">MailMessage</span>
    </span>{
        <span class="hljs-keyword">return</span> (<span class="hljs-keyword">new</span> MailMessage)
            -&gt;subject(<span class="hljs-string">'New Registration Attempt with Your Email Address'</span>)
            -&gt;line(<span class="hljs-string">'You are receiving this email because we received a registration request with your registered email address.'</span>)
            -&gt;action(<span class="hljs-string">'Login Instead'</span>, route(<span class="hljs-string">'login'</span>))
            -&gt;line(Lang::get(<span class="hljs-string">'If you did not try to register a new account, no further action is required.'</span>));
    }
}
</code></pre>
<p>Next, we will create a job that accept <code>CreateNewUser</code> action and the submitted input to make the response time consistent</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Jobs</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Auth</span>\<span class="hljs-title">Events</span>\<span class="hljs-title">Registered</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Bus</span>\<span class="hljs-title">Queueable</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">Queue</span>\<span class="hljs-title">ShouldQueue</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Foundation</span>\<span class="hljs-title">Bus</span>\<span class="hljs-title">Dispatchable</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Queue</span>\<span class="hljs-title">InteractsWithQueue</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Queue</span>\<span class="hljs-title">SerializesModels</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Laravel</span>\<span class="hljs-title">Fortify</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">CreatesNewUsers</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterUser</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ShouldQueue</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">Dispatchable</span>, <span class="hljs-title">InteractsWithQueue</span>, <span class="hljs-title">Queueable</span>, <span class="hljs-title">SerializesModels</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> CreatesNewUsers $creator, <span class="hljs-keyword">private</span> <span class="hljs-keyword">array</span> $input</span>)
    </span>{
        <span class="hljs-comment">//</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span>(<span class="hljs-params"></span>)
    </span>{
        $user = <span class="hljs-keyword">$this</span>-&gt;creator-&gt;create(<span class="hljs-keyword">$this</span>-&gt;input);

        <span class="hljs-keyword">if</span> ($user) {
            event(<span class="hljs-keyword">new</span> Registered($user));
        }
    }
}
</code></pre>
<p>And finally, create a controller for registration, like we did with resetting passwords, and make the <code>register</code> route point to it</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>\<span class="hljs-title">Auth</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Responses</span>\<span class="hljs-title">RegisterResponse</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Jobs</span>\<span class="hljs-title">RegisterUser</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Request</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Laravel</span>\<span class="hljs-title">Fortify</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">CreatesNewUsers</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Laravel</span>\<span class="hljs-title">Fortify</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>\<span class="hljs-title">RegisteredUserController</span> <span class="hljs-title">as</span> <span class="hljs-title">FortifyRegisteredUserController</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisteredUserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">FortifyRegisteredUserController</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">Request $request, CreatesNewUsers $creator</span>): <span class="hljs-title">RegisterResponse</span>
    </span>{

        RegisterUser::dispatch($creator, $request-&gt;all());

        <span class="hljs-keyword">return</span> app(RegisterResponse::class);
    }
}
</code></pre>
<pre><code class="lang-php">Route::post(<span class="hljs-string">'register'</span>, <span class="hljs-string">'App\Http\Controllers\Auth\RegisteredUserController@store'</span>)
    -&gt;middleware(<span class="hljs-string">'guest'</span>);
</code></pre>
<p>Now login, reset password and registration will never disclose existing users information and our app is protected against user enumeration attacks ✌.</p>
]]></content:encoded></item><item><title><![CDATA[Adding PHPUnit Test Log and Coverage to GitLab CI/CD Pipeline]]></title><description><![CDATA[In this tutorial we are going to setup a GitLab CI/CD job that can run your PHPUnit test suite and extract a testing report plus the overall coverage. First, we need to setup our server and install the required tools. DigitalOcean has many useful tut...]]></description><link>https://muhamadhhassan.me/adding-phpunit-test-log-and-coverage-to-gitlab-cicd-pipeline</link><guid isPermaLink="true">https://muhamadhhassan.me/adding-phpunit-test-log-and-coverage-to-gitlab-cicd-pipeline</guid><category><![CDATA[PHPUnit]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Fri, 22 Apr 2022 22:22:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1652288135173/pHPp9JNzg.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial we are going to setup a GitLab CI/CD job that can run your <code>PHPUnit</code> test suite and extract a testing report plus the overall coverage. First, we need to setup our server and install the required tools. <code>DigitalOcean</code> has many useful tutorials and we are going to use some of them for the initial setup.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>An <code>Ubuntu 20.04</code> server setup by following this <a target="_blank" href="https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-20-04">tutorial</a></li>
<li>Install <code>Docker</code> following this <a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04">tutorial</a></li>
<li>Finally, installing <code>Docker Compose</code> by following this <a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-20-04">tutorial</a></li>
</ul>
<h2 id="heading-server-setup">Server Setup</h2>
<p>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.</p>
<ol>
<li><p>Adding the official <code>gitlab-runner</code> repo and inspecting the security of the installing script</p>
<pre><code class="lang-bash">curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh &gt; script.deb.sh
less script.deb.sh
</code></pre>
</li>
<li><p>Running the installer</p>
<pre><code class="lang-bash">sudo bash script.deb.sh
</code></pre>
</li>
<li><p>Install <code>gitlab-runner</code> service</p>
<pre><code class="lang-bash">sudo apt install gitlab-runner
</code></pre>
</li>
<li><p>Check the service status</p>
<pre><code class="lang-bash">systemctl status gitlab-runner
</code></pre>
<p>The output should be something like this</p>
<pre><code class="lang-bash">Output
● gitlab-runner.service - GitLab Runner
   Loaded: loaded (/etc/systemd/system/gitlab-runner.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2020-06-01 09:01:49 UTC; 4s ago
 Main PID: 16653 (gitlab-runner)
    Tasks: 6 (<span class="hljs-built_in">limit</span>: 1152)
   CGroup: /system.slice/gitlab-runner.service
           └─16653 /usr/lib/gitlab-runner/gitlab-runner run --working-directory /home/gitlab-runner --config /etc/gitla
</code></pre>
</li>
</ol>
<h3 id="heading-register-a-runner-for-your-gitlab-project">Register a Runner for Your GitLab Project</h3>
<ol>
<li><p>In your GitLab project, navigate to <strong>Settings &gt; CI/CD &gt; Runners</strong>.</p>
</li>
<li><p>In the <strong>Specific Runners</strong> section, you’ll find the <strong>registration token</strong> and the GitLab URL. Copy both as we’ll need them for the next command.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ba7t65mlfj8uxd00e6kc.png" alt="Image description" /></p>
</li>
<li><p>Now in the terminal, register the runner by running</p>
<pre><code class="lang-bash">sudo gitlab-runner register -n --url https://your_gitlab.com --registration-token project_token --executor shell --description <span class="hljs-string">"Staging Shell Runner"</span> --tag-list deployment
</code></pre>
<p>This seems like a lot of options but they’re pretty easy to understand:</p>
<ul>
<li><code>-n</code> executes the register command non-interactively.</li>
<li><code>--url</code> is the GitLab URL from step 2.</li>
<li><code>--registration-token</code> is the token you copied from the runners page in step 2.</li>
<li><code>--executor</code> is the executor type, we are using <code>shell</code> executer here which is a simple executor that you use to execute builds locally on the machine where GitLab Runner is installed.</li>
<li><code>--description</code> is the runner’s description, which will show up in GitLab.</li>
<li><code>--tag-list</code> 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 <code>deployment</code> tag will allow you to refer to this specific runner to execute the deployment job.</li>
</ul>
</li>
<li><p>The output of the above command will return an output like this:</p>
<pre><code class="lang-bash">Output
Runner registered successfully. Feel free to start it, but <span class="hljs-keyword">if</span> it<span class="hljs-string">'s running already the config should be automatically reloaded!</span>
</code></pre>
<p>And the runner will show up in your project’s <strong>Settings &gt; CI/CD &gt; Runners</strong>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zfp1axk52mf8z3f5gfi8.png" alt="Image description" /></p>
</li>
</ol>
<h3 id="heading-create-deployment-user">Create Deployment User</h3>
<ol>
<li><p>Create a new user</p>
<pre><code class="lang-bash">sudo adduser deployer
</code></pre>
</li>
<li><p>Add user to docker group to permit <code>deployer</code> to execute the <code>docker</code> command, which is required to perform the deployment</p>
<pre><code class="lang-bash">sudo usermod -aG docker deployer
</code></pre>
</li>
<li><p>Create SSH key for <code>deployer</code></p>
<p>Switch to the <code>deployer</code> user</p>
<pre><code class="lang-bash">su deployer
</code></pre>
<p>Then generate a 4096-bit SSH key</p>
<pre><code class="lang-bash">ssh-keygen -b 4096
</code></pre>
<blockquote>
<p>⚠ 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</p>
</blockquote>
<p> Add the new key to the authorized keys</p>
<pre><code class="lang-bash"> cat ~/.ssh/id_rsa.pub &gt;&gt; ~/.ssh/authorized_keys
</code></pre>
</li>
<li><p>Storing the private key in a GitLab CI/CD variable</p>
<p>First, get the private key be executing</p>
<pre><code class="lang-bash">cat ~/.ssh/id_rsa
</code></pre>
<p>Copy the output and navigate to <strong>Settings &gt; CI / CD &gt; Variables</strong> and click <strong>Add Variable</strong></p>
<p>fill the variable form like this</p>
<ul>
<li>Key: <code>ID_RSA</code></li>
<li>Value: Paste your SSH private key from your clipboard (including a line break at the end).</li>
<li>Type: <strong>File</strong></li>
<li>Environment Scope: <strong>All (default)</strong></li>
<li>Protect variable: <strong>Checked</strong></li>
<li>Mask variable: <strong>Unchecked</strong></li>
</ul>
<p>Create another variable for your server IP address</p>
<ul>
<li>Key: <code>SERVER_IP</code></li>
<li>Value: <code>your_server_IP</code></li>
<li>Type: <strong>Variable</strong></li>
<li>Environment scope: <strong>All (default)</strong></li>
<li>Protect variable: <strong>Checked</strong></li>
<li>Mask variable: <strong>Checked</strong></li>
</ul>
<p>And the last variable is for the user</p>
<ul>
<li>Key: <code>SERVER_USER</code></li>
<li>Value: <code>deployer</code></li>
<li>Type: <strong>Variable</strong></li>
<li>Environment scope: <strong>All (default)</strong></li>
<li>Protect variable: <strong>Checked</strong></li>
<li>Mask variable: <strong>Checked</strong></li>
</ul>
</li>
</ol>
<h2 id="heading-configuring-gitlab-ciyml-file">Configuring <code>.gitlab-ci.yml</code> File</h2>
<p>Next, we will be prepare the docker file for testing environment, the application service in docker compose file and finally PHPUnit job in <code>.gitlab-ci.yml</code></p>
<h3 id="heading-application-docker-file">Application Docker file</h3>
<p>In your app docker file we will need to install <a target="_blank" href="https://xdebug.org/">XDebug</a> extension to collect the testing coverage report and create two new files: <code>phpunit-report.xml</code> and <code>phpunit-coverage.xml</code> for testing report and testing coverage.</p>
<p>We will create the file in <code>./docker/testingApp.dockerfile</code> with minimal configuration. It should be something like this.</p>
<pre><code class="lang-docker">FROM php:8.1.3-fpm-alpine

WORKDIR /var/www/

# Install alpine packages
RUN apk add --no-cache --update # Add your packages

# Install php extensions
RUN docker-php-ext-install # Add the PHP extension you need

# Install XDebug
RUN pecl install xdebug \
    &amp;&amp; docker-php-ext-enable xdebug 

# Copy existing application directory contents
COPY --chown=www-data:www-data . .

RUN touch phpunit-report.xml phpunit-coverage.xml
RUN chmod 777 phpunit-report.xml phpunit-coverage.xml

USER www-data
</code></pre>
<h3 id="heading-application-service">Application Service</h3>
<p>The <code>app</code> service in <code>./docker/docker-compose-testing.yml</code> will have two volumes: one for the <code>tests</code> directory and the other is <code>./docker/php/conf.d/xdebug.ini</code> that will contain the basic XDebug configuration.</p>
<p>The app service should look like this:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">"3"</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">app:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">"app-testing"</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">../</span>
      <span class="hljs-attr">dockerfile:</span> <span class="hljs-string">./docker/testingApp.dockerfile</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini</span>
    <span class="hljs-attr">working_dir:</span> <span class="hljs-string">/var/www</span>
</code></pre>
<p>And xdebug.ini is quite minimal, we just set enable the <code>coverage</code> mode but you can enable multiple modes at the same time. Learn more about XDebug modes from the <a target="_blank" href="https://xdebug.org/docs/all_settings#mode">documentation</a></p>
<pre><code class="lang-ini"><span class="hljs-attr">zend_extension</span>=xdebug

<span class="hljs-section">[xdebug]</span>
<span class="hljs-attr">xdebug.mode</span>=coverage
</code></pre>
<h3 id="heading-phpunit-job">PHPUnit Job</h3>
<p>In <code>.gitlab-ci.yml</code> we will create a job for <code>PHPUnit</code>  that will have the <code>deployment</code> tag so that it uses our runner and extract the required artifacts for GitLab to display test reports.</p>
<p>The job will be</p>
<pre><code class="lang-yaml"><span class="hljs-attr">phpunit:</span>
  <span class="hljs-attr">stage:</span> <span class="hljs-string">test</span>
  <span class="hljs-attr">tags:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">deployment</span>
  <span class="hljs-attr">before_script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker-compose</span> <span class="hljs-string">-p</span> <span class="hljs-string">my-project</span> <span class="hljs-string">-f</span> <span class="hljs-string">docker/docker-compose-testing.yml</span> <span class="hljs-string">build</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker-compose</span> <span class="hljs-string">-p</span> <span class="hljs-string">my-project</span> <span class="hljs-string">-f</span> <span class="hljs-string">docker/docker-compose-testing.yml</span> <span class="hljs-string">up</span> <span class="hljs-string">-d</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker</span> <span class="hljs-string">exec</span> <span class="hljs-string">$CONTAINER_NAME</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">migrate</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker</span> <span class="hljs-string">exec</span> <span class="hljs-string">$CONTAINER_NAME</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">db:seed</span>
  <span class="hljs-attr">script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker</span> <span class="hljs-string">exec</span> <span class="hljs-string">-t</span> <span class="hljs-string">$CONTAINER_NAME</span> <span class="hljs-string">vendor/bin/phpunit</span> <span class="hljs-string">--do-not-cache-result</span> <span class="hljs-string">--log-junit</span> <span class="hljs-string">phpunit-report.xml</span> <span class="hljs-string">--coverage-cobertura</span> <span class="hljs-string">phpunit-coverage.xml</span> <span class="hljs-string">--coverage-text</span> <span class="hljs-string">--colors=never</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker</span> <span class="hljs-string">cp</span> <span class="hljs-string">$CONTAINER_NAME:/var/www/phpunit-report.xml</span> <span class="hljs-string">./</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker</span> <span class="hljs-string">cp</span> <span class="hljs-string">$CONTAINER_NAME:/var/www/phpunit-coverage.xml</span> <span class="hljs-string">./</span>
  <span class="hljs-attr">after_script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">docker-compose</span> <span class="hljs-string">-p</span> <span class="hljs-string">my-project</span> <span class="hljs-string">-f</span> <span class="hljs-string">docker/docker-compose-testing.yml</span> <span class="hljs-string">down</span>
  <span class="hljs-attr">artifacts:</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">reports:</span>
      <span class="hljs-attr">junit:</span> <span class="hljs-string">phpunit-report.xml</span>
      <span class="hljs-attr">coverage_report:</span>
        <span class="hljs-attr">coverage_format:</span> <span class="hljs-string">cobertura</span>
        <span class="hljs-attr">path:</span> <span class="hljs-string">phpunit-coverage.xml</span>
  <span class="hljs-attr">coverage:</span> <span class="hljs-string">'/^\s*Lines:\s*\d+.\d+\%/'</span>
  <span class="hljs-attr">only:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">develop</span>
</code></pre>
<p>You should notice that we build our containers using <code>docker-compose-testing.yml</code>, run the DB migrations and seeder then run our test suit with a few options:</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -t <span class="hljs-variable">$CONTAINER_NAME</span> vendor/bin/phpunit --do-not-cache-result --log-junit phpunit-report.xml --coverage-cobertura phpunit-coverage.xml --coverage-text --colors=never
</code></pre>
<ul>
<li><code>--do-not-cache-result</code> to disable test result caching.</li>
<li><code>--log-junit phpunit-report.xml</code> specify the test log format and the output file.</li>
<li><code>--coverage-cobertura phpunit-coverage.xml</code> specify the coverage full report format and the output file.</li>
<li><code>--coverage-text</code> generate code coverage report in text format.</li>
<li><code>--colors=never</code> disable colors in the output to make it easier to extract the coverage percentage from the command output.</li>
</ul>
<p>Then we copy the generated reports from inside the container to the pipeline namespace to be used as job artifacts</p>
<pre><code class="lang-bash">docker cp <span class="hljs-variable">$CONTAINER_NAME</span>:/var/www/phpunit-report.xml ./
docker cp <span class="hljs-variable">$CONTAINER_NAME</span>:/var/www/phpunit-coverage.xml ./
</code></pre>
<p>The job will have two artifacts of type <code>reports</code> the first is the a <code>junit</code> for test log and a <code>cobertura</code> report for the test coverage.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">artifacts:</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">reports:</span>
      <span class="hljs-attr">junit:</span> <span class="hljs-string">phpunit-report.xml</span>
      <span class="hljs-attr">coverage_report:</span>
        <span class="hljs-attr">coverage_format:</span> <span class="hljs-string">cobertura</span>
        <span class="hljs-attr">path:</span> <span class="hljs-string">phpunit-coverage.xml</span>
</code></pre>
<blockquote>
<p>ℹ The report formats and files’ extensions are specified by GitLab</p>
</blockquote>
<h2 id="heading-project-configuration">Project Configuration</h2>
<p>At this point we have created a job for PHPUnit that we run on our <code>Staging Shell Runner</code> 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.</p>
<p>To go one step further, we can track the test coverage history and add coverage badge to the project</p>
<h3 id="heading-test-coverage-history-deprecatedhttpsdocsgitlabcom1410eecipipelinessettingshtmladd-test-coverage-results-using-project-settings-deprecated-in-gitlab-149">Test Coverage History <em>(<a target="_blank" href="https://docs.gitlab.com/14.10/ee/ci/pipelines/settings.html#add-test-coverage-results-using-project-settings-deprecated">Deprecated</a> in GitLab 14.9)</em></h3>
<p>Navigate to <strong>Settings &gt; CI/CD &gt; General Pipelines</strong> and in the <strong>Test Coverage Parsing</strong> field add the same regular expression that we used in the job <code>^\s*Lines:\s*\d+.\d+\%</code></p>
<h3 id="heading-test-coverage-badge">Test Coverage Badge</h3>
<p>Navigate to <strong>Settings &gt; General Settings &gt; Badges</strong> and click <strong>Add Badge</strong> and fill the form as follows:</p>
<ul>
<li>Name: <strong>PHPUnit Coverage</strong></li>
<li>Link: <code>https://gitlab.com/[PROJECT_PATH]/-/commits/[BRANCH_NAME]</code></li>
<li>Badge Image URL: <code>https://gitlab.com/[PROJECT_PATH]/badges/[BRANCH_NAME]/coverage.svg</code></li>
</ul>
<h3 id="heading-result">Result</h3>
<ul>
<li>You can see a test report in your pipeline</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uyq4kyaz9xaxe199trw2.png" alt="Image description" /></p>
<ul>
<li>Navigate to <strong>Analytics &gt; Repository &gt; Code Coverage Statistics</strong> to see the history of test coverage</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zcctqbj8x4ohllf0zb8q.png" alt="Image description" /></p>
<ul>
<li>The effect of each merge request on the test coverage can be found in the merge request overview page.</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2c4fc5rz1kwzl95gv896.png" alt="Image description" /></p>
]]></content:encoded></item><item><title><![CDATA[Laravel Static Code Analysis with PHPStan]]></title><description><![CDATA[Code analysis is the process of testing and evaluating a program either statically or dynamically.
Dynamic analysis is the process of testing and evaluating a program — while the software is running. It addresses the diagnosis and correction of bugs,...]]></description><link>https://muhamadhhassan.me/laravel-static-code-analysis-with-phpstan</link><guid isPermaLink="true">https://muhamadhhassan.me/laravel-static-code-analysis-with-phpstan</guid><category><![CDATA[Laravel]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[PHP]]></category><category><![CDATA[ci-cd]]></category><dc:creator><![CDATA[Muhamad Hassan]]></dc:creator><pubDate>Sat, 26 Feb 2022 21:42:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1651959256366/omUNipTzX.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Code analysis is the process of testing and evaluating a program either statically or dynamically.</p>
<p>Dynamic analysis is the process of testing and evaluating a program — while the 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.</p>
<p>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 provides an automated feedback loop so the developers will know early on which in turn make it easier, and cheaper, to fix those problems.</p>
<hr />
<h2 id="heading-code-analysis-jargons">Code Analysis Jargons</h2>
<p>Before moving to PHPStan, or any other tool, we need to be familiar with the terms that are commonly used in the code analysis world. You can also think of them as what the tools will be looking for in your software.</p>
<h3 id="heading-measurements">Measurements</h3>
<p><strong>- Naming</strong> Checking if variables and methods’ names, are they too short or too long? Do they follow a naming convention like camel-case?</p>
<p><strong>- Type Hinting</strong> Some tools can suggest a name consistent with the return type. For example a <code>getFoo()</code> method that returns a <code>boolean</code> is better be named <code>isFoo()</code>.</p>
<p><strong>- Lines of Code</strong> 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.</p>
<p><strong>- Commented Code</strong> 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.</p>
<p><strong>- Return Statements</strong> How many return statements do you have throughout your method? Many return statements make it difficult to understand the method.</p>
<p><strong>- Return Types</strong> Makes sure that the return type matches the expected. Having many return types possibilities confuses the analyzers.</p>
<h3 id="heading-code-structure">Code Structure</h3>
<p><strong>- Dedicated Exceptions</strong> Ensure the use of dedicated exceptions, instead of generic run-time exceptions, that can be cached by client code.</p>
<p><strong>- No Static Calls</strong> Avoid using static calls in your code and instead use dependency injection. Factory methods are the only exception.</p>
<p><strong>- DRY</strong> Checks for code duplication either in repeating literal values or whole blocks of code.</p>
<h3 id="heading-complexity">Complexity</h3>
<p>Having a lot of control structures in one method AKA the pyramid of doom. Possible fixes include:</p>
<ul>
<li><p>Early return statements</p>
</li>
<li><p>Merging nested if statements in combination with helper functions that make the condition readable</p>
</li>
</ul>
<h3 id="heading-security-issues">Security Issues</h3>
<p><strong>- Cipher Algorithms</strong> Ensure the use of cryptographic systems resistant to cryptanalysis, which are not vulnerable to well-known attacks like brute force attacks for example.</p>
<p><strong>- Cookies</strong> Always create sensitive cookies with the “secure” flag so it’s not sent over an unencrypted HTTP request.</p>
<p><strong>- Dynamic Execution</strong> 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.</p>
<hr />
<h2 id="heading-what-does-phpstan-bring">What Does <em>PHPStan</em> Bring?</h2>
<h3 id="heading-running-phpstan-for-the-first-time">Running <em>PHPStan</em> for the First Time</h3>
<p>I have been using <em>SonarQube</em> for a quite long time but when I first came across <em>PHPStan</em> <a target="_blank" href="https://github.com/phpstan/phpstan">repo</a> I found this arguable claim...</p>
<blockquote>
<p><em>PHPStan</em> 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. So to put it to the test, I installed <em>PHPStan</em> in an application that has been analyzed with <em>SonarQube</em> since day one and the results were impressive</p>
</blockquote>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ptzmjgtlmnfdd01rbjfe.png" alt="Image Test results" /></p>
<p><em>PHPStan</em> 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.</p>
<h3 id="heading-rule-levels">Rule Levels</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Level</td><td>Name</td><td>Details</td></tr>
</thead>
<tbody>
<tr>
<td>00</td><td>Basic Checks</td><td>Checks for Unknown classes, unknown functions, unknown methods called on $this, wrong number of arguments passed to those methods and functions, always undefined variables.</td></tr>
<tr>
<td>01</td><td><code>$this</code> Unknowns</td><td>Possibly undefined variables, unknown magic methods and properties on classes with <code>__call</code> and <code>__get</code>.</td></tr>
<tr>
<td>02</td><td>Methods</td><td>Unknown methods checked on all expressions (not just <code>$this</code>), validating <em>PHPDocs.</em></td></tr>
<tr>
<td>03</td><td>Types</td><td>Checks for return types, types assigned to properties.</td></tr>
<tr>
<td>04</td><td>Dead Code</td><td>Basic dead code checking - always false <code>instanceof</code> and other type checks, dead <code>else</code> branches, unreachable code after <code>return</code>; etc.</td></tr>
<tr>
<td>05</td><td>Arguments</td><td>Checking types of arguments passed to methods and functions.</td></tr>
<tr>
<td>06</td><td>Type Hints</td><td>Reports missing type hints.</td></tr>
<tr>
<td>07</td><td>Union Types</td><td>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.</td></tr>
<tr>
<td>08</td><td>Nullable Types</td><td>Report calling methods and accessing properties on nullable types.</td></tr>
<tr>
<td>09</td><td>Mixed Type</td><td>Be very strict about the mixed type, the only allowed operation you can do with it is to pass it to another mixed.</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-how-to-use-phpstan">How to Use <em>PHPStan</em>?</h2>
<h3 id="heading-installation">Installation</h3>
<p>To use <em>PHPStan</em> with Laravel we are going to use <a target="_blank" href="https://github.com/nunomaduro/larastan">Larastan</a> extension. <a target="_blank" href="https://phpstan.org/user-guide/extension-library#installing-extensions">Extensions</a> are useful when there are subjective bugs or to accommodate to a certain framework while taking advantage of <em>PHPStan</em> capabilities.</p>
<ol>
<li><p>First, we install the package with composer</p>
<pre><code class="lang-bash"> composer require nunomaduro/larastan:^2.0 --dev
</code></pre>
</li>
</ol>
<blockquote>
<p>Note: This version requires PHP 8.0+ and Laravel 9.0+</p>
</blockquote>
<ol>
<li><p>Then you can start analyzing your code with the console command using the default configuration of <em>PHPStan</em></p>
<pre><code class="lang-bash"> ./vendor/bin/phpstan analyse app --memory-limit=25
</code></pre>
<p> Here we specified the path that we want to analyze <code>app</code> and the memory limit <code>25</code> MB. You can find all the options of the command line <a target="_blank" href="https://phpstan.org/user-guide/command-line-usage">here</a>.</p>
</li>
</ol>
<h3 id="heading-configuration-file">Configuration File</h3>
<p><em>PHPStan</em> uses a configuration file, <code>phpstan.neon</code> or <code>phpstan.neon.dist</code>, that allows you to:</p>
<ul>
<li><p>Define the paths that will be analyzed.</p>
</li>
<li><p>Set the rule level.</p>
</li>
<li><p>Exclude paths.</p>
</li>
<li><p>Include <em>PHPStan</em> extensions.</p>
</li>
<li><p>Ignore errors.</p>
</li>
<li><p>Define the maximum number of parallel processes</p>
</li>
</ul>
<p>Here is an example of a simple configuration file that by default lives in the root directory of your application but you can learn more from the configuration <a target="_blank" href="https://phpstan.org/config-reference">reference</a>.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">includes:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">./vendor/nunomaduro/larastan/extension.neon</span>

<span class="hljs-attr">parameters:</span>

    <span class="hljs-attr">paths:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">app</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">config</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">database</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">routes</span>

    <span class="hljs-comment"># The level 9 is the highest level</span>
    <span class="hljs-attr">level:</span> <span class="hljs-number">5</span>

    <span class="hljs-attr">ignoreErrors:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">'#PHPDoc tag @var#'</span>

    <span class="hljs-attr">parallel:</span>
        <span class="hljs-attr">maximumNumberOfProcesses:</span> <span class="hljs-number">4</span>

    <span class="hljs-attr">noUnnecessaryCollectionCall:</span> <span class="hljs-literal">false</span>
    <span class="hljs-attr">checkMissingIterableValueType:</span> <span class="hljs-literal">false</span>
</code></pre>
<h3 id="heading-ignoring-errors">Ignoring Errors</h3>
<p>Most probably, you are going to need to ignore some errors which are luckily allowed in two different ways:</p>
<ol>
<li><p>Inline using <em>PHPDoc</em> tags</p>
<pre><code class="lang-php"> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
     <span class="hljs-comment">/** <span class="hljs-doctag">@phpstan</span>-ignore-next-line */</span>
     <span class="hljs-keyword">echo</span> $foo;

     <span class="hljs-keyword">echo</span> $bar <span class="hljs-comment">/** <span class="hljs-doctag">@phpstan</span>-ignore-line */</span>
 }
</code></pre>
</li>
<li><p>From the configuration file and this is more clean</p>
<pre><code class="lang-yaml">   <span class="hljs-attr">parameters:</span>

       <span class="hljs-attr">ignoreErrors:</span>

           <span class="hljs-bullet">-</span>
               <span class="hljs-attr">message:</span> <span class="hljs-string">'Access to an  undefined property [a-zA-Z0-9\_]+::\$foo'</span>
               <span class="hljs-attr">path:</span> <span class="hljs-string">some/dir/someFile.php</span>
           <span class="hljs-bullet">-</span>
               <span class="hljs-attr">message:</span> <span class="hljs-string">'#Call to an undefined method [a-zA-Z0-9\_]+::doFoo()#'</span>
               <span class="hljs-attr">path:</span> <span class="hljs-string">other/dir/DifferentFile.php</span>
               <span class="hljs-attr">count:</span> <span class="hljs-number">2</span> <span class="hljs-comment"># optional, and it will ignore the first two occurances of the error</span>
           <span class="hljs-bullet">-</span>
               <span class="hljs-attr">message:</span> <span class="hljs-string">'#Call to an undefined method [a-zA-Z0-9\_]+::doBar()#'</span>
               <span class="hljs-attr">paths:</span>
                   <span class="hljs-bullet">-</span> <span class="hljs-string">some/dir/*</span>
                   <span class="hljs-bullet">-</span> <span class="hljs-string">other/dir/*</span>
</code></pre>
</li>
</ol>
<h3 id="heading-the-baseline">The Baseline</h3>
<p>Introducing <em>PHPStan</em> to the CI pipeline, increasing the strictness level or upgrading to a newer version can be overwhelming. <em>PHPStan</em> allows you to declare the currently reported list of errors as <em>“the baseline”</em> and stop reporting them in subsequent runs. It allows you to be interested in violations only in new and changed code.</p>
<p>If you want to export the current list of errors and use it as the baseline, run <em>PHPStan</em> with <code>--generate-baseline</code> option</p>
<pre><code class="lang-bash">./vendor/bin/phpstan analyse --memory-limit=25 --generate-base
</code></pre>
<blockquote>
<p>Note: We dropped the path option from the example in <a target="_blank" href="https://outline.robustastudio.com/doc/laravel-static-code-analysis-with-phpstan-oxyQT0wo3v/edit#h-installation">installation</a> as it is now being set in the config file.</p>
</blockquote>
<p>It will generate the list of errors with the number of occurrences per file and saves it in <code>phpstan-baseline.neon</code>. Finally, we add the baseline file to our <code>includes</code></p>
<pre><code class="lang-yaml"><span class="hljs-attr">includes:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">./vendor/nunomaduro/larastan/extension.neon</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">phpstan-baseline.neon</span>
</code></pre>
<h3 id="heading-adding-phpstan-to-your-cicd">Adding <em>PHPStan</em> to Your CI/CD</h3>
<p>Adding <em>PHPStan</em> 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.</p>
<p>Embed this snippet in your <code>gitlab-ci.yml</code> 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.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">stages:</span> 
  <span class="hljs-bullet">-</span> <span class="hljs-string">staticanalysis</span> <span class="hljs-bullet">-</span> 

<span class="hljs-attr">phpstan:</span>
  <span class="hljs-attr">stage:</span> <span class="hljs-string">staticanalysis</span>
  <span class="hljs-attr">image:</span> <span class="hljs-string">composer</span>
  <span class="hljs-attr">before_script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">composer</span> <span class="hljs-string">require</span> <span class="hljs-string">nunomaduro/larastan:1.0.2</span> <span class="hljs-string">--dev</span> <span class="hljs-string">--no-plugins</span> <span class="hljs-string">--no-interaction</span> <span class="hljs-string">--no-scripts</span> <span class="hljs-string">--prefer-dist</span> <span class="hljs-string">--ignore-platform-reqs</span>
  <span class="hljs-attr">script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">vendor/bin/phpstan</span> <span class="hljs-string">analyse</span> <span class="hljs-string">--no-progress</span> <span class="hljs-string">--error-format</span> <span class="hljs-string">gitlab</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">phpstan.json</span>
  <span class="hljs-attr">cache:</span>
    <span class="hljs-attr">key:</span> <span class="hljs-string">${CI_COMMIT_REF_SLUG}-composer-larastan</span>
    <span class="hljs-attr">paths:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">vendor/</span>
  <span class="hljs-attr">artifacts:</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">reports:</span>
      <span class="hljs-attr">codequality:</span> <span class="hljs-string">phpstan.json</span>
  <span class="hljs-attr">allow_failure:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">dependencies:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">php-cs-fixer</span>
  <span class="hljs-attr">needs:</span> 
    <span class="hljs-bullet">-</span> <span class="hljs-string">php-cs-fixer</span>
  <span class="hljs-attr">only:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">master</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">develop</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">/^release\/[0-9]+.[0-9]+.[0-9]$/</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">/^hotfix\/[0-9]+.[0-9]+.[0-9]$/</span>
</code></pre>
<hr />
<h2 id="heading-limitations-of-static-analysis">Limitations of Static Analysis</h2>
<p>Static analysis is not a substitute for testing, they are different tools targeting different domains in the development lifecycle, and it has some limitations:</p>
<ul>
<li><p>No Understanding of Developer Intent</p>
<pre><code class="lang-php">  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateArea</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> $length, <span class="hljs-keyword">int</span> $width</span>): <span class="hljs-title">int</span>
  </span>{
      $area = $length + $width;

      <span class="hljs-keyword">return</span>;
  }
</code></pre>
<p>  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!</p>
</li>
<li><p>Some rules are subjective depending on the context.</p>
</li>
<li><p>False Positives and False Negatives.</p>
</li>
</ul>
<hr />
<h2 id="heading-helpful-links">Helpful Links</h2>
<ul>
<li><p><a target="_blank" href="https://github.com/nunomaduro/larastan/blob/master/docs/rules.md#NoUnnecessaryCollectionCall">Laravel-specific rules</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/nunomaduro/larastan/blob/master/docs/errors-to-ignore.md">Errors to ignore</a></p>
</li>
<li><p><a target="_blank" href="https://phpstan.org/writing-php-code/phpdocs-basics"><em>PHPDocs</em> usage with <em>PHPStan</em></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/analysis-tools-dev">List of analysis tools for different languages</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>