<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <atom:link href="https://ryangjchandler.co.uk/feed" rel="self" type="application/rss+xml" />
        <title><![CDATA[Ryan Chandler]]></title>
        <link><![CDATA[https://ryangjchandler.co.uk/feed]]></link>
        <image>
            <url>https://ryangjchandler.co.uk/favicon.jpg</url>
            <title><![CDATA[Ryan Chandler]]></title>
            <link><![CDATA[https://ryangjchandler.co.uk/feed]]></link>
        </image>
        <description><![CDATA[Latest blog posts from Ryan Chandler.]]></description>
        <language>en-GB</language>
        <pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate>

                    <item>
                <title><![CDATA[Writing code that feels native to Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/writing-code-that-feels-native-to-laravel</link>
                <description><![CDATA[<p>Once you become familiar with Laravel, certain patterns start to stand out. Classes get resolved out of the container through facades, you can swap out instances inside of tests, entry points are predictable, configuration lives in familiar places.</p>
<p>Laravel does this on purpose, it's all about convention. Consistency is probably the framework's strongest selling point.</p>
<p>When a new feature gets introduced to the framework it tends to feel natural because it follows the same patterns. You don't necessarily have to think about what a method <em>might</em> be called, or where it belongs, or even how it works. It just integrates nicely alongside the rest of your code and behaves in the way you expect.</p>
<p>I think that this same idea can be applied to, and ultimately shape, your application code.</p>
<p>I'll give you an example. Laravel has <a href="https://laravel.com/docs/13.x/facades">facades</a> (tl;dr static proxies that resolve their underlying classes from the container) and those facades can be &quot;faked&quot; inside of tests, essentially swapping out the real instance for a testable, mocked one.</p>
<p>There's no reason you can't apply this same pattern to your own service classes.</p>
<p>If your service classes are resolved through the container, they become trivial to replace during tests. Pull out a shared interface or contract, implement that for the real service implementation and then create a &quot;fake&quot; version of the service class that can be used inside of your tests. That fake version could use mocks and provide useful testing helpers, or simply do nothing and be mocked itself.</p>
<p>Go a step further and let your testing code leak into your production code by adding a static <code>fake()</code> method to the real class that just swaps the bound instance in the container.</p>
<p>The benefit isn't just clearer tests, it's consistency. You would use a fake version of a Laravel class in your test, so why shouldn't you use a fake version of your own class?</p>
<p>The same logic can be applied to entry points. Jobs use a <code>handle</code> method, middleware uses a <code>handle</code> method, listeners use a <code>handle</code> method. The convention makes these classes predictable to write.</p>
<p>If you're using the action class pattern, give those classes a <code>handle</code> method instead of an <code>__invoke</code> or <code>execute</code> method so that they align with the rest of the framework. It becomes easy to reason about, easy to swap, and easy to compose with things like pipelines or decorators later on.</p>
<p>The broader idea here is to lean on the same conventions that Laravel has already established.</p>
<p>When your application code follows those patterns, it starts to feel like a part of the framework itself. Other developers don't necessarily need to learn your complex architecture, they can rely on what they already know about Laravel.</p>
<p>This might not be something that you apply to all classes in your application, but when you're introducing a service, action, or subsystem, it's worth considering.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Overcoming AI anxiety]]></title>
                <link>https://ryangjchandler.co.uk/posts/overcoming-ai-anxiety</link>
                <description><![CDATA[<p>Writing code pays my bills. It also happens to be a hobby that I was fortunate enough to turn into a career. The satisfaction of solving a problem, the concept of building something from nothing, the small wins that add up over time, the sense of accomplishment. That's what I enjoy.</p>
<p>For the longest time that felt like a stable foundation. If you could write good code and build solid software, there would always be a place for you somewhere.</p>
<p>Enter AI.</p>
<p>At first it was tab completions. Little suggestions inside of my editor that gave me a little productivity boost, not too different from a language server providing me with smart and sensible completions for variables and types. Easy to accept with a <code>Tab</code>, easy to ignore with an <code>Esc</code>. It felt incremental.</p>
<p>Then it stopped feeling incremental. Those small suggestions turned into entire functions, entire classes. You soon realise you're not writing every line of code and you're no longer engaging with your code in the same way. You move from construction to curation, spending more time reading, steering and second-guessing.</p>
<p>That's where my unease started. Unease is probably a poor choice of word because the tooling is reliable, often remarkably capable, and almost as good as you (sometimes better to be honest).</p>
<p>My own &quot;anxiety&quot; around AI wasn’t really fear of the technology itself. It was the realisation that something fundamental about the way I work was shifting. I wasn't building things up piece-by-piece in the same way anymore. I was merely an evaluation engine and guidance counsellor for a &quot;clanker&quot;.</p>
<p>Once you sit with that for a while, you start to ask the hard questions.</p>
<p>&quot;If this thing can write most of the code, what value do I add?&quot;</p>
<p>&quot;If I'm not the one writing the code for every solution, will I lose touch?&quot;</p>
<p>And perhaps more quitely, &quot;If this keeps improving at the same rate, where does that leave me in X years?&quot;.</p>
<p>I didn't really have answers for those questions immediately and that's where the &quot;anxiety&quot; really lingers.</p>
<p>It was only once I had truly integrated these tools into my day-to-day work that I started to see the obvious boundaries and form real answers.</p>
<p>AI generates code, but it doesn't <em>truly</em> understand the intent. It doesn’t always have the context to take a real problem in your system and map it to an outcome. You're the one who bridges that gap. It follows patterns and guidelines that <strong>you</strong> provide, but it doesn’t own the consequences of those choices. It can suggest a solution, but only to the problem <strong>you’ve</strong> framed.</p>
<p>That distinction is what matters. The responsibility of software design and software engineering hasn't moved. You're still the one deciding what to build, why it matters, and whether the solution is actually correct. Not just syntactically, but architecturally and contextually.</p>
<p>The AI accelerates your execution, it doesn't replace your brain and your judgment. Once that clicks, those questions start to feel a little less open-ended and existential.</p>
<p>To leave you with a more poetic outro:</p>
<p>Your value as a software engineer isn't in writing every single line of code, it's knowing which lines should exist at all.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 26 Mar 2026 17:30:00 +0000</pubDate>
                                    <category>Thoughts</category>
                            </item>
                    <item>
                <title><![CDATA[Quickly deploy your Forge site from the terminal]]></title>
                <link>https://ryangjchandler.co.uk/posts/quickly-deploy-your-forge-site-from-the-terminal</link>
                <description><![CDATA[<p><a href="https://forge.laravel.com">Forge</a> is the way that I deploy most of my projects but I've never been a big user of the <a href="https://forge.laravel.com/docs/cli">official CLI</a>.</p>
<p>I instead use a Bash script to deploy my sites from the terminal. I figured it could be useful for somebody else so here's my script.</p>
<pre><code class="language-bash">#!/usr/bin/env bash

echo &quot;Deploying...&quot;

# You can get this from the &quot;Deployments&quot; page in your site settings.
FORGE_DEPLOY_URL=&quot;https://forge.laravel.com/servers/&lt;SERVER_ID&gt;/sites/&lt;SITE_ID&gt;/deploy/http?token=&lt;TOKEN&gt;&quot;
FORGE_DEPLOY_COMMIT=$(git rev-parse HEAD)
FORGE_DEPLOY_MESSAGE=$(git log -1 --pretty=%B | xargs)
FORGE_DEPLOY_AUTHOR=&quot;Ryan Chandler&quot;

curl -X POST $FORGE_DEPLOY_URL \
    -H &quot;Content-Type: application/x-www-form-urlencoded&quot; \
    -d &quot;forge_deploy_commit=${FORGE_DEPLOY_COMMIT}&amp;forge_deploy_author=${FORGE_DEPLOY_AUTHOR}&amp;forge_deploy_message=${FORGE_DEPLOY_MESSAGE}&quot;

echo &quot;Deployment request submitted.&quot;
</code></pre>
<p>The nice part is that you can still specify the Git details for the deployment!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Easy Stripe webhook testing with Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/easy-stripe-webhook-testing-with-laravel</link>
                <description><![CDATA[<p>I've been working on a couple of new side projects recently and integrating with Stripe is super simple thanks to <a href="https://laravel.com/docs/12.x/billing">Cashier</a>.</p>
<p>Testing webhooks locally normally means using the Stripe CLI and that involves a couple of options to make sure it's configured correctly for your Laravel application and also proxying those webhooks to the correct endpoint.</p>
<p>One of the handiest scripts I used whilst working on <a href="https://forge.laravel.com">Forge</a> was a tiny Bash script that configures the Stripe CLI based on your <code>.env</code> file automatically.</p>
<pre><code class="language-bash">#!/usr/bin/env bash

set -euo pipefail

APP_URL=&quot;$(awk -F '=' '/^APP_URL/{gsub(/&quot;/, &quot;&quot;, $2); print $2}' .env)&quot;
STRIPE_SECRET=&quot;$(awk -F '=' '/^STRIPE_SECRET/{gsub(/&quot;/, &quot;&quot;, $2); print $2}' .env)&quot;

stripe listen -f &quot;$APP_URL/stripe/webhook&quot; --api-key=&quot;$STRIPE_SECRET&quot;
</code></pre>
<p>As long as you've got the <code>awk</code> utility on your system, you should be good to add this to your project somewhere and execute it when need be.</p>
<pre><code class="language-bash">chmod +x ./bin/stripe.sh
./stripe.sh
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[2025: A year in review]]></title>
                <link>https://ryangjchandler.co.uk/posts/2025-a-year-in-review</link>
                <description><![CDATA[<p>2025 has officially ended and we are now in 2026. As I've done for the last 6 years, here is a blog post reviewing my year and looking ahead into the next.</p>
<h3>Open source</h3>
<p>Just like the last couple of years, the open source side of things has been pretty quiet. I'm still maintaining my packages and keeping them in check.</p>
<p>The biggest thing I worked on open source wise is definitely <a href="https://phiki.dev">Phiki 2.0</a>.</p>
<p>It was a complete rewrite of the internals and got everything almost perfect compared to Shiki and <code>vscode-textmate</code>. I'm super happy with how it turned out and glad that PHP developers are able to get super clean syntax highlighting without all of the faff that comes with JavaScript pacakges.</p>
<p>On a slightly more somber note, I archived the PXP project in March 2025. I spoke about how I wanted to revive the project in the last end of year review and that was the intention, but I quickly realised that a project of that size wouldn't be the best thing to work on whilst also pumping out tonnes of cool <a href="https://laravel.com/blog/what-to-expect-in-the-next-generation-of-laravel-forge">Forge</a> stuff at <a href="https://laravel.com">Laravel</a>.</p>
<h3>Content Creation</h3>
<p>Not including this post, I've written 12 blog posts for this site. Another slow year on the blog, but I'm happy with the things I've posted.</p>
<p>I <a href="https://www.youtube.com/@ryangjchandler">published a few videos too</a> on random bits and bobs, but not as many as I would've liked.</p>
<h3>Conferences</h3>
<p>I attended a few conferences in 2025.</p>
<ul>
<li>Laracon EU (Speaker)</li>
<li>Laravel Live UK (Sponsor)</li>
<li>Laracon US</li>
<li>Laravel Live DK</li>
<li>wire:live (Speaker)</li>
</ul>
<p>They were all excellent events. It was my first year as a Laravel employee which allowed me to attend more events than I usually would which I'm super grateful for.</p>
<h3>Work</h3>
<p>What a year it has been. I started at Laravel in January and immediately dove straight in to work on the next-generation of <a href="https://forge.laravel.com">Forge</a>.</p>
<p>It was great to work with a team of super talented developers, designers, and project managers. The launch went about as well as it could have and we were all super proud of what we had achieved in such a small amount of time.</p>
<h3>Looking at 2026</h3>
<p>2026 is an interesting year. I've officially moved on from the Forge (core services) team and will be working on <a href="https://cloud.laravel.com">Cloud</a> for the foreseeable future.</p>
<p>It's definitely a switch up from Forge and I can't wait to get into all of the nitty-gritty that comes with cloud platforms.</p>
<p>I'm sad to be leaving the Forge team but I absolutely believe that they'll continue to smash it.</p>
<p>I'm also working on a new SaaS product for PHP developers, specifically those of you who want to monetize your work. It's called Privato and will be launching in the next month or so.</p>
<p>You pay a flat monthly fee for the platform, bring your own Stripe account and Privato takes care of the rest. No fees per purchase or anything, a single monthly payment instead.</p>
<p>I'll keep it short this year and let you carry on with your 2026 celebrations.</p>
<p>Happy New Year!</p>
<p>Ryan</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[How to download a website for offline viewing with wget]]></title>
                <link>https://ryangjchandler.co.uk/posts/how-to-download-a-website-for-offline-viewing-with-wget</link>
                <description><![CDATA[<p>I've been on my fair share of flights recently and as we all know, the Wi-Fi is a little hit or miss. It is getting better thanks to Starlink but it still isn't 100% reliable.</p>
<p>I wanted to get some things done on a plane and one of my most visited websites is <a href="https://laravel.com">laravel.com</a>. Despite being a Laravel developer and an engineer <em>at</em> Laravel, there are still things that I have to lookup sometimes: validation rules, collection method names, and more.</p>
<p>So I decided to download the entire Laravel website to my machine so that I could serve it using a local web server. It turns out this is super easy to do with <a href="https://linux.die.net/man/1/wget"><code>wget</code></a>.</p>
<p>If you haven't got <code>wget</code> installed already, you can use <code>brew</code> on macOS to install it.</p>
<pre><code class="language-sh">brew install wget
</code></pre>
<p>Once you've got it installed you can use the following command to download a copy of a website for offline viewing, including frontend assets and child pages.</p>
<pre><code class="language-sh">wget --mirror --convert-links --adjust-extension --page-requisites --no-parent &lt;url&gt;
</code></pre>
<p>I only wanted the latest Laravel docs so I ran the following command:</p>
<pre><code class="language-sh">wget --mirror --convert-links --adjust-extension --page-requisites --no-parent https://laravel.com/docs/12.x
</code></pre>
<p>This created a <code>laravel.com</code> directory in the same one as the command was run. You can then serve this directory using a local web server such as <code>php -S localhost:8000</code>.</p>
<p>If you want to wrap this up into a nice little shell command / helper, you can add the following to your <code>.zshrc</code> (or equivalent):</p>
<pre><code class="language-zsh">offline-copy() {
    wget --mirror --convert-links --adjust-extension --page-requisites --no-parent &quot;$@&quot;
}
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 04 Dec 2025 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Creating custom Facade fakes in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/creating-custom-facade-fakes-in-laravel</link>
                <description><![CDATA[<p>I recently released a new version of my <a href="https://github.com/ryangjchandler/laravel-cloudflare-turnstile/">Cloudflare Turnstile package for Laravel</a>.</p>
<p>One of the features I added was the ability to test your Turnstile integrations using a fake implementation of the Turnstile client.</p>
<pre><code class="language-php">it('validates data', function () {
    Turnstile::fake(); [code! focus]
});
</code></pre>
<p>Under the hood, the package uses a custom Facade to call methods on the Turnstile client. This facade binds to a <code>ClientInterface</code> implemented by the concrete <code>Client</code> class as well as the <code>FakeClient</code> class.</p>
<pre><code class="language-php">class Turnstile extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return ClientInterface::class;
    }
}
</code></pre>
<p>The concrete <code>Client</code> class is then bound to the <code>ClientInterface</code> through the service container.</p>
<pre><code class="language-php">$this-&gt;app-&gt;scoped(ClientInterface::class, static function (Application $app): Client {
    return new Client($app['config']-&gt;get('services.turnstile.secret'));
});
</code></pre>
<p>The power of the interface here is that it allows us to easily swap out the implementation with a <code>FakeClient</code> class when testing.</p>
<p>To achieve this, I added a <code>fake()</code> method to the <code>Turnstile</code> facade that calls the <code>Facade</code> class's <code>static::swap()</code> method.</p>
<pre><code class="language-php">class Turnstile extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return ClientInterface::class;
    }

    public static function fake(): FakeClient // [code! focus:start]
    {
        static::swap($fake = new FakeClient);

        return $fake;
    } // [code! focus:end]
}
</code></pre>
<p>The <code>swap()</code> method itself does some work under the hood to replace the resolved instance of the facade itself with the provided fake implementation, but also overwrites the binding in the service container so that any subsequent calls
to the facade or any bindings to <code>ClientInterface</code> will return the fake implementation.</p>
<p>This allows us to easily stub out the Turnstile methods that are called by the package and provide clean, Laravel-esque APIs for testing.</p>
<pre><code class="language-php">Turnstile::fake(); // Force pass.
Turnstile::fake()-&gt;fail(); // Force fail.
Turnstile::fake()-&gt;expired(); // Force expired.
</code></pre>
<p>Why not give this a go in your own applications and packages? Future you will thank you for the improved developer experience and reduced boilerplate code!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 05 Nov 2025 19:37:48 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[npm ci vs npm install]]></title>
                <link>https://ryangjchandler.co.uk/posts/npm-ci-vs-npm-install</link>
                <description><![CDATA[<p>When working on a JavaScript project, there are two common commands that are used to install dependencies: <code>npm install</code> and <code>npm ci</code>. While they seem similar, they serve different purposes and can have an impact on your workflow.</p>
<h2>npm install</h2>
<p><code>npm install</code> installs dependencies listed inside of <code>package.json</code>.</p>
<p>If the version that gets installed is different to the version found inside of your <code>package-lock.json</code> file, then it will update the <code>package-lock.json</code> with the version. This can lead to variations in different environments and unexpected version bumps as part of your changes.</p>
<p>It's flexible, but can be problematic. I'd only recommend using this command <strong>when installing a new package</strong> in your project.</p>
<h2>npm ci</h2>
<p><code>npm ci</code> will install the exact version of a package from the <code>package-lock.json</code> file. This is great as you can guarantee that the version you have installed is the same as your <code>main</code> branch and the rest of your team (assuming they also use <code>npm ci</code>).</p>
<p>If the <code>package-lock.json</code> file is out of sync with the <code>package.json</code> file, the command will fail to run to be certain that it is installing the correct thing.</p>
<p>This command is more deterministic and I'd recommend this when setting up a new project from Git, updating your local environment and checking you've got the right dependencies, or in CI where you normally see a good performance boost compared to <code>npm install</code>.</p>
<h2>When to use each</h2>
<p>To summarise the above:</p>
<ul>
<li><code>npm install</code> should be used when you want to install or update a package.</li>
<li><code>npm ci</code> should be used to install dependencies from scratch, in CI/CD pipelines and for production builds where consistency and determinism is crucial.</li>
</ul>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 22 Sep 2025 00:00:00 +0000</pubDate>
                                    <category>JavaScript</category>
                            </item>
                    <item>
                <title><![CDATA[My minimal Ghostty config]]></title>
                <link>https://ryangjchandler.co.uk/posts/my-minimal-ghostty-config</link>
                <description><![CDATA[<p>I've been using Ghostty as my main terminal for a week or so at this point (late to the party, I know!).</p>
<p>I like to keep my tools fairly minimalistic, but consistent. That normally means:</p>
<ul>
<li>A light theme</li>
<li>A nice monospace font</li>
<li>Breathing room between lines and the window</li>
</ul>
<p>Ghostty's configuration system is insanely simple, especially compared to iTerm's deeply nested input fields. Here's my config and a screenshot for reference.</p>
<pre><code class="language-ini">theme = GitHub Light Default

font-family = JetBrains Mono
font-size = 14
font-thicken = true
font-feature = -liga

adjust-cell-height = 20 

window-padding-x = 20
window-padding-y = 20
</code></pre>
<figure>
    <img src="https://ryangjchandler.co.uk/build/assets/ghostty-config-sep-16-CIiDgITa.png" alt="" class="border dark:border-neutral-700 shadow-xs">
    <figcaption>A screenshot of my Ghostty terminal window, slightly zoomed in for better viewability.</figcaption>
</figure>

]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 15 Sep 2025 00:00:00 +0000</pubDate>
                                    <category>Tooling</category>
                            </item>
                    <item>
                <title><![CDATA[Enabling WAL mode with SQLite in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/enabling-wal-mode-with-sqlite-in-laravel</link>
                <description><![CDATA[<p>SQLite's WAL (Write-ahead Logging) mode improves the reliability and performance of SQLite databases by changing where data is written to.</p>
<p>Instead of writing changes directly to the <code>database.sqlite</code> file, they instead get written to a separate log file first. That log file then gets merged into the main file in one go, allowing you to write without blocking reads from the database.</p>
<p>It's <em>really</em> easy to enable this mode in Laravel!</p>
<p>You just need to update the <code>journal_mode</code> configuration value for SQLite databases inside of the <code>database.php</code> config file, setting it to <code>WAL</code>.</p>
<pre><code class="language-php">return [

    //...
    
    'connections' =&gt; [

        'sqlite' =&gt; [
            'driver' =&gt; 'sqlite',
            'url' =&gt; env('DB_URL'),
            'database' =&gt; env('DB_DATABASE', database_path('database.sqlite')),
            'prefix' =&gt; '',
            'foreign_key_constraints' =&gt; env('DB_FOREIGN_KEYS', true),
            'busy_timeout' =&gt; null,
            'journal_mode' =&gt; 'WAL',
            'synchronous' =&gt; null,
        ],

        // ...

    ],

];
</code></pre>
<p>When Laravel creates the SQLite database connection, it will run <code>PRAGMA journal_mode=WAL</code> and all of your database writes will use the separate log file instead.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 07 Aug 2025 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Build your own software]]></title>
                <link>https://ryangjchandler.co.uk/posts/build-your-own-software</link>
                <description><![CDATA[<p>You should build your own software. It's one of the most effective ways of growing as a developer, even if you're just building small, personal tools.</p>
<p>Early in the software development journey we're often curious – &quot;how does X work?&quot;, &quot;why does Y do this specific thing?&quot;, etc. Once we start working full-time and spend less time exploring things, that aspect of software development tends to fade away. Building your own software encourages that curiosity, since you have full-control over the journey. You don't need to worry about deadlines, team dynamics, or processes. You can experiment with new languages, frameworks, patterns – whatever it is that you're curious about.</p>
<p>A common argument against building your own software is that reinventing the wheel is bad, that it's a waste of time. Building something that's already been built can be a deliberate way to learn. You'll figure out why things <em>need</em> to work the way they do, what tradeoffs exist, or where performance decisions come into play.</p>
<p>Building your own software also provides a tangible goal, since you're the one setting the expectations. You could build a simple to-do list application or the next Netflix, it doesn't matter. As long as it does what <em>you</em> need it to do, it's a success.</p>
<p>So start small. Build something that solves a problem you have. It doesn't need to be perfect. It doesn't need to be original. The goal isn't to ship the next big thing – it's to learn, explore and grow as a developer.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 27 Mar 2025 00:00:00 +0000</pubDate>
                                    <category>Thoughts</category>
                            </item>
                    <item>
                <title><![CDATA[Preventing scrollbar layout shifts]]></title>
                <link>https://ryangjchandler.co.uk/posts/preventing-scrollbar-layout-shifts</link>
                <description><![CDATA[<p>Have you ever been on a website and navigated between pages, only to notice that the layout shifts slightly because the scrollbar suddenly appears on longer pages?</p>
<p>I have, and it kind of bugs me. It turns out you can add a tiny bit of CSS to your website to prevent this from happening. Better yet? The CSS is actually supported in all major browsers.</p>
<pre><code class="language-css">html {
    scrollbar-gutter: stable;
}
</code></pre>
<hr />
<p>Here's a comparison between a page navigation with and without this bit of CSS.</p>
<p><strong>Without <code>scrollbar-gutter</code></strong></p>
<figure>
    <img src="https://ryangjchandler.co.uk/build/assets/without-D4lPtrJ0.gif" alt="" class="border dark:border-neutral-700 shadow-xs">
    <figcaption></figcaption>
</figure>

<p>Notice how the page shifts to the left when the scrollbar appears? Yuck!</p>
<p>That's caused by the scrollbar creating a fixed-width gutter which the page needs to account for when positioning and rendering.</p>
<p><strong>With <code>scrollbar-gutter</code></strong></p>
<figure>
    <img src="https://ryangjchandler.co.uk/build/assets/with-DSkmkAh_.gif" alt="" class="border dark:border-neutral-700 shadow-xs">
    <figcaption></figcaption>
</figure>

<p>The page no longer entirely shifts to the left to account for the scrollbar's fixed-width gutter. <em>Much</em> better!</p>
<p>(Ignore the navigation shifting around in this example, that's an unrelated issue and poor markup craftsmanship on my part)</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 21 Mar 2025 00:00:00 +0000</pubDate>
                                    <category>CSS</category>
                            </item>
                    <item>
                <title><![CDATA[Rusty string formatting in PHP]]></title>
                <link>https://ryangjchandler.co.uk/posts/rusty-string-formatting-in-php</link>
                <description><![CDATA[<p>As a PHP developer who likes to occasionally dabble in Rust, I find myself missing the developer experience of the <code>format!()</code> family of macros when I come back to writing PHP.</p>
<p>If you're not familiar with <code>format!()</code> or <code>print!()</code> macros in Rust, they're essentially the equivalent of PHP's <code>sprintf()</code> and <code>printf()</code>. The main difference between the two languages is that Rust's macros don't inherit the syntax of C's <code>sprintf()</code> where you have placeholders like <code>%s</code>, <code>%d</code>, etc. Instead you use <code>{}</code> as the placeholders and Rust will just convert the values to strings.</p>
<aside class="aside--right aside--context__note"><p>Rust doesn't implicitly convert <em>any</em> value to a string. The value does need to implement the <code>std::fmt::Display</code> trait for it to compile without errors.</p></aside>
<p>Here's an example of what it looks like:</p>
<pre><code class="language-rust">fn main() {
    let name = &quot;Ryan&quot;;

    println!(&quot;Hello, {}!&quot;, name);
}
</code></pre>
<p>So I've built a new package for PHP that offers the same sort of syntax – let me introduce you to <a href="https://github.com/ryangjchandler/f"><code>f</code></a>. The name <code>f</code> was inspired (read &quot;stolen&quot;) from Python, where &quot;f-strings&quot; are used to handle interpolation and inline formatting.</p>
<p>You can install the package using Composer:</p>
<pre><code class="language-sh">composer require ryangjchandler/f
</code></pre>
<p>It provides a global <code>f()</code> function that you can use to format a string.</p>
<pre><code class="language-php">$name = &quot;Ryan&quot;;

echo f(&quot;Hello, {}!&quot;, $name);
</code></pre>
<p>That's pretty close, right? Of course, that's a really simple and silly example because you could just use regular interpolation. Here are some comparisons between <code>f()</code> syntax and the equivalent <code>sprintf()</code> syntax provided by PHP.</p>
<hr />
<p><strong>Referencing positional arguments</strong></p>
<div x-data="{
    tabs: JSON.parse('[\u0022f\u0022,\u0022sprintf\u0022]'),
    activeTab: 'f',
}" class="prose-code-tabs">
    <div class="mx-4 flex items-center gap-x-2.5">
                    <button type="button" x-on:click="activeTab = 'f'" class="text-base px-4 p-1 rounded-t-lg bg-[#FAFAFA] min-w-10" x-bind:class="{
                'bg-[#FAFAFA] dark:bg-[#282c34] ring-2 ring-neutral-200/50 dark:ring-neutral-700/75': activeTab === 'f',
                'bg-[#FBFBFB] dark:bg-[#343841] hover:bg-[#F0F0F0] dark:hover:bg-[#1b1d21]': activeTab !== 'f',
            }">
                f
            </button>
                    <button type="button" x-on:click="activeTab = 'sprintf'" class="text-base px-4 p-1 rounded-t-lg bg-[#FAFAFA] min-w-10" x-bind:class="{
                'bg-[#FAFAFA] dark:bg-[#282c34] ring-2 ring-neutral-200/50 dark:ring-neutral-700/75': activeTab === 'sprintf',
                'bg-[#FBFBFB] dark:bg-[#343841] hover:bg-[#F0F0F0] dark:hover:bg-[#1b1d21]': activeTab !== 'sprintf',
            }">
                sprintf
            </button>
            </div>

            <div x-show="activeTab === 'f'" x-cloak class="[>pre.phiki]:!mt-0">
            <pre class="phiki language-php one-light phiki-themes one-dark-pro" data-language="php" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #282c34;--phiki-dark-color: #abb2bf"><code><span class="line"><span class="token" style="color: #4078F2;;--phiki-dark-color: #61afef">f</span><span class="token" style="--phiki-dark-color: #abb2bf">(</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">The {1} contains {0} monkeys. That&#039;s a nice {1} full of {0} monkeys.</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #986801;;--phiki-dark-color: #d19a66">100</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">zoo</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&#039;</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #abb2bf">)</span><span class="token">
</span></span></code></pre>
        </div>
            <div x-show="activeTab === 'sprintf'" x-cloak class="[>pre.phiki]:!mt-0">
            <pre class="phiki language-php one-light phiki-themes one-dark-pro" data-language="php" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #282c34;--phiki-dark-color: #abb2bf"><code><span class="line"><span class="token" style="color: #4078F2;;--phiki-dark-color: #61afef">f</span><span class="token" style="--phiki-dark-color: #abb2bf">(</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">The %2</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #e06c75">s</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">contains %1</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #e06c75">d</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">monkeys. That&#039;s a nice %2</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #e06c75">s</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">full of %1</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #e06c75">d</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">monkeys.</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #986801;;--phiki-dark-color: #d19a66">100</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">zoo</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&#039;</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #abb2bf">)</span><span class="token">
</span></span></code></pre>
        </div>
    </div>

<p>Note that F uses 0-based indexing when referencing positional arguments.</p>
<p><strong>Right-justifying text</strong></p>
<div x-data="{
    tabs: JSON.parse('[\u0022f\u0022,\u0022sprintf\u0022]'),
    activeTab: 'f',
}" class="prose-code-tabs">
    <div class="mx-4 flex items-center gap-x-2.5">
                    <button type="button" x-on:click="activeTab = 'f'" class="text-base px-4 p-1 rounded-t-lg bg-[#FAFAFA] min-w-10" x-bind:class="{
                'bg-[#FAFAFA] dark:bg-[#282c34] ring-2 ring-neutral-200/50 dark:ring-neutral-700/75': activeTab === 'f',
                'bg-[#FBFBFB] dark:bg-[#343841] hover:bg-[#F0F0F0] dark:hover:bg-[#1b1d21]': activeTab !== 'f',
            }">
                f
            </button>
                    <button type="button" x-on:click="activeTab = 'sprintf'" class="text-base px-4 p-1 rounded-t-lg bg-[#FAFAFA] min-w-10" x-bind:class="{
                'bg-[#FAFAFA] dark:bg-[#282c34] ring-2 ring-neutral-200/50 dark:ring-neutral-700/75': activeTab === 'sprintf',
                'bg-[#FBFBFB] dark:bg-[#343841] hover:bg-[#F0F0F0] dark:hover:bg-[#1b1d21]': activeTab !== 'sprintf',
            }">
                sprintf
            </button>
            </div>

            <div x-show="activeTab === 'f'" x-cloak class="[>pre.phiki]:!mt-0">
            <pre class="phiki language-php one-light phiki-themes one-dark-pro" data-language="php" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #282c34;--phiki-dark-color: #abb2bf"><code><span class="line"><span class="token" style="color: #4078F2;;--phiki-dark-color: #61afef">f</span><span class="token" style="--phiki-dark-color: #abb2bf">(</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">The following number has been padded to a length of 10 – {:0&gt;10}.</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #986801;;--phiki-dark-color: #d19a66">100</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #abb2bf">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #7f848e;--phiki-dark-font-style: italic">//</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #7f848e;--phiki-dark-font-style: italic"> 0000000100</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #7f848e;--phiki-dark-font-style: italic">
</span></span></code></pre>
        </div>
            <div x-show="activeTab === 'sprintf'" x-cloak class="[>pre.phiki]:!mt-0">
            <pre class="phiki language-php one-light phiki-themes one-dark-pro" data-language="php" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #282c34;--phiki-dark-color: #abb2bf"><code><span class="line"><span class="token" style="color: #4078F2;;--phiki-dark-color: #61afef">f</span><span class="token" style="--phiki-dark-color: #abb2bf">(</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">The following number has been padded to a length of 10 – %&#039;010d.</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #61afef">    </span><span class="token" style="color: #986801;;--phiki-dark-color: #d19a66">100</span><span class="token" style="--phiki-dark-color: #abb2bf">,</span><span class="token" style="--phiki-dark-color: #61afef">
</span></span><span class="line"><span class="token" style="--phiki-dark-color: #abb2bf">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #7f848e;--phiki-dark-font-style: italic">//</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #7f848e;--phiki-dark-font-style: italic"> 0000000100</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #7f848e;--phiki-dark-font-style: italic">
</span></span></code></pre>
        </div>
    </div>

<p>The <code>sprintf()</code> syntax here is kind of mystical. <code>'0'</code> is character to pad with, <code>10</code> is the length, <code>d</code> is the format specifier.</p>
<p>F's syntax on the otherhand reads slightly nicer in my opinion. Use <code>0</code> to right-justify (<code>&gt;</code>) the placeholder to a length of <code>10</code>.</p>
<p>If you wanted to left-justify the text, you'd flip the operator to <code>&lt;</code> and it would just work. To left-justify with <code>sprintf</code>, you'd need to add a <code>-</code> character.</p>
<p><strong>Escaping placeholders</strong></p>
<div x-data="{
    tabs: JSON.parse('[\u0022f\u0022,\u0022sprintf\u0022]'),
    activeTab: 'f',
}" class="prose-code-tabs">
    <div class="mx-4 flex items-center gap-x-2.5">
                    <button type="button" x-on:click="activeTab = 'f'" class="text-base px-4 p-1 rounded-t-lg bg-[#FAFAFA] min-w-10" x-bind:class="{
                'bg-[#FAFAFA] dark:bg-[#282c34] ring-2 ring-neutral-200/50 dark:ring-neutral-700/75': activeTab === 'f',
                'bg-[#FBFBFB] dark:bg-[#343841] hover:bg-[#F0F0F0] dark:hover:bg-[#1b1d21]': activeTab !== 'f',
            }">
                f
            </button>
                    <button type="button" x-on:click="activeTab = 'sprintf'" class="text-base px-4 p-1 rounded-t-lg bg-[#FAFAFA] min-w-10" x-bind:class="{
                'bg-[#FAFAFA] dark:bg-[#282c34] ring-2 ring-neutral-200/50 dark:ring-neutral-700/75': activeTab === 'sprintf',
                'bg-[#FBFBFB] dark:bg-[#343841] hover:bg-[#F0F0F0] dark:hover:bg-[#1b1d21]': activeTab !== 'sprintf',
            }">
                sprintf
            </button>
            </div>

            <div x-show="activeTab === 'f'" x-cloak class="[>pre.phiki]:!mt-0">
            <pre class="phiki language-php one-light phiki-themes one-dark-pro" data-language="php" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #282c34;--phiki-dark-color: #abb2bf"><code><span class="line"><span class="token" style="color: #4078F2;;--phiki-dark-color: #61afef">f</span><span class="token" style="--phiki-dark-color: #abb2bf">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">I don&#039;t want the \{} placeholder to be formatted.</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="--phiki-dark-color: #abb2bf">)</span><span class="token">
</span></span></code></pre>
        </div>
            <div x-show="activeTab === 'sprintf'" x-cloak class="[>pre.phiki]:!mt-0">
            <pre class="phiki language-php one-light phiki-themes one-dark-pro" data-language="php" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #282c34;--phiki-dark-color: #abb2bf"><code><span class="line"><span class="token" style="color: #4078F2;;--phiki-dark-color: #61afef">f</span><span class="token" style="--phiki-dark-color: #abb2bf">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">I don&#039;t want the %%s placeholder to be formatted</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #98c379">&quot;</span><span class="token" style="--phiki-dark-color: #abb2bf">)</span><span class="token">
</span></span></code></pre>
        </div>
    </div>

<p><code>\</code> is the character that we're all used to using for escaping things, so it's natural to use that for F.</p>
<hr />
<p>F supports a bunch of different placeholder formats. Here's the table of syntaxes at the time of writing this post.</p>
<table>
<thead>
<tr>
<th>Placeholder</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>{}</code></td>
<td>References an argument based on the position of the placeholder in the format string.</td>
</tr>
<tr>
<td><code>{2}</code></td>
<td>References the 3rd argument (0-based indexing).</td>
</tr>
<tr>
<td><code>{name}</code></td>
<td>References a named argument.</td>
</tr>
<tr>
<td><code>{:b}</code></td>
<td>Formats an integer as binary.</td>
</tr>
<tr>
<td><code>{:x}</code></td>
<td>Formats an integer as hexadecimal.</td>
</tr>
<tr>
<td><code>{:o}</code></td>
<td>Formats an integer as octal.</td>
</tr>
<tr>
<td><code>{:&gt;10}</code></td>
<td>Right-justifies the argument to a width of <code>10</code> using a single space.</td>
</tr>
<tr>
<td><code>{:&lt;10}</code></td>
<td>Left-justifies the argument to a width of <code>10</code> using a single space.</td>
</tr>
<tr>
<td><code>{:0&gt;10}</code></td>
<td>Right-justifies the argument to a width of <code>10</code> using a custom character <code>0</code>.</td>
</tr>
<tr>
<td><code>{:0&lt;10}</code></td>
<td>Left-justifies the argument to a width of <code>10</code> using a custom character <code>0</code>.</td>
</tr>
<tr>
<td><code>{:&gt;width$}</code></td>
<td>Right-justifies the argument to a width defined by the named argument <code>width</code>.</td>
</tr>
</tbody>
</table>
<h2>Sign off</h2>
<p>Some people prefer string concatenation. Others like using <code>sprintf()</code>. Me? I like the &quot;rusty&quot; syntax.</p>
<p>Check out the code on <a href="https://github.com/ryangjchandler/f">GitHub</a> and maybe try it out in your next hobby project!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 20 Mar 2025 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Registering global arguments and options in Laravel Zero]]></title>
                <link>https://ryangjchandler.co.uk/posts/registering-global-arguments-and-options-in-laravel-zero</link>
                <description><![CDATA[<p>I recently ran into a scenario where I wanted to register a couple of global options inside of a Laravel Zero project. These options need to be available for all commands inside of my project, but I didn't want to extend a custom base <code>Command</code> class.</p>
<p>I tried a couple of things and eventually landed on the following:</p>
<pre><code class="language-php">use Illuminate\Console\Application;
use Symfony\Component\Console\Input\InputOption;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Application::starting(function (Application $application): void {
            $option = new InputOption(
                name: 'example',
                mode: InputOption::VALUE_REQUIRED,
                default: 'foo',
                suggestedValues: ['foo', 'bar', 'baz']
            );
            
            $application-&gt;getDefinition()-&gt;addOption($option);
        });
    }
}
</code></pre>
<p>Now every command that I add to my Laravel Zero application will have the <code>--example</code> option attached to it, allowing me to do things such as load config files from a specified location without needing to do that manually inside of each command, kind of like this:</p>
<pre><code class="language-php">use Illuminate\Console\Application;
use Symfony\Component\Console\Input\InputOption;
use Illuminate\Console\Events\CommandStarting;
use Illuminate\Support\Facades\Event;
use App\Contracts\UserConfiguration;
use App\Configuration\ProjectConfiguration;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        /*
         * Register the `--config` option with every single command by default.
         * 
         * Default to `./config.json`, but accept a value from the user.
         */
        Application::starting(function (Application $application): void {
            $option = new InputOption(
                name: 'config',
                mode: InputOption::VALUE_REQUIRED,
                default: './config.json',
            );
            
            $application-&gt;getDefinition()-&gt;addOption($option);
        });

        /*
         * When a command is executed, the framework dispatches a `CommandStarting` event.
         * 
         * The event includes the parsed input (arguments &amp; options), so I can use that to
         * bind an object to the container which can be used &amp; injected outside of the command.
         */
        Event::listen(CommandStarting::class, function (CommandStarting $event) {
            $this-&gt;app-&gt;instance(
                UserConfiguration::class,
                ProjectConfiguration::parse($event-&gt;input-&gt;getOption('config'))
            );
        });
    }
}
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 18 Mar 2025 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Saying goodbye to PXP]]></title>
                <link>https://ryangjchandler.co.uk/posts/saying-goodbye-to-pxp</link>
                <description><![CDATA[<p>Over the past couple of years, PXP has been a passion project of mine – something I've poured countless hours into, driven by the idea of pushing the PHP ecosystem and development experience in new and exciting ways. What started as way of learning Rust 3 or 4 years ago eventually became this mammoth of a project, in terms of code and ambition.</p>
<p>It's been incredibly rewarding to see the ideas behind the project excite people. I've attended various conferences over the last couple of years and have always had a couple of people ask me about the project, and the answer has always been <em>&quot;I'm working on it, when I've got time.&quot;</em></p>
<p>As much as I enjoy working on PXP, I've reached a point now where it simply doesn't make much sense to continue working on it. I don't have the time to give it the attention it deserves. Software projects, especially ones as ambitious as this, require consistent effort, maintenance and iteration. When you're the only one driving the effort, it becomes hard to give it all of that alongside work and life.</p>
<p>All of that isn't to say that I've lost interest in the ideas behind PXP. Far from it! I still believe in the potential of tools written in languages other than PHP and I'm excited by others working on similar things. There are some fantastic projects out there tackling similar problems – whether it's static analysis tools, language servers, or faster web servers. If you're looking for alternatives, I'd encourage you to check out <a href="https://github.com/carthage-software/mago">Mago</a>. <a href="https://x.com/azjezz">Saif</a> was one of the earlier contributors to my original PHP parser project in Rust and had a tonne of impact on the project. They're now working hard on Mago and can dedicate much more time to the project. Odds are I'll probably contribute to Mago myself too in the future!</p>
<p>Ceasing development on PXP wasn't an easy decision to make. Ideas for the project have been looming around in my mind constantly and it's super frustrating not being able to bring said ideas to life.</p>
<p>Who knows – maybe one day, the ideas behind PXP will resurface in another form, whether it's from myself or from likeminded developers. But for now, it's time to call it a day.</p>
<p>Instead of deleting the repository entirely, I've <a href="https://github.com/ryangjchandler/pxp">archived it under my personal GitHub account</a> for others to reference if needed. Everything is MIT licensed, so please feel free to use some of the code from the project as long as it adheres to the licensing.</p>
<p>Thank you to everyone who was interested in the project, contributed along the way, and asked how it was going.</p>
<p>– Ryan</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 13 Mar 2025 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Goto, or not to goto go]]></title>
                <link>https://ryangjchandler.co.uk/posts/goto-or-not-to-goto-go</link>
                <description><![CDATA[<p>The <code>goto</code> statement – feared, ridiculed, yet still lurking around in PHP. Newer PHP developers probably don't even know that it exists and those who do often try to pretend that it doesn't. But is <code>goto</code> really as bad as its reputation suggests?</p>
<p>The <code>goto</code> statement lets you jump from one part of your code to another. You mark a point in the code with a <code>label</code> and then reference it to jump.</p>
<pre><code class="language-php">goto syke;
echo &quot;You shall not pass.&quot;;

syke:
echo &quot;Passed ya!&quot;;
</code></pre>
<p>That first <code>echo</code> is never actually executed because the <code>goto</code> statement is jumping over it to the <code>syke</code> label. Forgive me for I have sinned.</p>
<p>Most modern languages either completely omit the <code>goto</code> feature, or strongly recommend against using it. It does still have a few niche uses though.</p>
<ul>
<li><strong>Exiting deeply nested loops</strong> – instead of numbered <code>break</code> or <code>continue</code> statements, you can add a label and just <code>goto</code> it.</li>
<li><strong>Code obfuscation</strong> – want code that's impossible to read? Drop in a bunch of <code>goto</code> statements and give someone a heavy headache.</li>
<li><strong>Retry mechanisms</strong> – instead of doing things with a <code>while</code> loop, use a <code>goto</code> to jump <em>back</em> to a specific point. This is what <a href="https://github.com/laravel/framework/blob/7b8e12d8f4218615370d329a258f0b7c4afc6237/src/Illuminate/Support/helpers.php#L350">Laravel's own <code>retry()</code> helper</a> does internally!</li>
</ul>
<h3>Why you should probably avoid it</h3>
<p>The main reason developers shun <code>goto</code> is because it makes code hard to follow. Jumping around your code can turn a simple routine into a tangled spaghetti mess. IDEs and language servers do make it easier with &quot;go to X&quot;, but you're still better off avoiding it.</p>
<p>Most problems <code>goto</code> was designed to solve are better handled with functions and loops.</p>
<h3>So should you use it?</h3>
<p>Unless you're writing a short blog post about it, probably not. Knowing that it exists is useful though! Why not drop it into a PR and impress (or scare) your colleagues?</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 03 Mar 2025 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Don't subscribe to complexity]]></title>
                <link>https://ryangjchandler.co.uk/posts/dont-subscribe-to-complexity</link>
                <description><![CDATA[<p><strong>tl;dr</strong> Complexity is a silent killer. It sneaks into projects under the guise of best practices, cutting-edge frameworks, and future-proofing. More often than not, it actually causes more problems than it solves.</p>
<p>Here's the problem with complexity. Many developers build solutions for problems they don't have yet. They anticipate scaling issues, edge cases, or future requirements that will likely never materialise. Instead of focusing on solving the problems at hand, they overengineer their systems, adding unnecessary layers that slow down development and introduce unnecessary cognitive overhead.</p>
<p>Abstractions are powerful, but overdoing it tends to make systems harder to understand and maintain. Layers upon layers of interfaces, abstract classes, factory patterns is really just glorified indirection. If a developer needs to dive neck-deep when clicking through classes to find a method implementation or definition, the abstraction has failed.</p>
<p>Something else that causes a lot of problems is &quot;trend-chasing&quot;. New frameworks, libraries, and architectural styles appear all of the time. Don't get me wrong, some of them do bring real benefits to the table, but the majority of them are just hype. Adopting a microservices architecture when a monolithic approach would do, or switching to a brand-new JavaScript framework because it's trending on GitHub. You should be choosing the tools that fit your needs (which could be microservices or domain-driven design). You shouldn't be chasing the latest and greatest – give it some to grow – new doesn't always equal better.</p>
<p>Here's my 5 step guide to reducing unnecessary complexity.</p>
<p><strong>1. Keep it simple, stupid (KISS)</strong></p>
<p>Focus on solving today's problem. Don't think about the imaginary ones of the future. The simplest solution that works right now is often the best.</p>
<p><strong>2. You ain't gonna need it (YAGNI)</strong></p>
<p>Don't build unnecessary complexity in the name of flexibility. Adding infinite levels of abstraction for a future use-case that may never come is wasteful. Build what is needed for now and iterate when the requirements change.</p>
<p><strong>3. Optimise for readability</strong></p>
<p>Your code should be easy to understand, not just for you but anyone who has to maintain it. Clear, well-structured and self-explanatory code should save you from those nightmarish debugging sessions.</p>
<p><strong>4. Resist the hype</strong></p>
<p>Choose tools and architectures based on necessity, not popularity. Just because somebody said &quot;X is cool&quot;, doesn't mean you should be using X. Prioritize stability and simplicity over following the latest &quot;cool kids&quot; thing.</p>
<p><strong>5. Refactor as you go</strong></p>
<p>Start simple and improve things as you go along. Avoid prematurely optimising or restructuring a system before it's absolutely necessary. Small, incremental improvements over time lead to cleaner, more manageable and easily reviewable code.</p>
<hr />
<p>Complexity doesn't make your code more sophisticated – it makes it harder to work with.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 07 Feb 2025 00:00:00 +0000</pubDate>
                                    <category>Thoughts</category>
                            </item>
                    <item>
                <title><![CDATA[2024: A year in review]]></title>
                <link>https://ryangjchandler.co.uk/posts/2024-a-year-in-review</link>
                <description><![CDATA[<p>2024 is coming to a close and as I've done for the last 4 years, I'm here again with a blog post talking about the year and how it's been.</p>
<h3>Open-source</h3>
<p>Quite like 2023, I've been quite quiet on the open-source front. I've continued to maintain a few packages and some Filament plugins, but I didn't really do anything <em>too</em> groundbreaking.</p>
<p>The <a href="https://github.com/pxp-lang/pxp">PXP</a> project sat there, dormant, for a few months. Admittedly, I think I was dealing with quite a bit of burnout. Even though I wanted to spend some time working on it, I just didn't have the energy.</p>
<p>It's quite disappointing actually because I had a major breakthrough on how I wanted the project to grow and progress, then <strong>BAM</strong>, burnout.</p>
<p>As we approach the end of the year though, I'm starting to find some energy and I've started to pick things back up. Having some time away from a project gives you a fresh perspective when you come back to it. At first you forget what's what and then you have a eureka moment and realise that what you <em>were</em> doing isn't the best.</p>
<p>Besides my existing packages and PXP, I did actually spend some time on a problem that I've been wanting to solve for a few years now – <strong>syntax highlighting</strong>. I've been using <a href="https://shiki.style/">Shiki</a> for ages but it always annoyed me how slow it was and how much setup was needed to get it working from PHP. So I really dug into the complexities of TextMate grammars and released <a href="https://github.com/phikiphp/phiki">Phiki</a>, a syntax highlighter written in PHP that uses TextMate grammars and VSCode themes to produce beautifully highlighted code.</p>
<p>If you read a few of my blog posts, you'll see it in action. The results have been excellent and I've had quite a few people reach out to me with nothing but kind things to say about the project.</p>
<h3>Content Creation</h3>
<p>Not including this post, I've written 17 blog posts for this site. I used to write about all sorts but much like my open-source work, I've just not had the energy. Still, 17 posts isn't bad.</p>
<p>I also continued working on my <a href="https://rustforphp.dev">Rust for PHP Developers</a> video course. At the time of writing this, there are more than <strong>40 videos</strong> published and I've still got a few that need to be edited and published. I'm super thankful to those who purchased the course and waited patiently for me to release the videos. Burnout was the biggest bottleneck, but I'm happy I've managed to get so many videos out for people to enjoy.</p>
<p>In hindsight, I regret doing the pre-order sale. I wanted to make sure that people were interested and that the time spent on the videos could be offset, but it also added a tonne of subconscious pressure. In future, I'll probably just do a typical newsletter thing for seeing if there's any interest.</p>
<h3>Conferences</h3>
<p>I attended a few conferences in 2024.</p>
<ul>
<li>Laracon EU</li>
<li>Laravel Live UK (Speaker)</li>
<li>Laracon US</li>
</ul>
<p>All of them were great. It's always nice to hear people talking about things you're not 100% clued up on, but it's also nice to see people who you might only get to see once a year.</p>
<p>I'm looking forward to attending more conferences in 2025.</p>
<h3>Work</h3>
<p>Funnily enough, I wrote about burnout in 2023 and how that led to me changing jobs. I was freelancing on top of a full-time job and it was a bit too much.</p>
<p>As we enter 2025, I'm very excited to announce that I'll be leaving my current role and starting a new one at <a href="https://laravel.com">a very special company</a>.</p>
<p>I can't wait to get started. I'll be working with some of the smartest people in the industry and honestly, I think it might be <strong>the</strong> dream job for a lot of Laravel developers.</p>
<h3>Looking forward to 2025</h3>
<p>I'm going to continue working on PXP. I've got some ideas that I want to experiment with, mostly aimed towards making it hyper-useful to PHP developers and removing the <em>need</em> to know Rust to help contribute to its success.</p>
<p>I want to continue working on cool things and sharing them online too. Not because there is some magical problem that &quot;thing&quot; is going to fix, but because <a href="https://aaronfrancis.com/2024/because-i-wanted-to-12c5137c">I want to</a> build something for the sake of building it.</p>
<p>Happy New Year!</p>
<p>Ryan</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 28 Dec 2024 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Adding dark mode to my website]]></title>
                <link>https://ryangjchandler.co.uk/posts/adding-dark-mode-to-my-website</link>
                <description><![CDATA[<p>After absolutely zero demand, I've added dark mode to my website.</p>
<p>The front end is all styled with Tailwind so it didn't take too long, thankfully. Add a couple of <code>dark:</code> classes in various Blade templates and it just works. The one issue I did have was with syntax highlighted code blocks.</p>
<p>The light version of the site uses a light theme for syntax highlighting. It's nice and consistent with the rest of the site, so it made sense. When you switch to dark mode though, the last thing you want is your monitor or laptop screen turning into a mini floodlight as you scroll through a blog post.</p>
<p>To combat this I did some work in <a href="https://github.com/phikiphp/phiki">Phiki</a> and added &quot;multi-theme&quot; support. This means I can syntax highlight a code block with different themes at the same time and then use some CSS to switch between the themes.</p>
<p>Switch between themes using the sun/moon icon button in the header and see the code block theme change!</p>
<pre><code class="language-php">&lt;?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * Define the application's command schedule.
     */
    protected function schedule(Schedule $schedule): void
    {
        // $schedule-&gt;command('inspire')-&gt;hourly();
    }

    /**
     * Register the commands for the application.
     */
    protected function commands(): void
    {
        $this-&gt;load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}
</code></pre>
<p>I was a big fan of this functionality in Shiki, so porting it over made a tonne of sense.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 05 Nov 2024 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Fast and powerful syntax highlighting in PHP with Phiki]]></title>
                <link>https://ryangjchandler.co.uk/posts/fast-and-powerful-syntax-highlighting-in-php-with-phiki</link>
                <description><![CDATA[<p><strong>tl;dr</strong> I wrote <a href="https://github.com/phikiphp/phiki">a syntax highlighter</a>. It's pretty good and I had a tonne of fun working on it.</p>
<h2>Preface</h2>
<p>Syntax highlighting is something that we've all had to add to a site before, probably. Whether it's documentation or our personal sites, figuring out what package or service to use can be a nightmare.</p>
<p>I faced this problem too. Way back when my personal site used Highlight.php, a PHP port of the popular Highlight.js package. Then I tried out Shiki, a JavaScript package that uses VSCode themes and TextMate grammars to highlight code.</p>
<p>Highlight.php was pretty fast but it lacked contextual highlighting which made everything feel really flat. Shiki is a very good package but it's written in JavaScript, so there's a huge overhead when trying to use it from PHP.</p>
<p>I was frustrated with these tools so the only logical thing to do was build my own syntax highlighter in PHP.</p>
<h2>Overview</h2>
<p><a href="https://github.com/phikiphp/phiki">Phiki</a> is a syntax highlighter written in PHP that uses VSCode themes and TextMate grammar files to produce beautifully highlighted snippets of code.</p>
<p>Phiki is really easy to use. Install the package with Composer:</p>
<pre><code class="language-sh">composer require phiki/phiki
</code></pre>
<p>And use the <code>Phiki::codeToHtml()</code> method to convert a string of code into a syntax highlighted piece of HTML.</p>
<pre><code class="language-php">use Phiki\Phiki;
use Phiki\Grammar\Grammar;
use Phiki\Theme\Theme;

$phiki = new Phiki();

echo $phiki-&gt;codeToHtml(
    code: &quot;echo 1 + 2;&quot;,
    grammar: Grammar::Php,
    theme: Theme::GithubDark,
);
</code></pre>
<p>Phiki ships with a bunch of languages and themes out of the box, all of which can be found as members on the <code>Grammar</code> and <code>Theme</code> enums you see above.</p>
<h3>Highlighting code for the terminal</h3>
<p>If you have a scenario where you need to highlight code for the terminal, you can use the <code>codeToTerminal()</code> method with the same set of parameters to generate a string of text containing ANSI escape sequences for the terminal</p>
<pre><code class="language-php">echo $phiki-&gt;codeToTerminal(
    code: &quot;echo 1 + 2;&quot;,
    grammar: Grammar::Php,
    theme: Theme::GithubDark,
);
</code></pre>
<figure>
    <img src="https://github.com/phikiphp/phiki/raw/main/art/codeToTerminal.png" alt="A preview of some highlighted code in the terminal." class="border dark:border-neutral-700 shadow-xs">
    <figcaption>A preview of some highlighted code in the terminal.</figcaption>
</figure>

<h3>CommonMark</h3>
<p>Highlighting code blocks in Markdown files is probably the most common use case for a syntax highlighter. Phiki ships with a <code>league/commonmark</code> extension so you don't need to do any manual wiring.</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;
use Phiki\CommonMark\PhikiExtension;
use Phiki\Theme\Theme;

$converter = new CommonMarkConverter();

$converter-&gt;getEnvironment()-&gt;addExtension(new PhikiExtension(Theme::GithubDark));

echo $converter-&gt;convert(&lt;&lt;&lt;'MD'
    ```php
    echo &quot;Hello, world!&quot;;
    ```
MD);
</code></pre>
<p>Register the extension, providing a <code>Theme</code>, and it all just works.</p>
<h2>Future</h2>
<p>I have a small list of things that I want to do before I tag a <code>v1.0.0</code>. Here's the rough list:</p>
<h3>Dual themes</h3>
<p>When a site has a light and dark mode, having different highlighting themes for each variant is quite a nice feature. It's hard to find one theme that works well for both colour schemes. The API for this would probably be something like this:</p>
<pre><code class="language-php">$phiki-&gt;codeToHtml(
    code: &quot;...&quot;,
    grammar: Grammar::Php,
    theme: [
        'light' =&gt; Theme::GithubLight,
        'dark' =&gt; Theme::GithubDark,
    ],
);
</code></pre>
<p>The generated HTML could then use CSS variables to store various style values for each theme and a bit of CSS could be added to the site to change which CSS variables are used.</p>
<h3>Transformers</h3>
<p>Phiki already has a &quot;transformer&quot; API that lets you modify things at various stages in the highlighting process. This could in theory be used to add things like <code>[!code focus]</code> to focus a particular line in a block of code.</p>
<p>The transformer API is very rugged at the moment though and I'd like to make it as simple to use as possible. Thankfully I can make these sort of breaking changes pre-1.0.</p>
<h3>Performance</h3>
<p>There are a few places in the code that have sub-optimal performance. Parsing grammars, transforming RegEx patterns, etc. Finding ways to make this more performant is vital as I want Phiki to be <em>the</em> fastest highlighter on the market.</p>
<h2>Pitfalls</h2>
<p>The current version of Phiki is my 4th attempt at writing a syntax highlighter similar to Shiki in PHP. I've probably spent anywhere from 50 to 100 hours working on the idea and finally getting to a place where it works and is near-perfect, I'd say that's not bad. I've given up plenty of times before.</p>
<p>Despite all of this hard work, Phiki still has a bit of a problem. It's not <em>perfect</em>.</p>
<p>TextMate grammars contains a bunch of regular expressions which determine what tokens are in a file and how they should be highlighted. The TextMate editor, and subsequent <code>vscode-textmate</code> package, both use a RegEx engine called <a href="https://github.com/kkos/oniguruma">Oniguruma</a>. PHP uses the PCRE2 engine.</p>
<p>Oniguruma is a very good RegEx engine and has support for a bunch of things. Some of those things aren't supported by PCRE2, which is the main reason why Phiki isn't perfect. In all of my testing, the main blocker is support for &quot;variable-length lookbehinds&quot;. Here's an example:</p>
<pre><code>(?&lt;=^\S+)=
</code></pre>
<p>This pattern is looking for a <code>=</code> character, but will only match if it is preceded by the start of the line and any number of non-whitespace characters. PCRE2 doesn't support this type of lookbehind, mainly because of the performance implications. My understanding is that the architecture and design decisions in PCRE2 would make adding these sort of lookbehinds painful and the performance would be horrible.</p>
<p>Of the 200+ grammars that Phiki currently ships with, only 12 of them are using variable-length lookbehinds. Others were also using them but I managed to patch them out of the grammar files with some simpler and potentially less-accurate RegEx patterns.</p>
<p>What I'm trying to figure out now is the best way to workaround this problem. The way I see it, I've got two choices.</p>
<ol>
<li>Remove these grammars from Phiki and let users add them at their own risk.</li>
<li>Write a wrapper around PCRE2 that adds support for variable-length lookbehinds, albeit with a performance penalty.</li>
</ol>
<p>As a developer who enjoys tackling tough problems, my mind tells me that option 2 is the way to go. Effectively write a RegEx engine in pure PHP, learn some new things and eliminate the problem for good. On the other hand, the amount of time required to build said RegEx engine would be insane and probably not worth it in the long run.</p>
<p>I'd love to know what you think. Let me know on <a href="https://twitter.com/ryangjchandler">Twitter</a>.</p>
<h2>Sign off</h2>
<p>Thanks for reading! I'd love it if you gave Phiki a go and provided some feedback on <a href="https://github.com/phikiphp/phiki">GitHub</a>. There is still a ways to go before tagging <code>v1.0.0</code>, so all feedback is welcome.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 19 Oct 2024 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Embedding Blade inside of Markdown content]]></title>
                <link>https://ryangjchandler.co.uk/posts/embedding-blade-inside-of-markdown-content</link>
                <description><![CDATA[<p>If you haven't read my blog post <a href="/posts/revitalising-my-site-for-2025">&quot;Revitalising my site for 2025&quot;</a>, I'd recommend going back to read it since I cover some of the cool things I'm doing to make my website perfect for my own workflow.</p>
<p>One of the things that I added was the ability to embed Blade template code inside of a Markdown file, allowing me to build custom Blade components for blog posts and then add them into the Markdown directly.</p>
<p>I've had a few people ask me how I'm doing this so I thought I'd show you.</p>
<h2>Markdown extensions</h2>
<p>The <code>league/commonmark</code> package has an extension API that lets you register custom blocks, inline elements, and renderers. the syntax I chose for my Blade extension looks like this:</p>
<pre><code class="language-md">@blade
    &lt;!-- Put my custom Blade code here. --&gt;
@endblade
</code></pre>
<p>This type of extension is a Block extension, since the syntax spans multiple lines. The <code>league/commonmark</code> package uses an AST (abstract syntax tree) to represent the parsed Markdown code before rendering HTML, so we need to tell the package how to parse this custom Blade block.</p>
<h3>Writing the parser</h3>
<p>Blocks typically span multiple lines and have some sort of opening &amp; closing syntax. In this scenario that's <code>@blade</code> and <code>@endblade</code>. Everything in between that is parsed a literal string and any Markdown is ignored.</p>
<p>The Markdown parser needs to know when a block should start being parsed. This is done by writing a class that implements the <code>BlockStartParserInterface</code>.</p>
<pre><code class="language-php">use League\CommonMark\Parser\Block\BlockStart;
use League\CommonMark\Parser\Block\BlockStartParserInterface;
use League\CommonMark\Parser\Cursor;
use League\CommonMark\Parser\MarkdownParserStateInterface;

class BladeStartParser implements BlockStartParserInterface
{
    const REGEX = '/^@blade/';

    public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart
    {
        if ($cursor-&gt;isIndented()) {
            return BlockStart::none();
        }

        if (! $cursor-&gt;match(self::REGEX)) {
            return BlockStart::none();
        }

        return BlockStart::of(new BladeParser)-&gt;at($cursor);
    }
}
</code></pre>
<p>The sole responsibility of this class is to determine whether or not the block is present at the current position in the Markdown document. Most blocks will use a regular expression to do this, like the <code>BladeStartParser</code> is.</p>
<p>If that RegEx doesn't match, or if the cursor is indented (not at the start of the line), then there's zero-chance that the block can be found, so it returns early.</p>
<p>If the <code>@blade</code> construct is found, then the parser is told to start parsing the rest of the block using the <code>BladeParser</code> class.</p>
<aside class="aside--left aside--context__note"><p>The <code>Cursor::match()</code> method will consume any text matched by the RegEx, so there's no need to manually move the cursor along.</p></aside>
<p>The <code>BladeParser</code> class extends <code>AbstractBlockContinueParser</code> and is responsible for parsing the text until the end of the block is reached.</p>
<pre><code class="language-php">use App\CommonMark\Block\Blade;
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
use League\CommonMark\Parser\Cursor;
use League\CommonMark\Parser\Block\BlockContinueParserInterface;
use League\CommonMark\Parser\Block\BlockContinue;
use League\CommonMark\Util\ArrayCollection;

class BladeParser extends AbstractBlockContinueParser
{
    private Blade $block;

    private ArrayCollection $strings;

    public function __construct()
    {
        $this-&gt;block = new Blade();
        $this-&gt;strings = new ArrayCollection();
    }

    public function getBlock(): Blade
    {
        return $this-&gt;block;
    }

    public function addLine(string $line): void
    {
        $this-&gt;strings[] = $line;
    }

    public function closeBlock(): void
    {
        $this-&gt;block-&gt;setContent(
            ltrim(implode(&quot;\n&quot;, $this-&gt;strings-&gt;toArray()))
        );
    }

    public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue
    {
        if ($cursor-&gt;match('/^@endblade/')) {
            return BlockContinue::finished();
        }

        return BlockContinue::at($cursor);
    }
}
</code></pre>
<p>There are a few more things going on inside of this class.</p>
<p>The Markdown parser needs to know which block is being parsed, so a custom <code>Blade</code> block is being stored in a property. There's also another property that stores a list of strings.</p>
<p><code>AbstractBlockContinueParser</code> implements a method called <code>isContainer()</code> which tells the parser whether or not the block can contain other Markdown elements (headings, blockquotes, etc). The default implementation returns <code>false</code> which is fine in this case because Blade blocks aren't interpreted as Markdown.</p>
<p>Instead of parsing the content of the block as Markdown, the parser will consume each line inside of the block and call the <code>addLine()</code> method with a string containing the lines text. It needs to be collected and stored somewhere so that it can be passed to the Blade compiler later on.</p>
<p><code>tryContinue()</code> is continuously checking to see if the <code>@endblade</code> marker can be found at the start of a line, indicating whether or not the block is finished.</p>
<p>If it <em>can</em> be found then the parser is told this block is no longer being parsed. Otherwise the parser continues consuming lines.</p>
<p>Once the parser is done parsing the Blade block, the <code>closeBlock()</code> method is called and any lines of text collected are stored inside of the custom <code>Blade</code> block object.</p>
<pre><code class="language-php">namespace App\CommonMark\Block;

use League\CommonMark\Node\Block\AbstractBlock;

final class Blade extends AbstractBlock
{
    public function __construct(
        private string $content = ''
    ) {}

    public function getContent(): string
    {
        return $this-&gt;content;
    }

    public function setContent(string $content): void
    {
        $this-&gt;content = $content;
    }
}
</code></pre>
<p>Block classes are mostly plain objects that store information about a block. They're not responsible for rendering.</p>
<h3>Rendering the Blade template</h3>
<p>To actually render a block, we need to write a custom block renderer.</p>
<pre><code class="language-php">use App\CommonMark\Block\Blade;
use Illuminate\Support\Facades\Blade as Engine;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;

class BladeRenderer implements NodeRendererInterface
{
    /**
     * @param Blade $node
     */
    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
    {
        Blade::assertInstanceOf($node);

        return Engine::render($node-&gt;getContent());
    }
}
</code></pre>
<p>This class takes in a <code>Node</code>, in this case the <code>Blade</code> block from before, and returns a string of HTML that represents that block.</p>
<p>The Blade engine provides an API for compiling and rendering a string of Blade through the <code>Blade::render()</code> method (aliased to <code>Engine</code> to avoid collision with the block).</p>
<p>This is how the code between <code>@blade</code> and <code>@endblade</code> is compiled and eventually added to the final HTML output.</p>
<h3>Hooking it all up</h3>
<p>To actually tell the <code>league/commonmark</code> engine that there's a custom block, we need to register all of the custom classes with the engine.</p>
<p>In my blog, I do this by manually building an <code>Environment</code> object with all of the CommonMark features I need and registering a custom <code>Extension</code> that has my custom blocks and renderers.</p>
<pre><code class="language-php">$this-&gt;app-&gt;singleton(MarkdownConverter::class, static function (): MarkdownConverter {
    $environment = new Environment();

    $environment
        -&gt;addExtension(new CommonMarkCoreExtension)
        -&gt;addExtension(new GithubFlavoredMarkdownExtension)
        -&gt;addExtension(new DescriptionListExtension)
        -&gt;addExtension(new PhikiExtension(Theme::GithubDark))
        -&gt;addExtension(new MyExtension);

    return new MarkdownConverter($environment);
});
</code></pre>
<pre><code class="language-php">use App\CommonMark\Block\Blade;
use App\CommonMark\Block\Parser\BladeStartParser;
use App\CommonMark\Block\Renderer\BladeRenderer;
use League\CommonMark\Environment\EnvironmentBuilderInterface;
use League\CommonMark\Extension\ExtensionInterface;

final class MyExtension implements ExtensionInterface
{
    public function register(EnvironmentBuilderInterface $environment): void
    {
        $environment
            -&gt;addBlockStartParser(new BladeStartParser, 80)
            -&gt;addRenderer(Blade::class, new BladeRenderer);
    }
}
</code></pre>
<p>This tells the engine how to parse the <code>@blade</code> blocks and how to render the custom <code>Blade</code> block node.</p>
<h2>Using in your own apps</h2>
<p>Implementing this manually in your own applications is probably a bit too tedious, so I've decided to pull this out into a separate package. I'm already using it on my website!</p>
<p>Install the package with Composer:</p>
<pre><code class="language-sh">composer require ryangjchandler/commonmark-blade-block
</code></pre>
<p>Then follow the instructions on <a href="https://github.com/ryangjchandler/commonmark-blade-block">the GitHub repository</a> to get it setup.</p>
<h2>Sign off</h2>
<p>Hopefully this has been insightful. The <code>league/commonmark</code> package is excellent and incredibly extensible – you can basically do anything you want inside of a Markdown file.</p>
<p>Thanks for reading, catch you next time.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 17 Oct 2024 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Revitalising my site for 2025]]></title>
                <link>https://ryangjchandler.co.uk/posts/revitalising-my-site-for-2025</link>
                <description><![CDATA[<p>If you've read some of my posts recently, you might have noticed that this one looks a little different. I've redesigned my site and made some serious upgrades.</p>
<p>The previous iteration of my site was built on top of an old Laravel application from about 4 years ago. It was still running on Laravel 10.x and had a load of old, unreachable code that I wanted to get rid of.</p>
<p>Now I could have gone through the steps to upgrade to Laravel 11.x and removed all of that old code, but I wanted to keep the skeleton up-to-date with the latest changes in Laravel 11.x, so I decided to start from scratch and rebuild the site as a new project.</p>
<p>I'll give you the basics of the new site.</p>
<p>It's running on <strong>Laravel 11.x</strong> and rendered completely with <strong>Blade</strong>. There's a hint of Livewire for some interactive components, but it's not on every single page. I'm using <strong>Tailwind</strong> for the styling and have purposely kept things minimal. Here's a comparison between the old and new home pages.</p>
<div class="grid md:gap-8 xl:-mx-20 prose-image-grid md:grid-cols-2">
    <figure>
    <img src="https://ryangjchandler.co.uk/build/assets/old-BHz4T8nd.png" alt="The old design." class="border dark:border-neutral-700 shadow-xs">
    <figcaption>The old design.</figcaption>
</figure>
    <figure>
    <img src="https://ryangjchandler.co.uk/build/assets/new-D7nBIGFu.png" alt="The new design." class="border dark:border-neutral-700 shadow-xs">
    <figcaption>The new design.</figcaption>
</figure>
</div>

<p>I found the content being on the right-hand side of a permanent sidebar annoying and the font weights felt wrong, so the new design goes back to a single column layout with everything flowing top-to-bottom.</p>
<p>That's probably enough on general design changes. You can browse the site yourself to see what things look like.</p>
<h2>Content Management</h2>
<p>All of my posts are written in Markdown. It's mostly CommonMark-flavoured, with a few custom additions.</p>
<p>The previous iteration of my site actually had a Filament panel with a <code>MarkdownEditor</code> where I could manage everything, but I've decided to get rid of it completely. I'm much more comfortable writing Markdown inside of my text editor, so the Filament panel felt pointless.</p>
<figure>
    <img src="https://ryangjchandler.co.uk/build/assets/markdown-in-editor-Br66sTvD.png" alt="A screenshot of this blog post&#039;s Markdown file in my editor." class="border dark:border-neutral-700 shadow-xs">
    <figcaption>A screenshot of this blog post&#039;s Markdown file in my editor.</figcaption>
</figure>

<p>All of the content is stored on-disk in Markdown files and I use my <a href="https://github.com/ryangjchandler/orbit">Orbit</a> package to create Eloquent models from the files. This means that I can fetch content from disk the same way that I would from a regular database.</p>
<p>In terms of custom Markdown features, I've actually only got two right now.</p>
<h3>Blade blocks</h3>
<p>I've added support for Blade to my Markdown files. This means that I can do the following:</p>
<pre><code class="language-md">@blade
    &lt;!-- Put my custom Blade code here. --&gt;
@endblade
</code></pre>
<p>I purposely chose something that resembles a Blade directive since it doesn't interfere with any other syntax in a Markdown and is easy to spot when scanning a file. I'm actually using this to do the little image grid above.</p>
<pre><code class="language-md">@blade
&lt;x-typography.image-grid&gt;
    &lt;x-typography.figure :src=&quot;Vite::asset('...')&quot; /&gt;
    &lt;x-typography.figure :src=&quot;Vite::asset('...')&quot; /&gt;
&lt;/x-typography.image-grid&gt;
@endblade
</code></pre>
<p>The benefit to this approach is that I can literally embed anything I want here. I can use <code>Vite</code> to get image paths, build a custom Alpine.js component for a blog post, etc.</p>
<h3>Aside blocks</h3>
<p>Another custom block that I've added is the &quot;aside&quot; block. This literally generates an <code>aside</code> element where I can place additional content that isn't necessarily required reading for a blog post.</p>
<p>The super cool thing is that on larger screens (Tailwind <code>xl</code> and above), I can place them in the left and right gutter, a bit like the one you should see just to the right of this paragraph.</p>
<aside class="aside--right"><p>If you're on mobile, then this is going to show up underneath the text above. Try loading this page on desktop to get the best result.</p></aside>
<p>Here's the syntax for that:</p>
<pre><code class="language-md">&gt;&gt; This block will float to the right of the page, inside of the gutter.
</code></pre>
<p>and if I want one on the left, I just reverse the opening sequence of characters.</p>
<aside class="aside--left"><p>This one should show up on the left side of the screen.</p>
<p>Inline elements are supported, such as <strong>bold</strong>, <em>italic</em> and <code>code snippets</code>.</p></aside>
<pre><code class="language-md">&lt;&lt; This one should show up on the left side of the screen.
&lt;&lt;
&lt;&lt; Inline elements are supported, such as **bold**, _italic_ and `code snippets`.
</code></pre>
<p>When I want these &quot;aside&quot; blocks to have a little bit of context, I can append the opening sequence of characters with an identifier and use CSS to style the block differently.</p>
<aside class="aside--right aside--context__danger"><p>This one has a little heading and some special colours.</p></aside>
<pre><code class="language-md">&gt;&gt;[danger] This one has a little heading and some special colours.
</code></pre>
<h2>Syntax Highlighting</h2>
<p>In the past I've used Shiki, via the <a href="https://github.com/spatie/laravel-markdown"><code>spatie/laravel-markdown</code></a> package and <a href="https://torchlight.dev/">Torchlight</a>, to perform syntax highlighting on code blocks.</p>
<p>If you're not familiar with Shiki, it's a syntax highlighter written in JavaScript that uses TextMate grammars and Visual Studio Code themes to syntax highlight code snippets. It's the same technology (under the hood) that powers Visual Studio Code itself.</p>
<p>This is a powerful tool because any languages that has VSCode support, out of the box or through an extension, can be highlighted by Shiki. The one downside to Shiki and tools that use it, such as the ones mentioned above, is that you need a way of executing that JavaScript from PHP.</p>
<p><code>laravel-markdown</code> will shell out to a Node script and return the highlighted code and Torchlight does it all for you on a remote server so you need to call it through an API. This comes with some noticeable overhead, especially when you're writing a blog post and viewing changes live in the browser.</p>
<p>To make this more of a seamless experience, I actually wrote my own syntax highlighter in PHP called <a href="https://github.com/phikiphp/phiki">Phiki</a>. As you can tell from the name, it's &quot;Shiki for PHP&quot;.</p>
<p>It uses TextMate grammars and VSCode themes to syntax highlight code, but does it all with PHP instead of relying on a JavaScript package. This makes it much faster to execute and removes any need for caching or memoization.</p>
<p>The generated, highlighted code is pretty much perfect for most languages. Here's an example of some PHP code highlighted with Phiki.</p>
<pre><code class="language-php">&lt;?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * Define the application's command schedule.
     */
    protected function schedule(Schedule $schedule): void
    {
        // $schedule-&gt;command('inspire')-&gt;hourly();
    }

    /**
     * Register the commands for the application.
     */
    protected function commands(): void
    {
        $this-&gt;load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}
</code></pre>
<p>Phiki adds a <code>data-language</code> attribute to the generated HTML which lets you hook up a &quot;language tag&quot; to your code blocks. That's what you see in the top-right corner of the code block above.</p>
<p>I said that it's perfect for &quot;most languages&quot; and there's a reason for that. Shiki, or more specifically TextMate and <code>vscode-textmate</code>, use the Oniguruma engine to handle RegEx matching. PHP uses the PCRE2 engine and that means there are some compatibility issues with patterns used in TextMate grammars.</p>
<p>Most things can be translated, or &quot;lowered&quot;, into PCRE-compatible equivalents. This eliminates quite a few issues and differences between the two engines.</p>
<p>The main problem holding Phiki back right now is the fact that Oniguruma supports &quot;variable-length lookbehinds&quot;, but PCRE2 doesn't. The first way to resolve this would be manually patching grammars that use this RegEx feature, but that requires a solid understanding of the grammar itself and intended output. I've done this for quite a few grammars, but it's not the smoothest.</p>
<p>My current idea is building a layer on top of PHP's <code>preg_*</code> functions that implements a very small RegEx engine to handle these incompatible patterns. In 99% of cases, Phiki can use PHP's regular RegEx functions. If it comes across a pattern that throws up a problem then it can defer to the slower, but more powerful, custom RegEx engine.</p>
<p>I'm still reading up on how RegEx engines work, so don't expect to see that fully implemented anytime soon. Do expect some blog posts as I build the engine though, as I think it'll be pretty interesting to read about.</p>
<h2>Social images</h2>
<p>My old site used a third-party service to generate Open Graph images on-demand. This was overkill and honestly £7 not worth spending, so my new site generates them ahead of time using Puppeteer on my machine.</p>
<p>Here's what they look like:</p>
<figure>
    <img src="https://ryangjchandler.co.uk/build/assets/og-example-BEhwq-jT.png" alt="The Open Graph image for this blog post." class="border dark:border-neutral-700 shadow-xs">
    <figcaption>The Open Graph image for this blog post.</figcaption>
</figure>

<p>I just have a single Artisan command that loops through posts and pages, calls out to Puppeteer and then stores the image so I can commit to GitHub and deploy. It's free and actually quite fast.</p>
<aside class="aside--left"><p>I would like to have a solid way of doing this from PHP, with support for modern CSS features, so perhaps I'll look at that in the future.</p></aside>
<h2>Sign off</h2>
<p>Thanks for reading if you made it this far. I like reading about how websites are built and what happens behind the scenes, hopefully you enjoyed this too.</p>
<p>Personal sites are never fully complete. I treat mine like a playground / testing ground for ideas and that's why I wanted to wipe the slate clean. Give myself a solid foundation for future ideas.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 14 Oct 2024 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Setting up the command-line interface (Rebuilding Composer in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/rebuilding-composer-in-rust-setting-up-the-command-line-interface</link>
                <description><![CDATA[<p>Welcome to my new series of blog posts where I go through the various steps that it takes to rebuild Composer in Rust.</p>
<p><strong>This project is purely for fun</strong> – I don't intend to release this as an officially supported tool. If you've read some of my more recent blog posts, you can probably tell I'm in my &quot;programming is fun, right?&quot; phase.</p>
<p>So, the first thing that I need to do is get a command-line application running. The most popular CLI framework in the Rust world is <code>clap</code>, so I'm going to use that because who in this world would want to roll their own argparse in 2024?</p>
<p>Important detail upfront – this project is going to be a monorepo. I'm going to use Cargo's <code>workspace</code> feature which lets me separate out logic into separate packages so I can pull in various bits and pieces when I need them.</p>
<pre><code class="language-toml">[workspace]
members = [
    &quot;crs&quot;
]
resolver = &quot;2&quot;
</code></pre>
<p>That's all it takes to create a monorepo of different packages. Nifty!</p>
<p>The <code>crs</code> package is going to be the main binary for the project, so that's where I'm going to start building out the command-line interface.</p>
<p>Installing <code>clap</code> is as simple as running a single command.</p>
<pre><code class="language-sh">cargo add clap --package crs --features derive
</code></pre>
<p>The <code>--features</code> flag lets me enable conditionally compiled code from the <code>clap</code> package. In this case, I want to use the fancy wancy <code>#[derive()]</code> macro that it provides to write nice fluent command definitions.</p>
<p>To actually define the arguments, I need to create a <code>struct</code> with some fields and add a single <code>#[derive()]</code> attribute.</p>
<pre><code class="language-rust">use clap::{Parser, Subcommand};

#[derive(Parser)]
struct Arguments {
    #[clap(subcommand)]
    command: Command,
}

#[derive(Subcommand)]
enum Command {
    Require(RequireCommand),
}

#[derive(Parser)]
struct RequireCommand {
    package: String,
}

fn main() {
    let args = Arguments::parse();

    match &amp;args.command {
        Command::Require(cmd) =&gt; {
            println!(&quot;require {}&quot;, cmd.package);
        },
    }
}
</code></pre>
<p>So now, if I were to run the project in the terminal:</p>
<pre><code class="language-sh">cargo run --package crs -- require hello
</code></pre>
<p>I'll get something like this in the output:</p>
<pre><code>$&gt; cargo run --package crs -- require hello
require hello
</code></pre>
<p>The magic is all in the <code>#[derive(Parser)]</code> and <code>#[derive(Subcommand)]</code> macros. Rust macros are absolute wizardry.</p>
<p>In this case, those macros are looking at the <code>struct</code> or <code>enum</code> and implementing magical methods that handle parsing the arguments.</p>
<p>That can be seen in the call to <code>Arguments::parse()</code>. That static method is being implemented by <code>#[derive(Parser)]</code>.</p>
<p>Cool stuff done. Boring stuff now – code organisation. I don't want to write everything inside of a giant <code>match</code> block.</p>
<p>My personal preference is a new <code>cmd</code> module that exports a function for each command, e.g. <code>cmd/require.rs</code> would look like this.</p>
<pre><code class="language-rust">use crate::RequireCommand;

pub fn require(cmd: &amp;RequireCommand) {

}
</code></pre>
<p>This is a nice pattern in my opinion. Keeps the commands in separate files and everything related to a command can be co-located.</p>
<p>There we have it. A basic command-line application in Rust, setup in less than 5 minutes. Not bad!</p>
<p>The next post is going to be focused on making HTTP requests. That's a pretty essential part of building the <code>require</code> command.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 26 May 2024 00:00:00 +0000</pubDate>
                                    <category>Rust</category>
                            </item>
                    <item>
                <title><![CDATA[Downloading files from the web (Rebuilding Composer in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/rebuilding-composer-in-rust-downloading-files-from-the-web</link>
                <description><![CDATA[<p>Welcome back to the series. If this is your first time here, I recommend <a href="https://ryangjchandler.co.uk/posts/rebuilding-composer-in-rust-setting-up-the-command-line-interface">starting from the beginning</a> so you don't miss out on cool stuff.</p>
<p>In this post, I'm going to explain how <code>composer require</code> works at a very high level and then start to implement the foundations of my own <code>require</code> command.</p>
<h3>How Composer requires packages</h3>
<p>So what happens when you run <code>composer require</code>? I'm glad you asked!</p>
<p>Let's say you want to install one of my (excellent) packages. You'd run a command similar to this.</p>
<pre><code class="language-sh">composer require ryangjchandler/blade-cache-directive
</code></pre>
<p>The first important thing that happens is Composer tries to determine the &quot;requirements&quot; for the package you're attempting to install. This process involves figuring out whether the package actually exists in Composer's package repository, and if it does, which version is best to install in your project,</p>
<p>After it has figured those things out, it sends the necessary information over to an <code>Installer</code> class which handles actually downloading the package from the correct place, as well as installing any dependencies of the package you're trying to install.</p>
<p>That's a somewhat recursive process since dependencies of a package might also have dependencies, so that happens for each package that needs to be downloaded and installed.</p>
<p>Eventually it will have a list of all packages that need to be installed and where the packages need to be downloaded from.</p>
<p>The package files are downloaded (normally as a ZIP or a &quot;tarball&quot;), extracted into the <code>vendor</code> directory, the autoloader is regenerated and any Composer scripts are executed.</p>
<aside class="aside--left aside--context__note"><p>This is a very high-level explanation of what Composer does. The code itself is actually a big more spaghettified than you might imagine.</p>
<p>Spaghettified isn't actually a nice way to put. I prefer to say that the process involves some side-quests.</p></aside>
<h3>Downloading files from a URL in Rust</h3>
<p>It's going to take a few more posts before I get into the nitty gritty of installing real packages. I just want to focus on download a file, specifically an archive file, and extracting it into a directory somewhere.</p>
<p>To do this, I'm first going to need an HTTP client. There are many options in the Rust world, but only a few are truly feature complete in my opinion. My personal choice is a package called <code>reqwest</code>.</p>
<p>I'm going to create a new package in the monorepo for this called <code>crs-downloader</code>.</p>
<pre><code class="language-sh">cargo init crs-downloader --lib
</code></pre>
<aside class="aside--right aside--context__info"><p>Cargo automatically updates the <code>members</code> entry for the workspace when you create a new crate / package using the Cargo CLI.</p>
<p>The Rust ecosystem just feels so good to use.</p></aside>
<p>To install the <code>reqwest</code> package, I'll also use Cargo.</p>
<pre><code class="language-sh">cargo add reqwest --package crs-downloader --features blocking
</code></pre>
<p>I'm not writing asynchronous code, so I want to enable the <code>blocking</code> features which lets me run synchronous HTTP requests. At some point in the future, I'll introduce async stuff, but I'm keeping it simple for now.</p>
<p>This new crate is going to be responsible for downloading a single archive from a given URL, then returning a value that represents where that file has been downloaded to on disk.</p>
<p>I'll start by creating a new <code>struct</code> called <code>Downloader</code>.</p>
<pre><code class="language-rust">use reqwest::blocking::Client;

pub struct Downloader {
    client: Client,
}

impl Downloader {
    pub fn new() -&gt; Result&lt;Self, DownloadError&gt; {
        Ok(Self {
            client: Client::builder().build().map_err(|_| DownloadError::FailedToCreateClient)?,
        })
    }
}

#[derive(Debug, Clone)]
pub enum DownloadError {
    FailedToCreateClient,
}
</code></pre>
<p>The only piece of state that the <code>Downloader</code> has is an HTTP client. Instead of creating a new <code>Client</code> for each request, I can just make a single one and everything will be a little bit faster.</p>
<p>Cool, so how can something be downloaded from a given URL? I'll need a method, say <code>download</code>. That will take a single parameter <code>url</code>.</p>
<p>An HTTP request needs to be made to that <code>url</code>, then the data that is returned needs to be written to a specific place on the disk. I'm going to store things in a temporary directory so that it doesn't clutter a user directory.</p>
<p>Making that HTTP request is very simple with <code>reqwest</code>.</p>
<pre><code class="language-rust">impl Downloader {
    // ...

    pub fn download(&amp;self, url: &amp;str) -&gt; Result&lt;DownloadedFile, DownloadError&gt; {
        let response = match self.client.get(url).send() {
            Ok(response) =&gt; response,
            Err(_) =&gt; return Err(DownloadError::FailedToDownloadFile(url.to_string())),
        };

        todo!()
    }
}
</code></pre>
<p>Using the <code>Client</code> on the <code>Downloader</code>, I can make a <code>GET</code> request to the <code>url</code> and grab the response.</p>
<p>The <code>.send()</code> method returns a <code>Result</code>, meaning a value or an error. If something goes wrong during the request, I can return a simple <code>DownloadError</code>. There's no information in here apart from the <code>url</code> that was being requested – again, keeping things simple for now.</p>
<p>To store the downloaded data on disk I need to store it inside of a folder somewhere. Rust has a standard function for finding the &quot;temporary directory&quot; of a machine, but I want some more helpers. I'm going to use the <code>tempfile</code> package to help me a little.</p>
<pre><code class="language-sh">cargo add tempfile --package crs-downloader
</code></pre>
<p>This package provides a <code>TempDir</code> type that will create a temporary directory, and upon destruction of the <code>TempDir</code> value, delete that folder from the disk. This means the value needs to be &quot;owned&quot; by something. I'll opt to store it inside of the <code>Downloader</code>.</p>
<pre><code class="language-rust">pub struct Downloader {
    client: Client,
    tempdir: TempDir,
}

impl Downloader {
    pub fn new() -&gt; Result&lt;Self, DownloadError&gt; {
        Ok(Self {
            client: Client::builder().build().map_err(|_| DownloadError::FailedToCreateClient)?,
            tempdir: TempDir::new().map_err(|_| DownloadError::FailedToCreateTemporaryDirectory)?,
        })
    }
}
</code></pre>
<p>As long as the <code>Downloader</code> is kept &quot;alive&quot; in the application, the files that are downloaded will be available on disk.</p>
<p>Taking the data from the response and storing it inside of a file is pretty straightforward too.</p>
<pre><code class="language-rust">impl Downloader {
    // ...

    pub fn download(&amp;self, url: &amp;str) -&gt; Result&lt;DownloadedFile, DownloadError&gt; {
        // ...

        let path = self.tempdir.path().join(
            slugify_url(url)
        );

        let mut file = File::create(&amp;path).map_err(|_| DownloadError::FailedToCreateDestinationFile(path.to_string_lossy().to_string()))?;
        let text = response.text().map_err(|_| DownloadError::FailedToReadBytesFromResponse(url.to_string()))?;

        copy(&amp;mut text.as_bytes(), &amp;mut file)
            .map_err(|_| DownloadError::FailedToCopyBytesToFile(url.to_string(), path.to_string_lossy().to_string()))?;

        Ok(DownloadedFile { path })
    }
}
</code></pre>
<p>The code looks kind of crowded, but there's manual error-handling going on all over the place. I could introduce some casting magic, but I'm <strong>keeping things simple</strong>.</p>
<p>I've written all of this code without any tests so far. Now for rapid development, that's maybe not a bad thing, but I do want to make sure that this actually works.</p>
<pre><code class="language-rust">#[cfg(test)]
mod tests {
    use super::Downloader;

    #[test]
    fn it_can_download_a_file() {
        let downloader = Downloader::new().unwrap();
        let downloaded_file = downloader.download(&quot;https://www.rust-lang.org/logos/rust-logo-512x512.png&quot;).unwrap();

        assert!(downloaded_file.path.exists());
    }
}
</code></pre>
<p>This is a very simple test to make sure that the downloader can actually download a file. Hardcoding a URL feels like it might cause issues in the future if that URL goes missing, but it'll do for now.</p>
<p>I also want a test that ensures the temporary directory and the files are tidied up too.</p>
<pre><code class="language-rust">#[test]
fn it_tidies_up_after_itself() {
    let downloader = Downloader::new().unwrap();
    let downloaded_file = downloader.download(&quot;https://www.rust-lang.org/logos/rust-logo-512x512.png&quot;).unwrap();

    assert!(downloaded_file.path.exists());

    drop(downloader);
    
    assert!(!downloaded_file.path.exists());
}
</code></pre>
<pre><code class="language-rust">running 2 tests
test tests::it_can_download_a_file ... ok
test tests::it_tidies_up_after_itself ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s
</code></pre>
<p>Perfect! Both tests are passing and I can now download files and store them somewhere on disk.</p>
<p>In the next part of the series I'll start implementing the actual package resolving stuff. That will include using the real Packagist API to grab information about a package, where it can be downloaded and more.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 26 May 2024 00:00:00 +0000</pubDate>
                                    <category>Rust</category>
                            </item>
                    <item>
                <title><![CDATA[Fetching package information from Packagist (Rebuilding Composer in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/rebuilding-composer-in-rust-fetching-package-information-from-packagist</link>
                <description><![CDATA[<p>Welcome back! If you're here for the first step, I recommend starting from the beginning so you don't get lost.</p>
<p>This post is going to focus on interacting with the Packagist API to retrieve information about a given package.</p>
<p>To grab information about a package from Packagist, you can use a public API endpoint as below.</p>
<pre><code>https://repo.packagist.org/p2/ryangjchandler/blade-cache-directive.json
</code></pre>
<p>This returns some minified JSON that contains information about the Composer package. Things like the <code>name</code>, <code>require</code>, <code>autoload</code>, etc.</p>
<p>In order to grab this information from the project, I need to make an HTTP request to the endpoint. Like the previous episodes, I'm going to abstract this out into a new package in the workspace. I'm also going to add the <code>reqwest</code> package to I can make HTTP requests.</p>
<pre><code class="language-sh">cargo init crs-package-metadata --lib
cargo add reqwest --package crs-package-metadata --features blocking
</code></pre>
<p>Serialising and deserialising JSON in Rust is fairly straightforward. There's a package called <code>serde</code> that lets you use macros on various structures that represent the structure of the JSON.</p>
<pre><code class="language-sh">cargo add serde --package crs-package-metadata --features derive
cargo add serde_json --package crs-package-metadata
</code></pre>
<p>This lets me write a <code>struct</code> to represent the information returned from the Packagist API and deserialise a string of JSON into an instance of the <code>struct</code>.</p>
<p>The actual structure of the JSON is something like this:</p>
<pre><code class="language-json">{
    &quot;packages&quot;: {
        &quot;[vendor]/[package]&quot;: [
            {
                &quot;name&quot;: &quot;[vendor]/[package]&quot;,
                &quot;description&quot;: &quot;[description]&quot;,
                &quot;version&quot;: &quot;[version1]&quot;,
                // ...
            },
            {
                &quot;version&quot;: &quot;[version2]&quot;,
                // ...
            }
            // ...
        ]
    },
    &quot;minified&quot;: &quot;composer/2.0&quot;
}
</code></pre>
<p>I don't care about the <code>minified</code> key, since I know it's being minified. The <code>packages</code> key contains a single object with a single key (the name of the package). That key contains an array of objects that hold all of the information for a set of versions of the package.</p>
<p>The JSON is minified, which means that any keys that are common between the various versions of a package are omitted. Composer themselves have a package <code>composer/metadata-minifier</code> that can be used in PHP to expand the minified versions, but since I'm writing Rust, I don't have the luxury of using existing code.</p>
<p>That's not a big problem right now since I don't need all of that information. I only care about the following things:</p>
<ul>
<li>The <code>source</code> of a version.</li>
<li>The distributable artefacts (<code>dist</code>).</li>
<li>The raw <code>version</code> of the package.</li>
<li>The <code>version_normalized</code> field.</li>
</ul>
<pre><code class="language-rust">#[derive(Debug, Deserialize)]
pub struct PackageMetadata {
    versions: Vec&lt;PackageVersionMetadata&gt;,
}

#[derive(Debug, Deserialize)]
pub struct PackageVersionMetadata {
    version: String,
    version_normalized: String,
    dist: PackageDistMetadata,
    source: PackageSourceMetadata,
}

#[derive(Debug, Deserialize)]
pub struct PackageDistMetadata {
    url: String,
    r#type: String,
    shasum: String,
    reference: String,
}

#[derive(Debug, Deserialize)]
pub struct PackageSourceMetadata {
    url: String,
    r#type: String,
    reference: String
}
</code></pre>
<aside class="aside--left aside--context__info"><p>Rust has a set of reserved keywords – things you'd use to create structures, types, etc. It's possible to still use those reserved keywords by prefixing them with <code>r#</code> to create a &quot;raw identifier&quot;.</p></aside>
<p>With the rough structure defined, I can start to write the deserialisation logic.</p>
<pre><code class="language-rust">impl PackageMetadata {
    pub fn for_package(package: &amp;str) -&gt; Result&lt;Self, PackageMetadataError&gt; {
        let url = format!(&quot;https://repo.packagist.org/p2/{package}.json&quot;);
        let response = get(&amp;url).map_err(|_| PackageMetadataError::FailedToFetchPackageMetadata(package.to_string()))?;

        // If the package was not found, return an error.
        if response.status() == StatusCode::NOT_FOUND {
            return Err(PackageMetadataError::PackageNotFound(package.to_string()));
        }

        // Grab the raw JSON from the response.
        let json = response.text().map_err(|_| PackageMetadataError::FailedToReadPackageMetadata(package.to_string()))?;

        // Convert the raw JSON into an untyped JSON value.
        let metadata: Value = serde_json::from_str(&amp;json).map_err(|_| PackageMetadataError::FailedToParsePackageMetadata(package.to_string()))?;
        let versions = metadata[&quot;packages&quot;][package].clone();

        Ok(PackageMetadata {
            versions: serde_json::from_value(versions).map_err(|_| PackageMetadataError::FailedToParsePackageMetadata(package.to_string()))?
        })
    }
}
</code></pre>
<p>The <code>serde_json</code> API is really nice I think. Rust has support for operator overloading through the trait system, so you can access keys inside of an object in a similar way to JavaScript.</p>
<p>The code above does a bit of manual handling to grab the array of version objects. Since the <code>serde</code> macros rely on things being defined at compile-time, you have to do some trickery to make it read from nested keys that have variable names. In this case, that would be the package name being used as the key.</p>
<p>It's not impossible to do, but I find it much nicer to take the explicit route of grabbing that value from the JSON manually and then deserialising it further into the typed <code>PackageVersionMetadata</code> instances.</p>
<p>Time to write some tests. Thankfully, I know for a fact that at least one of my packages will be available at this endpoint. So I can use that as my test case.</p>
<pre><code class="language-rust">#[cfg(test)]
mod tests {
    use super::PackageMetadata;

    #[test]
    fn it_can_fetch_metadata_for_a_package() {
        let metadata_result = PackageMetadata::for_package(&quot;ryangjchandler/blade-cache-directive&quot;);

        assert!(metadata_result.is_ok());

        let metadata = metadata_result.unwrap();

        assert!(!metadata.versions.is_empty());
        assert!(metadata.versions.iter().any(|version| version.version == &quot;v1.0.0&quot;.to_string()));
    }

    #[test]
    fn it_returns_an_error_when_a_package_is_not_found() {
        let metadata = PackageMetadata::for_package(&quot;ryangjchandler/this-package-does-not-exist&quot;);

        assert!(metadata.is_err());
    }
}
</code></pre>
<p>More progress. Nice.</p>
<p>The next post in the series is going to focus on parsing out semantic version strings into nice little <code>VersionConstraint</code> values that will let me easily test a specific version against a constraint.</p>
<p>Until next time.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 26 May 2024 00:00:00 +0000</pubDate>
                                    <category>Rust</category>
                            </item>
                    <item>
                <title><![CDATA[Fun with Blade directives]]></title>
                <link>https://ryangjchandler.co.uk/posts/fun-with-blade-directives</link>
                <description><![CDATA[<p>Let's start this off by explaining how the Blade engine works with a few bullet points.</p>
<ul>
<li>You choose a Blade template to render.</li>
<li>The engine uses a series of regular expressions to parse and compile the template.</li>
<li>The engine produces a plain PHP file and writes it to disk (so that it's cached for future renders).</li>
<li>The PHP file is included and output buffers are used to capture the generated HTML.</li>
</ul>
<p>The most interesting step in the process is that RegEx patterns are used to extract various things from the template and generate the appropriate PHP code. Other template engines use a more traditional tokeniser and parser to process templates, but since Blade is more or less just syntax sugar over regular PHP code, it can do things in a much simpler manner.</p>
<p>What this does mean is that you're basically always dealing with arbitrary strings that might contain plain ol' PHP code.</p>
<h3>Custom Directives</h3>
<p>It's possible to write your own Blade directives. This lets you hide a lot of boilerplate code inside of a directive and simplify your Blade templates.</p>
<pre><code class="language-php">Blade::directive('example', function (string $expression) {
    // Logic goes here.
});
</code></pre>
<p>Something that catches a lot of new Laravel developers out is the fact that custom directives only receive a single argument to the callback function.</p>
<p>Let's say our the <code>@example()</code> directive here is designed to accept 2 arguments:</p>
<pre><code class="language-blade">@example('Hello, ', 'Ryan')
</code></pre>
<p>A less-experienced Laravel developer might expect the callback function to receive two arguments, corresponding to the two arguments we passed through to the actual directive.</p>
<p>That's not the case though. Instead, we receive a string containing the literal text from the Blade template.</p>
<pre><code class="language-php">Blade::directive('example', function (string $expression) {
    assert($expression === &quot;'Hello, ', 'Ryan'&quot;);
});
</code></pre>
<p>So instead of writing regular PHP code inside of the callback and returning a value, we actually instead want to return a string of PHP code. That PHP code will then be inserted into the generated template in place of the original directive.</p>
<pre><code class="language-php">Blade::directive(&quot;example&quot;, function (string $expression) {
    return &quot;&lt;?php echo implode(' ', [{$expression}]); ?&gt;&quot;;
});
</code></pre>
<p>There <em>are</em> packages out there that extend Laravel to support the more logical &quot;receive the real arguments inside of the callback&quot; approach, but the fact that we have a string here means we can do some fun and creative things.</p>
<h3>Named arguments</h3>
<p>Custom Blade directives quite often provide a wrapper around a regular PHP function. PHP 8.0 introduced the concept of &quot;named arguments&quot;, allowing you to pass arguments to a function out-of-order and instead provide the name of the argument instead.</p>
<pre><code class="language-php">function hello(string $name, string $greeting = &quot;Hello, &quot;)
{
    return $greeting . $name;
}

hello(greeting: &quot;Greetings, &quot;, name: &quot;Ryan&quot;);
</code></pre>
<p>If we wrap this <code>hello()</code> function inside of a Blade directive, we can actually still use named arguments!</p>
<pre><code class="language-php">Blade::directive(&quot;hello&quot;, function (string $expression) {
    return &quot;&lt;?php echo hello({$expression}); ?&gt;&quot;;
});
</code></pre>
<pre><code class="language-blade">@hello(greeting: &quot;Greetings,&quot;, name: &quot;Ryan&quot;)
</code></pre>
<p>Since the text between the parentheses is just being inserted inside of our expression, the named arguments are passed along verbatim to the underlying <code>hello()</code> function.</p>
<p>Pretty cool!</p>
<h3>Magic Variables</h3>
<p>Most Laravel developers have probably used &quot;magic variables&quot; in their projects before. The two most common examples are probably the <code>$loop</code> variable available inside of <code>@foreach</code> blocks, and the <code>$message</code> variable inside of an <code>@error</code> block.</p>
<p>Laravel ships with an <code>@auth</code> directive that lets you conditionally do stuff based on whether a user is logged in or not. This is cool, but I want to ship my own <code>@auth</code> directive that injects the current user into the block of code as a <code>$user</code> variable.</p>
<p>Fun fact – you can actually override Laravel's own directives with custom ones, since the Blade compiler checks for custom ones first. I don't recommend doing this though – all of this code is purely for educational and demonstration purposes!</p>
<pre><code class="language-php">Blade::directive(&quot;auth&quot;, function (string $expression) {
    $guard = $expression ?: &quot;()&quot;;

    return &quot;&lt;?php if (auth()-&gt;guard{$guard}-&gt;check()): ?&gt;&quot; .
        '&lt;?php $user = auth()-&gt;user(); ?&gt;';
});

Blade::directive(&quot;endauth&quot;, function () {
    return '&lt;?php unset($user); ?&gt;' . &quot;&lt;?php endif; ?&gt;&quot;;
});
</code></pre>
<p>The code above returns multiple statements for each directive. Starting and ending the <code>if</code> block, and also creating and unsetting the magical <code>$user</code> variable.</p>
<blockquote>
<p>This code isn't 100% sound, please do not do this in your own apps.</p>
</blockquote>
<p>The fact that we can compile directives into any arbitrary PHP code opens up some cool opportunities for things. I've even developed a couple of packages that take advantage of this for caching blocks of Blade code and even creating inline partials!</p>
<ul>
<li><a href="https://github.com/ryangjchandler/blade-cache-directive">blade-cache-directive</a></li>
<li><a href="https://github.com/ryangjchandler/blade-capture-directive">blade-capture-directive</a></li>
</ul>
<h3>Domain Specific Languages</h3>
<p>Another way that we can take advantage of the stringy nature of Blade directives is by writing our own domain-specific languages inside of a Blade directive.</p>
<p>Lots of server-side template engines have the concept of &quot;filters&quot;. Here's an example from Twig:</p>
<pre><code class="language-html">{{ names | join(',') | lower }}
</code></pre>
<p>So <code>names</code> is a variable that gets passed to the <code>join()</code> function. The output of <code>join(',')</code> is then sent through to <code>lower</code> and the result of that operation is then output in the template.</p>
<p>What if we wanted to do the same but in a Blade directive, perhaps something like this:</p>
<pre><code class="language-blade">@filter($names | join(',') | lower)
</code></pre>
<p>The first step is going to be parsing out the stuff inside of the directive. To get all of the different filters and the variable, we can split the expression by the <code>|</code> tokens, removing any excess whitespace around each part.</p>
<pre><code class="language-php">$parts = array_map(trim(...), explode(&quot;|&quot;, $expression));
</code></pre>
<p>To keep things simple, we'll assume that the first part is always a valid PHP expression.</p>
<pre><code class="language-php">$subject = $parts[0];
$filters = array_slice($parts, 1);
</code></pre>
<p>Each of the filters will map to a <code>Closure</code> that accepts the current value of <code>$subject</code>, as well as any arguments we pass to the filter. We'll need somewhere to store those callback functions.</p>
<p><strong>Warning:</strong> The code you're about to see contains magic.</p>
<pre><code class="language-php">class Filters
{
    protected array $filters = [];

    public function __construct(protected mixed $subject)
    {
        $this-&gt;addFilter(&quot;join&quot;, function (array $subject, string $glue = &quot;&quot;) {
            return implode($glue, $subject);
        });

        $this-&gt;addFilter(&quot;lower&quot;, function (string $subject) {
            return strtolower($subject);
        });
    }

    public function addFilter(string $name, Closure $callback): void
    {
        $this-&gt;filters[$name] = $callback;
    }

    public function get(): mixed
    {
        return $this-&gt;subject;
    }

    public function __call(string $name, array $args)
    {
        if (!isset($this-&gt;filters[$name])) {
            throw new Exception(&quot;Unrecognised filter [{$name}].&quot;);
        }

        $this-&gt;subject = $this-&gt;filters[$name]($this-&gt;subject, ...$args);

        return $this;
    }

    public function __get(string $name)
    {
        return $this-&gt;{$name}();
    }
}
</code></pre>
<p>Each filter is registered with the class upon instantiation. To actually invoke a filter, you either call a non-existent method on the class or access a non-existent property.</p>
<p>The Blade directive then needs to translate the string of filters into a series of method calls on a <code>Filters</code> object.</p>
<pre><code class="language-php">return sprintf(
        &lt;&lt;&lt;'PHP'
&lt;?php echo (new \App\Filters(%s))
    -&gt;%s
    -&gt;get(); ?&gt;
PHP
    ,
    $subject,
    implode(&quot;\n    -&gt;&quot;, $filters)
);
</code></pre>
<p>The <code>$subject</code> is passed to the constructor, then each of the filters is chained onto the object as a method or property. That triggers the <code>__call()</code> or <code>__get()</code> method on the object which runs the filter over <code>$subject</code>.</p>
<p>Then at the very end, the <code>-&gt;get()</code> method is called to retrieve the final value and output in the rendered template.</p>
<p>I warned you, here lies magic.</p>
<p>So the Blade example above would be converted into something like this:</p>
<pre><code class="language-php">echo (new \App\Filters($names))
    -&gt;join(',')
    -&gt;lower
    -&gt;get();
</code></pre>
<p>Passing <code>['Ryan', 'Jane', 'John']</code> through this set of filters would produce <code>ryan,jane,john</code>.</p>
<p>This is some seriously weird and wacky stuff – something you'll probably never want to use in a real application – but it's cool to mess around with regardless.</p>
<p>Perhaps you'll take some of these ideas away and build some cool Blade directives of your own for fun and magical purposes.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 16 May 2024 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Some cool SQLite things]]></title>
                <link>https://ryangjchandler.co.uk/posts/some-cool-sqlite-things</link>
                <description><![CDATA[<h3>Strict tables</h3>
<p>For those of you who don't know, SQLite is like a dynamically-typed language. There's no restrictions on what you can and can't store inside of a column.</p>
<p>That means if you have a <code>INTEGER</code> column in your database table, there's nothing stopping you from storing a string inside of it.</p>
<p>That is where <strong>strict tables</strong> come into play. You can enable &quot;strict mode&quot; when creating your table by appending the <code>strict</code> keyword to the table definition.</p>
<pre><code class="language-sql">CREATE TABLE users (
  id      INTEGER PRIMARY KEY,
  name    TEXT,
  email   TEXT,
  age     REAL
) strict;
</code></pre>
<p>Now any inserts will be type checked, preventing invalid types of data being inserted into your columns.</p>
<h3><code>.import</code></h3>
<p>Ever needed to import a CSV file into your database but didn't want to bother writing an import script to do it? SQLite has got you covered!</p>
<p>If you open your database in the SQLite command-line interface, you can use the <code>.import</code> command to import a CSV file directly into a database table.</p>
<pre><code class="language-sql">.import --csv /Users/ryan/Downloads/users.csv users
</code></pre>
<p>This will import the <code>users.csv</code> file into the <code>users</code> table.</p>
<h3>Extensions</h3>
<p>Lots of database engines have some sort of extension API that lets you add new functionality to the database without hand-rolling stuff.</p>
<p>SQLite is no exception to this. All you need to do is find the extension you want to use and download the object file for your operating system.</p>
<blockquote>
<p>If you don't want to mess around with downloading files, there's an excellent package manager called <code>sqlpkg</code> that takes care of the boring stuff: <a href="https://github.com/nalgeon/sqlpkg-cli">https://github.com/nalgeon/sqlpkg-cli</a>.</p>
</blockquote>
<p>If you're using the command-line interface for SQLite, you can load the extension using the <code>.load</code> command.</p>
<pre><code class="language-sql">.load /Users/ryan/Downloads/uuid
select uuid4();
</code></pre>
<p>If you want to find an extension to do something, try searching through <a href="https://sqlpkg.org/">sqlpkg.org</a>!</p>
<h3>Bytecode!?</h3>
<p>Most SQL engines convert your SQL statements into some sort of internal representation. It's normally a tree of nodes that describe what you're doing and the SQL engine uses the tree to perform operations.</p>
<p>SQLite is actually different in this regard. Instead of using a tree to process your statements, it instead converts everything into a flatter sequence of instructions, <strong>bytecodes</strong>.</p>
<p>This is very similar to how interpreted programming languages like PHP, JavaScript, Ruby etc are executed.</p>
<p>You can inspect the bytecode that is generated by prepending <code>EXPLAIN</code> to your SQL statements in the command-line interface!</p>
<pre><code class="language-sql">explain select * from users;
</code></pre>
<pre><code class="language-sql">addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     8     0                    0   Start at 8
1     OpenRead       0     2     0     2              0   root=2 iDb=0; users
2     Rewind         0     7     0                    0
3       Rowid          0     1     0                    0   r[1]=users.rowid
4       Column         0     1     2                    0   r[2]= cursor 0 column 1
5       ResultRow      1     2     0                    0   output=r[1..2]
6     Next           0     3     0                    1
7     Halt           0     0     0                    0
8     Transaction    0     0     1     0              1   usesStmtJournal=0
9     Goto           0     1     0                    0
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 14 May 2024 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Using Bunny Fonts in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/using-bunny-fonts-in-laravel</link>
                <description><![CDATA[<p>I've been using Bunny Fonts for quite a while now, after switching away from Google Fonts due to GDPR requirements and concerns.</p>
<p>But here's something that has always bothered me – adding a new font to an existing <code>&lt;link /&gt;</code> tag. You either need to reselect your existing fonts in Bunny's web interface or merge the two generated URLs manually.</p>
<p>So I've built a new package for Laravel to solve this problem and make things a whole lot simpler.</p>
<p>GitHub: <a href="https://github.com/ryangjchandler/laravel-bunny-fonts">https://github.com/ryangjchandler/laravel-bunny-fonts</a></p>
<p>You can install the package via Composer:</p>
<pre><code class="language-sh">composer require ryangjchandler/laravel-bunny-fonts
</code></pre>
<p>After installing the package, you have access to a nice &quot;builder&quot; API for registering your Bunny Fonts and rendering the necessary HTML tags.</p>
<p>Inside of a <code>ServiceProvider</code>, you can do the following:</p>
<pre><code class="language-php">use RyanChandler\BunnyFonts\Facades\BunnyFonts;
use RyanChandler\BunnyFonts\FontFamily;

BunnyFonts::add(FontFamily::Inter, [400, 500, 700]);
</code></pre>
<p>Then inside of a Blade template, you can use a Blade component or directive to render the relevant HTML.</p>
<pre><code class="language-blade">&lt;x-bunny-fonts /&gt;
&lt;!-- or --&gt;
@bunnyFonts()
</code></pre>
<h2>Sets</h2>
<p>I sometimes use different fonts in different places within the same Laravel application. Instead of loading <em>all</em> of the fonts <em>all</em> of the time, you can create different &quot;font sets&quot;.</p>
<pre><code class="language-php">BunnyFonts::set('shop')
    -&gt;add(FontFamily::Inter, [400, 500, 700]);
</code></pre>
<p>Then inside of the relevant Blade template:</p>
<pre><code class="language-blade">&lt;x-bunny-fonts set=&quot;shop&quot; /&gt;
&lt;!-- or --&gt;
@bunnyFonts('shop')
</code></pre>
<h2>Fun stuff</h2>
<p>You might have noticed a <code>FontFamily</code> enumeration being used in the example above. This is an enum provided by the package.</p>
<p>Don't worry, I didn't sit there and write out all of the font families supported by Bunny. The code is actually generated ahead of time using a small script inside of the package and some data from Bunny Fonts.</p>
<p>If you're interested in the code, you can <a href="https://github.com/ryangjchandler/laravel-bunny-fonts/blob/main/workbench/app/Console/GenerateFontEnumCommand.php">find it here</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 02 May 2024 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Disabling Composer's default timeout inside of scripts]]></title>
                <link>https://ryangjchandler.co.uk/posts/disabling-composers-default-timeout-inside-of-scripts</link>
                <description><![CDATA[<p>I like to use the <code>scripts</code> key inside of my <code>composer.json</code> to write reusable runner commands – normally things like background processes, build scripts, etc.</p>
<p>The problem is Composer has a default execution timeout of 30 seconds, so when I've got a long-running process like a queue worker running from a Composer script, it times out after 30 seconds.</p>
<p>Thankfully, there is a way to disable the timeout on a script-by-script basis.</p>
<pre><code class="language-json">{
    &quot;scripts&quot;: {
        &quot;queue&quot;: [
            &quot;Composer\\Config::disableProcessTimeout&quot;,
            &quot;php artisan queue:work&quot;
        ]
    }
}
</code></pre>
<p>All you need to do is turn the script into a multi-step one and add <code>Composer\\Config::disableProcessTimeout</code> at start of the list. Composer's default 30 second timeout will be disabled for the rest of the steps.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 12 Apr 2024 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Enums in Rust]]></title>
                <link>https://ryangjchandler.co.uk/posts/enums-in-rust</link>
                <description><![CDATA[<p>Rust is my second favourite programming languages. There are lots of things that I love about it and if I could take some of those features I love and squidge them into PHP, I would.</p>
<p>One of those features in Rust's powerful enumerations (enums). Yes, we have had enums in PHP since PHP 8.1, but they are more or less just glorified class constants. The only two real benefits they provide over class constants is the ability to use the name of the enum as a type and attach methods to an enum.</p>
<p>Rust's enums on the other hand are much more than just constants. I'd like to dig into them a little bit in this post and show you all the cool things you can do with them.</p>
<h2>Syntax</h2>
<p>We'll start off with the syntax. They look very similar to PHP's enums and many other languages.</p>
<pre><code class="language-rust">enum Role {
	Superadmin,
	Admin,
	Editor,
	User
}
</code></pre>
<p>The only real difference here is the lack of an explicit <code>case</code> statement like we have in PHP.</p>
<p>If we want to add methods to our <code>Role</code> enum, we can do so using an implementation (<code>impl</code>) block.</p>
<pre><code class="language-rust">impl Role {
	pub fn is_admin(&amp;self) -&gt; bool {
		matches!(self, Role::Admin)
	}
}
</code></pre>
<blockquote>
<p>This <code>impl</code> syntax isn't specifically for enums – methods on structs are also written in this way.</p>
</blockquote>
<p>Cool, but this is pretty basic right? There's nothing special here, it's just a plain ol' enumeration with some methods.</p>
<p>You're right – so let me introduce you to the magic.</p>
<h2>Tagged Unions 101</h2>
<p>Tagged unions, as a concept, have been around since the 1960s. Before we look at Rust's tagged unions, it's probably useful to understand what a regular <code>union</code> is. We'll use C as our example language.</p>
<p>In C, you can define a <code>union</code>. A <code>union</code> has many different fields, but the catch is that only one of those fields can be &quot;filled&quot; at any one time.</p>
<pre><code class="language-c">union Data {
	int i;
	float f;
	char str[255];
} data;
</code></pre>
<p>So if the <code>Data.i</code> field has a value, it means that <code>Data.f</code> and <code>Data.str</code> must be empty. Unions are also stored in a single memory location and the memory itself will always be big enough to store the largest field / member of the <code>union</code>.</p>
<blockquote>
<p>Fun fact – PHP's interpreter uses a <code>union</code> to define the internal representation of all PHP values. It's known as a <code>ZVal</code>.</p>
</blockquote>
<p>A tagged union is made up of two things – a tag, and a <code>union</code>. If we were to define one in C, we might do something like this:</p>
<pre><code class="language-c">typedef enum ValueType { Int, Float, String } ValueType;

typedef struct Value {
	Tag tag;
	union Data {
		int i;
		float f;
		char str[255];
	} value;
} Value;
</code></pre>
<p>When we construct a value, we &quot;tag&quot; it using one of the <code>ValueType</code> cases, then assign some data to one of the union fields based on the tag.</p>
<p>Tagged unions in languages like C and C++ aren't really considered &quot;safe&quot;. The union isn't strictly related to the tag, so there's nothing stopping us from having a value tagged as <code>Int</code> and trying to access the <code>String</code> field.</p>
<p>This is where Rust takes things a step further.</p>
<h2>Tagged Unions in Rust</h2>
<p>Rust extends on its basic enumerations by allowing us to define fields as part of the enum member directly. Let's recreate that <code>Value</code> tagged union.</p>
<pre><code class="language-rust">enum Value {
	Int(i64),
	Float(f64),
	Str(String),
}
</code></pre>
<p>This is known as a &quot;tuple variant&quot; or &quot;tuple member&quot;. Each of our enum members / cases would be the &quot;tag&quot;, and the values inside of those members would be part of the union.</p>
<p>Constructing / instantiating one of these members would then allow us to pass in a value for the field.</p>
<pre><code class="language-rust">let int_value = Value::Int(100);
</code></pre>
<p>The super-safety aspects start to show when you want to access a field. The only way to access a field is by destructuring and pattern matching the value.</p>
<pre><code class="language-rust">match int_value {
	Value::Int(value) =&gt; dbg!(value),
	_ =&gt; todo!(),
}
</code></pre>
<p>Tuple variants are just one of the syntaxes that we can use. We can also use the &quot;struct variant&quot; syntax.</p>
<pre><code class="language-rust">enum AstNode {
	Print {
		value: AstNode,
	},
	Add {
		left: AstNode,
		right: AstNode,
	}
}
</code></pre>
<p>So instead of having nameless values inside of our members, we can instead give them appropriate names. This is useful if you've got more than one value in a member.</p>
<p>The same rules apply when we want to access a value inside of the member.</p>
<pre><code class="language-rust">match node {
	AstNode::Print { value } =&gt; dbg!(value),
	AstNode::Add { left, right } =&gt; dbg!(left, right),
}
</code></pre>
<h2>Usage in Rust</h2>
<p>Rust leans heavily on tagged unions in the core of the language. There are two prime examples of this – the <code>Option</code> and <code>Result</code> types.</p>
<pre><code class="language-rust">enum Option&lt;T&gt; {
	Some(T),
	None,
}

enum Result&lt;T, E&gt; {
	Ok(T),
	Err(E),
}
</code></pre>
<p>These are almost perfect usecases for tagged unions – since both enums can only have two possible members, but you can also use generics to change the type of the value stored inside of the them.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 02 Mar 2024 00:00:00 +0000</pubDate>
                                    <category>Rust</category>
                            </item>
                    <item>
                <title><![CDATA[Preserve uploaded file names in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/preserve-uploaded-file-names-in-laravel</link>
                <description><![CDATA[<p>In a lot of scenarios, I want to maintain the name of a file when a user uploads it to a site, rather than using a randomnly generated one.</p>
<p>I sometimes forget the methods I need to call to make this work though, so here is a little code snippet for future me and anyone else who happens to come across this on the internet.</p>
<pre><code class="language-php">$request-&gt;file('upload')-&gt;storeAs('uploads', $request-&gt;file('upload')-&gt;getClientOriginalName())
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 09 Feb 2024 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Get a random element from a JavaScript array]]></title>
                <link>https://ryangjchandler.co.uk/posts/get-a-random-element-from-a-javascript-array</link>
                <description><![CDATA[<p>To get a random element from an array, you can use a couple of <code>Math</code> functions to generate a random index and retrieve a value.</p>
<pre><code class="language-js">function random(items) {
	return items[Math.floor(Math.random() * items.length)]
}
</code></pre>
<h3>How it works</h3>
<p><code>Math.random()</code> generates a random float between <code>0</code> and <code>1</code>. The generated float is always less than <code>1</code>, so when we multiply it by the length of the array, it's always going to be less than <code>items.length</code>.</p>
<p>Since the result of this operation is a floating-point number and arrays are integer-based, we can use <code>Math.floor()</code> to round that number down.</p>
<p>This approach guarantees that the generated index is always in the range <code>0..items.length</code> and will never produce an invalid index.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 22 Jan 2024 00:00:00 +0000</pubDate>
                                    <category>JavaScript</category>
                            </item>
                    <item>
                <title><![CDATA[What are UTM tags?]]></title>
                <link>https://ryangjchandler.co.uk/posts/what-are-utm-tags</link>
                <description><![CDATA[<p>UTM tags, short for &quot;Urchin tracking module&quot; tags, are parameters that can be added to URLs to provide more accurate traffic information to analytics providers.</p>
<p>They were initially introduced by the predecessor to Google Analytics named &quot;Urchin&quot;, hence the name. Since their introduction, near enough all analytics software provides support for breaking down traffic results by these tags.</p>
<p>As somebody who has only recently started learning more about SEO and improving my analysis of web traffic, I thought it might be useful for others to breakdown each of the &quot;tags&quot; and how they're intended to be used.</p>
<p>There are 5 main UTM tags available:</p>
<ul>
<li><code>utm_source</code></li>
<li><code>utm_medium</code></li>
<li><code>utm_campaign</code></li>
<li><code>utm_content</code></li>
<li><code>utm_term</code></li>
</ul>
<p>Let's take a look at each of them and how they're supposed to be used.</p>
<h3>Source</h3>
<p>The <code>utm_source</code> tag is used to determine which site or origin provided the traffic. If you post a link on Twitter, you might set the tag to <code>twitter</code> and then use this to breakdown conversions inside of your analytics tool.</p>
<h3>Medium</h3>
<p>The purpose of the <code>utm_medium</code> tag is to distinguish between the generic <em>type</em> of marketing medium, e.g. social media, email, affiliates, etc.</p>
<p>This tag allows you to analyse traffic as a broader level – rather than looking at specific social media sites, you can instead see how much traffic originates from <em>all</em> social media sites.</p>
<h3>Campaign</h3>
<p>The <code>utm_campaign</code> tag lets you give distinct names to each of your marketing pushes &amp; campaigns, so that you can compare performance across multiple campaigns.</p>
<p>For example, you might run a marketing campaign and realise that email marketing is performing badly (using the <code>utm_medium</code> and <code>utm_source</code> tags). After making some changes to your marketing material, you want to re-market the same URLs and compare their performance.</p>
<p>If you give each campaign a different <code>utm_campaign</code> source, you can do the comparison and reporting quite easily inside of most mainstream analytics tools.</p>
<h3>Content</h3>
<p>If you have multiple CTAs on a single page, you can use the <code>utm_content</code> tag to describe which CTA or link was used.</p>
<p>For example you have 2 &quot;Buy&quot; buttons on a page – one of them is green, one of them is black. If you add <code>utm_content=green-buy</code> and <code>utm_content=black-buy</code>, you can compare the conversion rates and traffic from each button and do some rudimentary A/B testing.</p>
<h3>Term</h3>
<p>This one is normally optional. You'll only really want to use it when you run paid ads that rely on keyword terms.</p>
<p>When you run one of these paid keyword ads, you can place the keywords inside of the <code>utm_term</code> tag and compare the performance between different keywords to see how people are landing on your page.</p>
<h3>Building URLs with UTM tags</h3>
<p>It's pretty tedious manually adding UTM tags to URLs, especially when the URLs are longer and you lose track of where you were.</p>
<p>To help with this, I've built a little tool that is available on this website to help generate URLs with UTM tags! Head over to the <a href="https://ryangjchandler.co.uk/tools/utm?utm_source=utm-blog-post&amp;utm_medium=blog&amp;utm_campaign=utm-blog-post">UTM Tag Builder</a> page and start building out UTM-tagged URLs.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 08 Jan 2024 00:00:00 +0000</pubDate>
                                    <category>General</category>
                            </item>
                    <item>
                <title><![CDATA[My favourite Alpine.js plugins]]></title>
                <link>https://ryangjchandler.co.uk/posts/my-favourite-alpinejs-plugins</link>
                <description><![CDATA[<p>I've been using <a href="https://alpinejs.dev/">Alpine.js</a> since it came out and have spent countless hours developing my own plugins and using other peoples plugins, so here's a list of some of my favourites.</p>
<h3><a href="https://github.com/ryangjchandler/alpine-clipboard"><code>@ryangjchandler/alpine-clipboard</code></a></h3>
<p>I'll start the list off with a biased choice. This is a package that I built to make copying things to the clipboard super easy.</p>
<p>You can use the <code>$clipboard()</code> magic function to copy some text to the clipboard, or if you're using a button and don't want to write out the <code>x-on:click</code> handler yourself, you can use <code>x-clipboard</code> too.</p>
<p>The underlying browser API is <code>Promise</code> based, so it's also possible to do something <em>after</em> the text has been successfully copied.</p>
<pre><code class="language-js">$clipboard(text).then(() =&gt; { ... })
</code></pre>
<p>Overall, this is a super useful plugin and I'm glad I made it because I use it in basically all of my projects.</p>
<h3><a href="https://github.com/marcreichel/alpine-autosize"><code>@marcreichel/alpine-autosize</code></a></h3>
<p>This is another excellent plugin that I use a lot. It turns a plain ol' <code>&lt;textarea&gt;</code> into an auto-resizing one, which is great for UX.</p>
<p>You install the plugin, add <code>x-autosize</code> to the <code>&lt;textarea&gt;</code> and it just works!</p>
<pre><code class="language-html">&lt;textarea x-autosize&gt;&lt;/textarea&gt;
</code></pre>
<h3><a href="https://github.com/ryangjchandler/alpine-tooltip"><code>@ryangjchandler/alpine-tooltip</code></a></h3>
<p>This is another one of my plugins that integrates Tippy with Alpine. It's used in a bunch of projects and the number of CDN hits is regularly above 900,000!</p>
<p>There's not much more to say about it really – it just makes it super easy to create tooltips without rolling the code yourself.</p>
<pre><code class="language-html">&lt;button x-tooltip.raw=&quot;Saving will bust the cache automatically.&quot;&gt;
	Save
&lt;/button&gt;
</code></pre>
<h3><a href="https://alpinejs.dev/plugins/collapse"><code>@alpinejs/collapse</code></a></h3>
<p>This one is an official plugin. It provides a new directive <code>x-collapse</code> that work in conjuction with <code>x-show</code> to make &quot;revealable&quot; or &quot;collapsing&quot; elements super simple.</p>
<p>There are browser elements like <code>&lt;detail&gt;</code> that also do this, but they don't have any transitions or animations. That's the sort of polish you want in your product, that's the sort of polish that this plugin provides.</p>
<pre><code class="language-html">&lt;button type=&quot;button&quot; x-on:click=&quot;open = !open&quot;&gt;
	Toggle
&lt;/button&gt;

&lt;div x-show=&quot;open&quot; x-collapse&gt;
	Toggled!
&lt;/div&gt;
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 07 Jan 2024 00:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Removing icons from table actions in Filament]]></title>
                <link>https://ryangjchandler.co.uk/posts/removing-icons-from-table-actions-in-filament</link>
                <description><![CDATA[<p>I'm not a huge fan of adding icons to actions inside of my Filament tables. The default set of actions that ship with Filament, such as <code>EditAction</code> and <code>DeleteAction</code>, come pre-configured with sensible icons from the Heroicons icon pack.</p>
<p><img src="https://ryangjchandler.co.uk/storage/x0O5G3q6GrECjnzmxAFsIX7yx2l3la8eRliJx6eO.png" alt="" />
They're just not to my taste and become somewhat of a visual distraction, especially when they're repeated across all rows and those rows already have a good amount of other &quot;stuff&quot;.</p>
<p>Now you could go through each <code>Resource</code> and add <code>-&gt;icon(null)</code> to the actions – but that is quite a long task. Instead, I would recommend using one of Filament's lifecycle hooks.</p>
<p>Filament provides a <code>configureUsing()</code> method on all of its components which let's you apply a set of default configuration choices on a particular component, without having to call the same chain of methods across all usages of said component.</p>
<p>This method can be used to remove the default icons that Filament provides. Inside of a <code>ServiceProvider::boot()</code> method, or even a <code>PanelProvider::boot()</code> method (since <code>PanelProvider</code> classes are just <code>ServiceProvider</code> classes), you can call this method and remove those icons.</p>
<pre><code class="language-php">EditAction::configureUsing(function (EditAction $action): void {
    $action-&gt;icon(null);
}, isImportant: true);
</code></pre>
<p>The <code>isImportant</code> named argument here ensures that the configuration callback you provide is executed <em>after</em> all &quot;unimportant&quot; configuration callbacks, as well as after the component's <code>setUp()</code> method is called.</p>
<p>This is necessary for removing these icons, since they're set inside of the <code>EditAction::setUp()</code> method.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 04 Jan 2024 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[2023: A year in review]]></title>
                <link>https://ryangjchandler.co.uk/posts/2023-a-year-in-review</link>
                <description><![CDATA[<p>2023 has been a bit of a weird year for me. The last couple of years I've spent a tonne of time on open-source projects, tweeting, and writing blog posts. 2023 was kind of a quiet one on that front.</p>
<h3>Programming</h3>
<p>In terms of the stuff that I did work on:</p>
<ul>
<li>Developed a couple of Filament plugins.</li>
<li>Started building a static analyser and language server for PHP &amp; PXP projects.</li>
<li>Started re-writing the static analyser and language server for PHP &amp; PXP projects in Rust.</li>
</ul>
<h3>Content Creation</h3>
<p>I started writing a book titled <strong>Data Structures in PHP</strong>. Writing a book is waaaay harder than it seems. You don't want to be too verbose because it's boring to read, but you also don't want to be too vague because it takes away all of the value. Finding the perfect balance between the two takes time, but I got there in the end.</p>
<p>I originally wanted the book to be a sort of encyclopedia for all things data structures, but it turned into more of an introduction to data structures. That's not a bad thing, since there are plenty of folks who haven't really interacted with data structures in their &quot;raw&quot; form before.</p>
<p><em>If you're interested in the book, you can get a 15% discount using code <strong>BLOG15</strong> – or use <a href="https://store.ryangjchandler.co.uk/checkout/buy/ef8e5b93-1c3b-4e32-8bae-f0798e537f11?logo=0&amp;enabled=112489">this link</a> and it will be automatically applied.</em></p>
<p>Once I released my book, I felt like I had the taste for informative content creation, so I started planning a course that teaches Rust to PHP developers.</p>
<p>That's still not fully released, but I have been recording videos and customers who pre-order (for a heavily reduced price) can start watching the videos as they release.</p>
<p>If you're interested in the course, you <a href="https://rustforphp.dev/">can still pre-order</a> and get instant access to some videos.</p>
<h3>Conferences</h3>
<h4>Laravel Live UK</h4>
<p>I did my first ever conference talk in June at Laravel Live UK. It was a pretty cool experience – public speaking has never really phased me, but doing it in front of people who know about the subject matter is a bit daunting, you say one thing that's wrong, you look like a fool.</p>
<p>Here are a couple of photos from the event:</p>
<p><img src="https://ryangjchandler.co.uk/storage/CWB7wMBpMNmv4G0stwjBnFShnDCrU0N809eEH4k8.jpg" alt="" />
<img src="https://ryangjchandler.co.uk/storage/6UM5rYB6jJOLJNPbeR33RC87ld8cEeGJPKHynqgy.jpg" alt="" />
Huge thanks to Jonty for giving me this opportunity, I really hope I can speak at Laravel Live again at the next event.</p>
<h4>Laracon US</h4>
<p>2023 was also the year I attended my first Laracon! I flew all the way to Nashville to see some wicked talks, meet some online friends in person and overall have a really awesome time.</p>
<p>Getting there was an absolute nightmare – my outbound flight from Heathrow was fine but some adverse weather conditions resulted in a cancelled connecting flight and a 7-hour layover at JFK.</p>
<p>Despite that, it was really really good. Very excited to see where Laracon US 2024 is and perhaps I'll apply to speak..</p>
<h3>Personal</h3>
<h4>Moving</h4>
<p>Back in March we sold our first house that we purchased back in 2021. It wasn't the smoothest sale and purchase... a burst water pipe at our new property prior to completion put a massive delay on the whole thing – plus some legal holdups – it took quite a while for the purchase of our new house to go through.</p>
<p>The new house is a bit of a project, a doer-upper if you like. I do enjoy a challenge and as we work on things I can see it all coming together and being a house that we stay in for a good few years.</p>
<h4>Jobs</h4>
<p>I think this year is the first year that I got somewhat close to being &quot;burned out&quot;. For a long time I was working a full-time job <em>and</em> freelancing, which was <strong>a lot</strong> of work. Back in June, I stopped freelancing and changed jobs to actually start working full-time for one of my freelance clients.</p>
<p>It's been a nice change of pace and I've had a lot more time to work on side-projects and stuff. I do still find myself wondering what to do though – when you go from doing so much all of the time, to doing less, you find yourself lost, unsure of what to do.</p>
<p>That's one of the reasons I started writing a book, working on a video course and a couple of new SaaS projects.</p>
<h3>Looking forward to 2024</h3>
<p>The main goal for 2024 is to work on cool shit, and enjoy working on cool shit. I don't want to put pressure on certain things, but I do see myself getting PXP to a point of usability.</p>
<p>I want to make sure that all of my work on open-source projects and other side-projects is sustainable, so finding ways to make that happen is my other goal.</p>
<p>Thanks for reading, if you made it this far.</p>
<p>Happy New Year!</p>
<p>Ryan</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 31 Dec 2023 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[How to find your php.ini file]]></title>
                <link>https://ryangjchandler.co.uk/posts/how-to-find-your-php-ini-file</link>
                <description><![CDATA[<h2>What is the <code>php.ini</code> file?</h2>
<p>PHP uses an INI file for all of it's configuration. It gets loaded when PHP starts up and is used to configure extensions and various PHP features.</p>
<p>How you locate your <code>php.ini</code> file all depends on what sort of access you have to your server. I'll detail a couple of different methods below.</p>
<h2>Command-line access</h2>
<p>If you have access to <code>php</code> through the command-line (inside of your terminal - maybe via SSH), you can find the <code>php.ini</code> file quite quickly.</p>
<ol>
<li>Open your terminal locally or connected to your server via SSH.</li>
<li>Run the <code>php --ini</code> command.</li>
<li>Locate the path to the <code>php.ini</code> file in the output.</li>
</ol>
<pre><code>% php --ini
Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.2
Loaded Configuration File:         /opt/homebrew/etc/php/8.2/php.ini
Scan for additional .ini files in: /opt/homebrew/etc/php/8.2/conf.d
Additional .ini files parsed:      /opt/homebrew/etc/php/8.2/conf.d/error_log.ini,
/opt/homebrew/etc/php/8.2/conf.d/ext-opcache.ini,
/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini
</code></pre>
<h2><code>phpinfo()</code></h2>
<p>If you can load a PHP script in the browser, you can use the <code>phpinfo()</code> function to output all of PHP's configuration values and find the path to the <code>php.ini</code> file.</p>
<p>Put the following snippet of code into a PHP file and load the file in your browser.</p>
<pre><code class="language-php">&lt;?php
	
phpinfo();
</code></pre>
<p><img src="https://ryangjchandler.co.uk/storage/8rNYkOTyLLZXftqGyfyHavcXpouST9Khdr38MJEy.png" alt="" /></p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 08 Nov 2023 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Autocomplete Tailwind classes inside of Blade class directives]]></title>
                <link>https://ryangjchandler.co.uk/posts/autocomplete-tailwind-classes-inside-of-blade-class-directives</link>
                <description><![CDATA[<p>Tailwind's Intellisense plugin for Visual Studio Code is great, but as somebody who uses Laravel Blade I am slowed down massively when writing Blade components or dynamic CSS class lists with the <code>@class</code> directive.</p>
<p>If you open up your <code>settings.json</code> file inside of Visual Studio Code, you can use an experimental feature in the Tailwind extension to get autocomplete inside of <code>$attributes-&gt;class()</code> and <code>@class()</code>.</p>
<pre><code class="language-json">{
    // ...
    &quot;tailwindCSS.experimental.classRegex&quot;: [
        [
            &quot;@?class\\(([^]*)\\)&quot;,
            &quot;'([^']*)'&quot;
        ]
    ]
}
</code></pre>
<p>Save this file, open up a Blade template and give it a go. You should now be able to autocomplete Tailwind classes in the following scenarios (<code>^</code> indicates cursor position):</p>
<pre><code class="language-blade">@class([
    '^'
])

{{ $attributes-&gt;class('^') }}

{{ $attributes-&gt;class([
    '^'
]) }}
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 04 Oct 2023 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Scroll to the first error message with Livewire]]></title>
                <link>https://ryangjchandler.co.uk/posts/scroll-to-the-first-error-message-with-livewire-3x</link>
                <description><![CDATA[<p>When submitting a form with Livewire, you probably want to render out some error messages and show them to your user. A nice enhancement is automatically scrolling to the first error message on the page.</p>
<p>First, make sure that the element that renders the error message has some sort of &quot;marker&quot; class or data attribute that marks it as an error message.</p>
<pre><code class="language-blade">@error('name')
    &lt;p class=&quot;error-message text-danger-red&quot;&gt;
        {{ $message }}
    &lt;/p&gt;
@enderror
</code></pre>
<p>Now inside of a <code>&lt;script&gt;</code> tag, you can write the following code.</p>
<pre><code class="language-js">Livewire.hook('commit', ({ succeed }) =&gt; {
    succeed(() =&gt; {
        setTimeout(() =&gt; {
            const firstErrorMessage = document.querySelector('.error-message')

            if (firstErrorMessage !== null) {
                firstErrorMessage.scrollIntoView({ block: 'center', inline: 'center' })
            }
        }, 0)
    })
}) 
</code></pre>
<p>Using <a href="https://livewire.laravel.com/docs/javascript">Livewire's JavaScript API</a> you can hook into the lifecycle of a request. The <a href="https://livewire.laravel.com/docs/javascript#commit-hooks"><code>commit</code></a> hook can be used to do something during the lifecycle of a single commit.</p>
<p>A callback provided to the <code>succeed()</code> function will be invoked once the commit has been processed by Livewire. Then on the next tick in the event loop, you can check for an error message element and scroll it into view.</p>
<p>If you're using Alpine, you can place this piece of code into the <code>init()</code> method or <code>x-init</code> directive and instead of calling <code>setTimeout</code> with a duration of <code>0</code>, use the <code>$nextTick</code> magic method which has the same outcome.</p>
<pre><code class="language-html">&lt;form x-data=&quot;{
    init() {
        Livewire.hook('commit', ({ succeed }) =&gt; {
            succeed(() =&gt; {
                this.$nextTick(() =&gt; {
                    const firstErrorMessage = document.querySelector('.error-message')

                    if (firstErrorMessage !== null) {
                        firstErrorMessage.scrollIntoView({ block: 'center', inline: 'center' })
                    }
                })
            })
        })
    }
}&quot;&gt;
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 18 Sep 2023 00:00:00 +0000</pubDate>
                                    <category>Livewire</category>
                            </item>
                    <item>
                <title><![CDATA[Understanding serialisation in PHP]]></title>
                <link>https://ryangjchandler.co.uk/posts/understanding-serialisation-in-php</link>
                <description><![CDATA[<p>Serialisation, or serialization, is a process that takes in a piece of data and generates a storable or transportable representation of the data.</p>
<p>The serialised representation of data can be achieved with various formats. JSON is very common as most languages have some form of JSON encoding and decoding. You could also use XML, YAML or even a raw string of bytes.</p>
<p>You're probably familiar with PHP's <code>serialize()</code> function. This function accepts a single value and returns the serialised version as a string.</p>
<p>What's unique about serialisation in PHP is that it actually uses a special serialisation format to represent various types of data, including arrays and objects.</p>
<p>Each data type that PHP can serialise has it's own representation and notation when serialised. Let's break these down and look at what  they represent.</p>
<h3>Booleans</h3>
<p>Booleans are very simple.</p>
<pre><code>b:0;
b:1;
</code></pre>
<p>The type specifier for boolean values is <code>b</code>. That is then followed by a colon and an integer representation of the boolean itself, so <code>false</code> becomes <code>0</code> and <code>true</code> becomes <code>1</code>.</p>
<h3>Null</h3>
<p>Serialising <code>null</code> produces the following.</p>
<pre><code>N;
</code></pre>
<p>Null doesn't have any additional data to include, so it is represented by a single <code>N</code> character.</p>
<h3>Integers and Floats</h3>
<p>Serialising the value <code>100</code> with <code>serialize()</code> returns the following string.</p>
<pre><code>i:100;
</code></pre>
<p>Serialised integers are represented with the character <code>i</code>, followed by a colon and the integer's value.</p>
<aside class="aside--right aside--context__note"><p>The value of the integer is always serialised in &quot;decimal&quot; form (base 10). The serialised version <strong>does not</strong> contain information about the original format of the value (hexadecimal, octal, binary, etc).</p></aside>
<p>Serialising the value <code>100.5</code> has a very similar format.</p>
<pre><code>d:100.5;
</code></pre>
<p>The only difference is that instead of an <code>i</code> for integer, the type specifier is <code>d</code> for &quot;double&quot;.</p>
<h3>Strings</h3>
<p>Serialised strings carry some extra information with them. The code below is the result of serialising <code>Hello, world</code>.</p>
<pre><code class="language-php">s:12:&quot;Hello, world&quot;;
</code></pre>
<p>The type specifier is <code>s</code>. This is then followed by a colon and the result of <code>strlen($value)</code>. Then that is followed by another colon and the original value wrapped in double quotes.</p>
<pre><code>s:[strlen(value)]:&quot;[value]&quot;
</code></pre>
<p>The reason the length of the string is important here is that is tells the piece of code unserialising how many characters or bytes it needs to process to find the string value.</p>
<p>It also helps in lower level languages where strings might be stored as an array of bytes. If you know how many bytes the string is, you can allocate the correct amount and avoid potential memory issues.</p>
<h3>Arrays</h3>
<p>Array serialisation is a little more involved, since a PHP array has keys <em>and</em> values. Let's first serialise an empty array <code>[]</code>.</p>
<pre><code>a:0:{}
</code></pre>
<p>The type specifier for an array is <code>a</code>. The second component in the serialised data is the length of the array. The third component is where the key and values in the array are placed.</p>
<pre><code>a:[count(value)]:{...values}
</code></pre>
<p>To see how the values are serialised, we can serialise a simple array with 3 values <code>[1, 2, 3]</code>.</p>
<pre><code>a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}
</code></pre>
<p>The stuff inside of the curly braces contains information about the keys <em>and</em> values inside of the array.</p>
<aside class="aside--left aside--context__info"><p>Remember that although we didn't specify any keys in the array, PHP will automatically index the values starting from <code>0</code>.</p></aside>
<p>The generic formation for the values is as follows.</p>
<pre><code>{key;value;key;value;key;value}
</code></pre>
<p>Expanding the original array into a more explicit, keyed equivalent.</p>
<pre><code class="language-php">[
    0 =&gt; 1,
    1 =&gt; 2,
    2 =&gt; 3,
]
</code></pre>
<p>We can look at each key-value pair and see that their serialised values are placed inside of the curly braces, in order.</p>
<pre><code>{i:0;i:1;i:1;i:2;i:2;i:3;}
 ^0  ^1  ^1  ^2  ^2  ^3
</code></pre>
<p>If we changed the array slightly and used strings for the keys instead.</p>
<pre><code class="language-php">[
    'a' =&gt; 1,
    'b' =&gt; 2,
    'c' =&gt; 3,
]
</code></pre>
<pre><code>a:3:{s:1:&quot;a&quot;;i:1;s:1:&quot;b&quot;;i:2;s:1:&quot;c&quot;;i:3;}
     ^a      ^1  ^b      ^2  ^c      ^3
</code></pre>
<p>It's also possible to serialise nested arrays, useful for more complex structures.</p>
<pre><code>a:1:{i:0;a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}}
</code></pre>
<h3>Objects</h3>
<p>The most complex serialisation format can be seen when serialising objects.</p>
<p>Let's take a simple <code>Nothing</code> class, instantiate it and serialise it.</p>
<pre><code class="language-php">class Nothing
{
    // ...
}

serialise(new Nothing);
</code></pre>
<pre><code>O:7:&quot;Nothing&quot;:0:{}
</code></pre>
<p>The type specifier for serialised objects is <code>O</code>. That is followed by the length of the class name, and the class name itself wrapped in double quotes.</p>
<p>The number following the class name is the number of properties that the object has. The curly braces then holds the serialised properties, in a similar format to the arrays.</p>
<p>Taking a new class <code>User</code> that has 2 properties — <code>$name</code> and <code>$age</code> — we can see how property values are serialised.</p>
<pre><code class="language-php">class User
{
    public function __construct(
        public $name,
        public $age,
    ) {}
}

serialize(new User(
    name: &quot;Ryan&quot;,
    age: 23
));
</code></pre>
<pre><code>O:6:&quot;User&quot;:2:{s:4:&quot;name&quot;;s:4:&quot;Ryan&quot;;s:3:&quot;age&quot;;i:23;}
</code></pre>
<p>The <code>User</code> object has 2 properties, so the name for each property is serialised as a string and the serialised value comes after.</p>
<p>Converting this format into a simplified grammar might look something like below.</p>
<pre><code>O:[strlen(value::class)]:&quot;[value::class]&quot;:[count(properties)]:{...property}

property ::= [name];[value]
</code></pre>
<h4>Non-public properties</h4>
<p>The <code>User</code> class only has public properties, but the <code>serialize()</code> function can also serialise protected and private properties.</p>
<p>Starting with protected properties, let's write a new class <code>SensitiveStuff</code> that has a single protected property <code>$password</code>.</p>
<pre><code class="language-php">class SensitiveStuff
{
    public function __construct(
        protected $password,
    ) {}
}

serialize(new SensitiveStuff(
    password: 'password123'
));
</code></pre>
<pre><code>O:14:&quot;SensitiveStuff&quot;:1:{s:11:&quot;\0*\0password&quot;;s:11:&quot;password123&quot;;}
</code></pre>
<p>Everything looks very similar, but you'll notice there are some extra characters where the property name is. Instead of the property name being serialised to <code>s:8:&quot;password&quot;</code>, there are 3 additional characters: <code>\0*\0</code>.</p>
<p>The <code>\0</code> character is known as the &quot;null terminator&quot; or &quot;null byte&quot;. The <code>*</code> (asterisk) is what marks this property as protected.</p>
<p>If we change the visibility of the property to private and re-serialise it, it will produce a slightly different value.</p>
<pre><code>O:14:&quot;SensitiveStuff&quot;:1:{s:24:&quot;\0SensitiveStuff\0password&quot;;s:11:&quot;password123&quot;;}
</code></pre>
<p>This time, the property name has been prefixed with a null byte character, the class name of the object and another null byte. This pattern represents a private property.</p>
<h2>Resources</h2>
<p>It's not possible to serialise <code>resource</code> values in PHP. When you attempt to serialise an object with a resource stored inside of a property, it will be cast to an integer and serialised as <code>0</code>.</p>
<h2>Sign off</h2>
<p>Thanks for reading! Hopefully this has given you a bit of an introduction to how various value types are serialised in PHP.</p>
<p>In another post I'll write about writing your own deserialisation logic in another programming language, most likely JavaScript!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 16 Aug 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Rendering & Echo (Build your own template engine in PHP)]]></title>
                <link>https://ryangjchandler.co.uk/posts/build-your-own-template-engine-in-php-rendering-echo</link>
                <description><![CDATA[<p>Let's build a tiny template engine for PHP!</p>
<p>This post will focus on rendering the template and echoing out data that can be escaped with <code>htmlspecialchars()</code>.</p>
<p>Before we start writing code we need to take care of the most important part of any programming project — giving the project a name. I'm going to call it Stencil.</p>
<p>The templates themselves will all be plain PHP. We won't be creating any special syntax like Twig or Blade, we'll focus solely on templating functionality.</p>
<p>We'll begin by creating the main class.</p>
<pre><code class="language-php">class Stencil
{
    public function __construct(
        protected string $path,
    ) {}
}
</code></pre>
<p>The <code>Stencil</code> class will need to know where the templates are located — so that gets passed in through the constructor.</p>
<p>To actually render our templates, we'll need a <code>render()</code> method.</p>
<pre><code class="language-php">class Stencil
{
    // ...

    public function render(string $template, array $data = []): string
    {
        // ?
    }
}
</code></pre>
<p>The <code>render()</code> method accepts the name of the template and an array of data variables that will be accessible inside of said template.</p>
<p>We now need to do three things:</p>
<ol>
<li>Form a path to the requested template.</li>
<li>Make sure the template exists.</li>
<li>Render the template with the provided data.</li>
</ol>
<pre><code class="language-php">class Stencil
{
    // ...

    public function render(string $template, array $data = []): string
    {
        $path = $this-&gt;path . DIRECTORY_SEPARATOR . $template . '.php';

        if (! file_exists($path)) {
            throw TemplateNotFoundException::make($template);
        }

        // ?
    }
}
</code></pre>
<p>The first two on the list are easy to do. Stencil will only look for <code>.php</code> files so forming a path is just a case of concatenating some strings. If the requested template contains any directory separators, that will handle the nesting of templates inside of directories.</p>
<p>If the file doesn't exist, throw a custom <code>TemplateNotFoundException</code>.</p>
<p>To cover the third point in the list, actually rendering the template, we'll want to make a new class called <code>Template</code>. This will house all of the methods available to the template and handle the real rendering side of things.</p>
<pre><code class="language-php">class Template
{
    public function __construct(
        protected string $path,
        protected array $data = [],
    ) {}

    public function render(): string
    {
        // ?
    }
}
</code></pre>
<pre><code class="language-php">class Stencil
{
    // ...

    public function render(string $template, array $data = []): string
    {
        $path = $this-&gt;path . DIRECTORY_SEPARATOR . $template . '.php';

        if (! file_exists($path)) {
            throw TemplateNotFoundException::make($template);
        }

        return (new Template($path, $data))-&gt;render();
    }
}
</code></pre>
<p>To obtain the rendered template as a string, we'll take advantage of PHP's output buffers. When you call <code>ob_start()</code> PHP will start to capture anything that the application attempts to output (<code>echo</code>, raw HTML, etc).</p>
<p>You can retrieve that as a string and then stop capturing the output using <code>ob_get_clean()</code>. A combination of these two functions and an <code>include</code> will let us evaluate a template file.</p>
<pre><code class="language-php">class Template
{
    // ...

    public function render(): string
    {
        ob_start();

        include $this-&gt;path;

        return ob_get_clean();
    }
}
</code></pre>
<p>This will handle rendering the template, but it doesn't do anything to let the template access those data variables stored inside of <code>$data</code>. PHP being the wonderful language it is provides another function called <code>extract()</code> that accepts an array of key value pairs.</p>
<p>The key for each item in the array will be used to create a new variable in the current scope using the associated value. Since <code>include</code> and its relatives always execute the PHP file in the current scope, the template will be able to access the extracted variables.</p>
<pre><code class="language-php">class Template
{
    // ...

    public function render(): string
    {
        ob_start();

        extract($this-&gt;data);

        include $this-&gt;path;

        return ob_get_clean();
    }
}
</code></pre>
<p>Perfect! Now we can render a template and give it access to the data variables provided. There is one thing that we haven't considered... if we wanted to create some variables inside of the <code>render()</code> method, our template would also be able to access those. That's not what we want!</p>
<p>To solve that problem, we need to wrap the <code>extract()</code> and <code>include</code> calls in an immediately-invoke closure — that way, the template will only have access to the variables <em>inside</em> of the closure.</p>
<pre><code class="language-php">class Template
{
    // ...

    public function render(): string
    {
        ob_start();

        (function () {
            extract($this-&gt;data);

            include $this-&gt;path;
        })();

        return ob_get_clean();
    }
}
</code></pre>
<p>The final piece of the puzzle is a method for escaping values when echoing them. Closures inherit <code>$this</code> which means our template will be able to call any method we define on the <code>Template</code> class. Let's create an <code>e()</code> method that accepts a value and escapes it using <code>htmlspecialchars()</code>.</p>
<pre><code class="language-php">class Template
{
    // ...

    public function e(?string $value): string
    {
        return htmlspecialchar($value ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }
}
</code></pre>
<p>And like that we have a little template engine for our PHP projects.</p>
<pre><code class="language-php">&lt;h1&gt;
    Hello, &lt;?= $this-&gt;e($name) ?&gt;!
&lt;/h1&gt;
</code></pre>
<p>The template above can be rendered using our engine:</p>
<pre><code class="language-php">$stencil-&gt;render('hello', [
    'name' =&gt; 'Ryan'
]);
</code></pre>
<p>And will output the following HTML:</p>
<pre><code class="language-html">&lt;h1&gt;
    Hello, Ryan!
&lt;/h1&gt;
</code></pre>
<p>In a future blog post we'll implement support for partials, allowing us to separate out common templates and use them in multiple places.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 14 Jun 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Write a lexer in PHP with Lexical]]></title>
                <link>https://ryangjchandler.co.uk/posts/write-a-lexer-in-php-with-lexical</link>
                <description><![CDATA[<p>I recently released a new PHP package called &quot;Lexical&quot;. It provides a set of attributes and objects to build regular expression based lexers in PHP.</p>
<p>If you want to skip the blog post and go straight to the package, the <a href="https://github.com/ryangjchandler/lexical">repository is public on GitHub</a>.</p>
<p>As somebody who enjoys experimenting with parsers and text processing, writing lexers has become a somewhat regular task for me. The first step in reducing boilerplate and copy-paste'd code between projects is to write a package that can handle the tedious task of tokenisation for me.</p>
<p>To demonstrate Lexical's functionality, I'll write a simple lexer that can handle mathematical expressions such as <code>1 + 2</code> or <code>4 / 5 * 6</code>. The lexer will need to handle 4 mathematical operators (<code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>) and numeric values (just integers for now).</p>
<p>We'll by creating a new enumeration that describes the token types.</p>
<pre><code class="language-php">enum TokenType
{
    case Number;
    case Add;
    case Subtract;
    case Multiply;
    case Divide;
}
</code></pre>
<p>Lexical provides a set of attributes that can be added to each <code>case</code> in the enumeration:</p>
<ul>
<li><code>Regex</code> - accepts a single regular expression.</li>
<li><code>Literal</code> - accepts a string of continuous characters.</li>
<li><code>Error</code> - designates a specific enumeration case as the &quot;error&quot; type.</li>
</ul>
<p>Adding the aforementioned attributes to <code>TokenType</code> looks a little something like the code below.</p>
<pre><code class="language-php">enum TokenType
{
    #[Regex(&quot;[0-9]+&quot;)]
    case Number;
    
    #[Literal(&quot;+&quot;)]
    case Add;
    
    #[Literal(&quot;-&quot;)]
    case Subtract;
    
    #[Literal(&quot;*&quot;)]
    case Multiply;

    #[Literal(&quot;/&quot;)]
    case Divide;
}
</code></pre>
<aside class="aside--left aside--context__note"><p>There's no need to add the <code>/</code> delimiters to the RegEx. Those are added accordingly by lexer.</p></aside>
<p>With the attributes in place, we can start to build a lexer using the <code>LexicalBuilder</code>.</p>
<pre><code class="language-php">$lexer = (new LexicalBuilder)
    -&gt;readTokenTypesFrom(TokenType::class)
    -&gt;build();
</code></pre>
<p>The <code>readTokenTypesFrom()</code> method is used to tell the builder where it should look for the various tokenising attributes. The <code>build()</code> method will take those attributes and return an object that implements <code>LexerInterface</code>, configured to look for the specified token types.</p>
<p>Then it's just a case of calling the <code>tokenise()</code> method on the lexer object.</p>
<pre><code class="language-php">$tokens = $lexer-&gt;tokenise('1+2'); // -&gt; [[TokenType::Number, '1'], [TokenType::Add, '+'], [TokenType::Number, '2']]
</code></pre>
<p>The <code>tokenise()</code> method returns a list of tuples, where the first item is the &quot;type&quot; (<code>TokenType</code> in this example) and the second item is the &quot;literal&quot; (a string containing the matched characters).</p>
<h2>Skipping whitespace and other patterns</h2>
<p>The lexer currently understands <code>1+2</code> but it would fail to tokenise <code>1 + 2</code> (added whitespace). This is because by default it expects each and every possible character to fall into a pattern. If it encountered an invalid or unrecognised character in the input, it would throw an exception (by default).</p>
<p>The whitespace is insignificant in this case, so can be skipped safely. To do this, we need to add a new <code>Lexer</code> attribute to the <code>TokenType</code> enumeration and pass through a regular expression that matches the characters we want to skip.</p>
<p>The <code>Lexer</code> attribute is used to configure the generic behaviour of the lexer. <code>skip</code> is the only option in the current version.</p>
<pre><code class="language-php">#[Lexer(skip: &quot;[ \t\n\f]+&quot;)]
enum TokenType
{
    // ...
}
</code></pre>
<p>Now the lexer will skip over any whitespace characters and successfully tokenise <code>1 + 2</code>.</p>
<h2>Error handling</h2>
<p>When a lexer encounters an unexpected character, it will throw an <code>UnexpectedCharacterException</code>.</p>
<pre><code class="language-php">try {
    $tokens = $lexer-&gt;tokenise();
} catch (UnexpectedCharacterException $e) {
    dd($e-&gt;character, $e-&gt;position);
}
</code></pre>
<p>As mentioned above, there is an <code>Error</code> attribute that can be used to mark an enum case as the &quot;error&quot; type.</p>
<pre><code class="language-php">enum TokenType
{
    // ...

    #[Error]
    case Error;
}
</code></pre>
<p>Now when the input is tokenised, the unrecognised character will be consumed like other tokens and will have a type of <code>TokenType::Error</code>.</p>
<pre><code class="language-php">$tokens = $lexer-&gt;tokenise('1 % 2'); // -&gt; [[TokenType::Number, '1'], [TokenType::Error, '%'], [TokenType::Number, '2']]
</code></pre>
<h2>Custom <code>Token</code> objects</h2>
<p>If you prefer to work with dedicated objects instead of Lexical's default tuple values for each token, you can provide a custom callback to map the matched token type and literal into a custom object.</p>
<pre><code class="language-php">class Token
{
    public function __construct(
        public readonly TokenType $type,
        public readonly string $literal,
    ) {}
}

$lexer = (new LexicalBuilder)
    -&gt;readTokenTypesFrom(TokenType::class)
    -&gt;produceTokenUsing(fn (TokenType $type, string $literal) =&gt; new Token($type, $literal))
    -&gt;build();

$lexer-&gt;tokenise('1 + 2'); // -&gt; [Token { type: TokenType::Number, literal: &quot;1&quot; }, ...]
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 07 Jun 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Minimal container (Build your own service container in PHP)]]></title>
                <link>https://ryangjchandler.co.uk/posts/build-your-own-service-container-in-php-minimal-container</link>
                <description><![CDATA[<p>In this mini series, you'll learn how to build your own service container for dependency injection in PHP. I'll start with the simplest PSR-11 compliant container and then add various features until we have a powerful, general purpose container.</p>
<h2>What is a &quot;service container&quot;?</h2>
<p>A service container is a PHP object that is responsible for the instatiation of other objects. You tell the container how to construct the object, then when you need an instance of it in your program, you ask for one.</p>
<h2>What is PSR-11?</h2>
<p><a href="https://www.php-fig.org/psr/psr-11/">PSR-11</a> is a document that specifies a common interface for service containers. It also defines two <code>Exception</code> interfaces that a container must throw to be compliant.</p>
<p>The interface itself only defines two methods:</p>
<pre><code class="language-php">interface ContainerInterface
{
    /**
     * Finds an entry of the container by its identifier and returns it.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.
     * @throws ContainerExceptionInterface Error while retrieving the entry.
     *
     * @return mixed Entry.
     */
    public function get(string $id);

    /**
     * Returns true if the container can return an entry for the given identifier.
     * Returns false otherwise.
     *
     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return bool
     */
    public function has(string $id): bool;
}
</code></pre>
<p>The interface is simple on purpose. By only requiring a container to have these 2 methods, it does not dictate how the services are bound to the container in the first place.</p>
<h2>Building a minimal PSR-11 compliant container</h2>
<p>Let's start by installing the <code>psr/container</code> package that provides <code>ContainerInterface</code> and creating our own <code>Container</code> class that implements that interface.</p>
<pre><code class="language-sh">composer require psr/container
</code></pre>
<pre><code class="language-php">use Psr\Container\ContainerInterface;

class Container implements ContainerInterface
{
    public function get(string $id): mixed
    {
        // ?
    }

    public function has(string $id): bool
    {
        // ?
    }
}
</code></pre>
<p>We want to &quot;bind&quot; some services to the container &amp;mdash so a suitable method name would be <code>bind()</code>. This method needs to accept a <code>string $id</code> and, for now, an <code>object $service</code>.</p>
<p>We can store the bindings in an array on the container.</p>
<pre><code class="language-php">class Container implements ContainerInterface
{
    protected array $bindings = [];

    public function bind(string $id, object $service): void
    {
        $this-&gt;bindings[$id] = $service;
    }
}
</code></pre>
<p>Now the <code>get()</code> and <code>has()</code> methods can read from <code>$bindings</code>.</p>
<pre><code class="language-php">class Container implements ContainerInterface
{
    // ...

    public function get(string $id): mixed
    {
        return $this-&gt;bindings[$id];
    }

    public function has(string $id): bool
    {
        return isset($this-&gt;bindings[$id]);
    }
}
</code></pre>
<p>The <code>ContainerInterface</code> contains a couple of DocBlock comments with <code>@throws</code> annotations. For the <code>Container</code> class to be truly <code>PSR-11</code> compliant, we need to make sure that we throw an <code>Exception</code> that implements the <code>NotFoundExceptionInterface</code> interface when trying to call <code>get()</code> with a non-existent <code>$id</code>.</p>
<pre><code class="language-php">use Psr\Container\NotFoundExceptionInterface;
use Exception;

class ServiceNotFoundException extends Exception implements NotFoundExceptionInterface
{
    // ...
}
</code></pre>
<pre><code class="language-php">class Container implements ContainerInterface
{
    // ...

    public function get(string $id): mixed
    {
        if (! $this-&gt;has($id)) {
            throw new ServiceNotFoundException($id);
        }

        return $this-&gt;bindings[$id];
    }
}
</code></pre>
<p>PSR-11 also defines a <code>ContainerExceptionInterface</code>, stating that Exceptions thrown directly by the container should implement it. The <code>NotFoundExceptionInterface</code> already extends that interface so there's nothing else to do.</p>
<p>We can write some Pest tests for the <code>Container</code> class.</p>
<pre><code class="language-php">it('can be constructed', function () {
    expect(new Container)-&gt;toBeInstanceOf(Container::class);
});

it('can bind and retrieve services', function () {
    $container = new Container;
    $container-&gt;bind('container', $container);

    expect($container-&gt;has('container'))-&gt;toBeTrue();
    expect($container-&gt;get('container'))-&gt;toBeInstanceOf(Container::class)-&gt;toBe($container);
});

it('throws a ServiceNotFoundException when trying to retrieve a non-existent service', function () {
    $container = new Container;

    expect(fn () =&gt; $container-&gt;get('foo'))
        -&gt;toThrow(ServiceNotFoundException::class);
});
</code></pre>
<p>And like that, we have a PSR-11 compliant service container.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 27 May 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Let's write an "esolang" in PHP]]></title>
                <link>https://ryangjchandler.co.uk/posts/lets-write-an-esolang-in-php</link>
                <description><![CDATA[<p>An esolang (esoteric language) is a programming language designed to be used as a joke or test the limits of what can be achieved with a particular language syntax.</p>
<p>In this post, I'll show you how to write your own esolang similar to <a href="https://en.wikipedia.org/wiki/Brainfuck">Brainf*ck</a> in PHP.</p>
<h2>Syntax</h2>
<p>Brainf*ck is a minimal esolang and the original implementation only consisted of 8 symbols — <code>&gt;</code>, <code>&lt;</code>, <code>+</code>, <code>-</code>, <code>.</code>, <code>,</code>, <code>[</code> and <code>]</code>. The language operated on a single contiguous sequence of memory called a &quot;tape&quot;. The memory itself contained 8-bit integers (bytes from <code>0</code> to <code>255</code>) which allows you represent the entire range of ASCII characters.</p>
<p>Here's a small overview of what each symbol / operator does.</p>
<table>
<thead>
<tr>
<th>Symbol</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>&gt;</code></td>
<td>Move pointer to next cell</td>
</tr>
<tr>
<td><code>&lt;</code></td>
<td>Move pointer to previous cell</td>
</tr>
<tr>
<td><code>+</code></td>
<td>Increment the byte at current cell</td>
</tr>
<tr>
<td><code>-</code></td>
<td>Decrement the byte at current cell</td>
</tr>
<tr>
<td><code>.</code></td>
<td>Print the byte as an ASCII character at current cell</td>
</tr>
<tr>
<td><code>,</code></td>
<td>Read a byte from input, store in current cell</td>
</tr>
<tr>
<td><code>[</code></td>
<td>If current cell contains a zero byte, jump to matching <code>]</code></td>
</tr>
<tr>
<td><code>]</code></td>
<td>If current cell contains non-zero byte, jump to matching <code>[</code></td>
</tr>
</tbody>
</table>
<p>The language that we create in this post will be very similar to Brainf*ck, but we'll use sigils and tokens found in the PHP language instead (with some variation). The table below maps the Brainf*ck tokens to our own. Let's combine the words PHP and Eso and call the language &quot;Peso&quot;.</p>
<table>
<thead>
<tr>
<th>Brainf*ck</th>
<th>Peso</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>&gt;</code></td>
<td><code>=&gt;</code></td>
</tr>
<tr>
<td><code>&lt;</code></td>
<td><code>&lt;=</code></td>
</tr>
<tr>
<td><code>+</code></td>
<td><code>+</code></td>
</tr>
<tr>
<td><code>-</code></td>
<td><code>-</code></td>
</tr>
<tr>
<td><code>.</code></td>
<td><code>echo</code></td>
</tr>
<tr>
<td><code>,</code></td>
<td><code>$</code></td>
</tr>
<tr>
<td><code>[</code></td>
<td><code>\</code></td>
</tr>
<tr>
<td><code>]</code></td>
<td><code>/</code></td>
</tr>
</tbody>
</table>
<p>You can treat the <code>\</code> and <code>/</code> tokens like a while loop where the condition is <code>$byte !== 0</code>.</p>
<h2>Lexer</h2>
<p>Let's start by writing a lexer. The job of the lexer will be taking a string of Peso code and converting it into a sequence of tokens.</p>
<p>The best place to start is with the tokens themselves. In this case we can just use an <code>enum</code> to define the tokens, since we don't really care about the characters themselves.</p>
<pre><code class="language-php">enum Token
{
    case RightDoubleArrow;
    case LeftDoubleArrow;
    case Plus;
    case Minus;
    case Echo;
    case Dollar;
    case Backslash;
    case Slash;
}
</code></pre>
<p>The first step in the <code>Lexer</code> will be splitting the input string into separate characters.</p>
<pre><code class="language-php">class Lexer
{
    /** @return array&lt;Token&gt; */
    public function tokenise(string $input): array
    {
        $chars = str_split($input);
        $tokens = [];

        return $tokens;
    }
}
</code></pre>
<p>Then we need to loop over each of the characters and try to find a token. We'll do this with a traditional <code>for</code> loop since it will allow us to skip X iterations for multi-character tokens.</p>
<pre><code class="language-php">class Lexer
{
    /** @return array&lt;Token&gt; */
    public function tokenise(string $input): array
    {
        $chars = str_split($input);
        $tokens = [];

        for ($i = 0; $i &lt; count($chars); $i++) {
            $char = $chars[$i];

            if ($char === '$') {
                $tokens[] = Token::Dollar;
            } elseif ($char === '\\') {
                $tokens[] = Token::Backslash;
            } elseif ($char === '/') {
                $tokens[] = Token::Slash;
            } elseif ($char === '+') {
                $tokens[] = Token::Plus;
            } elseif ($char === '-') {
                $tokens[] = Token::Minus;
            } elseif ($char === '=') {
                if ($chars[++$i] === '&gt;') {
                    $tokens[] = Token::RightDoubleArrow;
                } else {
                    throw UnexpectedCharacterException::make($char, expected: '&gt;');
                }
            } elseif ($char === '&lt;') {
                if ($chars[++$i] === '=') {
                    $tokens[] = Token::LeftDoubleArrow;
                } else {
                    throw UnexpectedCharacterException::make($char, expected: '=');
                }
            } elseif (array_slice($chars, $i, 4) === ['e', 'c', 'h', 'o']) {
                $i += 3;
                $tokens[] = Token::Echo;
            } elseif (ctype_space($char)) {
                continue;
            } else {
                throw UnexpectedCharacterException::make($char);
            }
        }

        return $tokens;
    }
}
</code></pre>
<p>Let's also write a unit test for the <code>Lexer</code> class to make sure that the correct token types are being produced, as well as a test to check that the <code>UnexpectedCharacterException</code> is thrown when we encounter something bad.</p>
<pre><code class="language-php">it('produces the correct tokens', function () {
    $lexer = new Lexer;

    expect($lexer-&gt;tokenise('=&gt; &lt;= + - echo $ \ /'))
        -&gt;toBe([
            Token::RightDoubleArrow,
            Token::LeftDoubleArrow,
            Token::Plus,
            Token::Minus,
            Token::Echo,
            Token::Dollar,
            Token::Backslash,
            Token::Slash
        ]);
});


it('throws an exception when encountering an unexpected character', function () {
    $lexer = new Lexer;

    expect(fn () =&gt; $lexer-&gt;tokenise('foo'))
        -&gt;toThrow(UnexpectedCharacterException::class, 'Unexpected character f');
});
</code></pre>
<h2>Parsing</h2>
<p>Writing a parser for this sort of language is a little bit overkill, but it makes sense to do it now because we'll use it later on to make Peso <em>blazingly fast</em>.</p>
<p>Parsing involves looking at each of the tokens that the <code>Lexer</code> produces and creating a set of structured nodes that represent the operations in the program.</p>
<pre><code class="language-php">class Parser
{
    protected ?Token $current = null;
    
    protected ?Token $next = null;

    protected int $position = 0;

    protected array $tokens;

    public function parse(array $tokens): Program
    {
        if (count($tokens) === 0) {
            return new Program();
        }

        $this-&gt;tokens = $tokens;
        $this-&gt;current = $tokens[$this-&gt;position];
        $this-&gt;next = $tokens[$this-&gt;position + 1] ?? null;

        $nodes = [];

        while ($this-&gt;position &lt; count($tokens)) {
            $nodes[] = $this-&gt;node();
        }

        return new Program($nodes);
    }
}
</code></pre>
<p>This is the boilerplate code for the <code>Parser</code>. It accepts an array of tokens, does some initialisations and then tries to get a <code>Node</code> from the current token. Most of the work is going to be done inside of the <code>Parser::node()</code> method.</p>
<pre><code class="language-php">class Parser
{
    // ...

    protected function node(): Node
    {
        if ($this-&gt;current === Token::Plus) {
            $this-&gt;next();
            return new IncrementNode;
        } elseif ($this-&gt;current === Token::Minus) {
            $this-&gt;next();
            return new DecrementNode;
        } elseif ($this-&gt;current === Token::RightDoubleArrow) {
            $this-&gt;next();
            return new MoveRightNode;
        } elseif ($this-&gt;current === Token::LeftDoubleArrow) {
            $this-&gt;next();
            return new MoveLeftNode;
        } elseif ($this-&gt;current === Token::Dollar) {
            $this-&gt;next();
            return new ReadByteNode;
        } elseif ($this-&gt;current === Token::Echo) {
            $this-&gt;next();
            return new EchoNode;
        } elseif ($this-&gt;current === Token::Backslash) {
            $this-&gt;next();

            $nodes = [];

            while ($this-&gt;current !== null &amp;&amp; $this-&gt;current !== Token::Slash) {
                $nodes[] = $this-&gt;node();
            }

            $this-&gt;expect(Token::Slash);

            return new WhileNode($nodes);
        } else {
            throw UnexpectedTokenException::make($this-&gt;current);
        }
    }

    protected function expect(Token $token): void
    {
        if ($this-&gt;current !== $token) {
            throw UnexpectedTokenException::make($this-&gt;current);
        }

        $this-&gt;next();
    }

    protected function next(): void
    {
        $this-&gt;position++;

        $this-&gt;current = $this-&gt;next;
        $this-&gt;next = $this-&gt;tokens[$this-&gt;position + 1] ?? null;
    }
}
</code></pre>
<p>The <code>Parser::node()</code> method is recursive when it tries to parse <code>\ /</code> loops. It will recursively parse each of the nodes inside of the loop and store them on the <code>WhileNode</code>.</p>
<p>To make sure the <code>Parser</code> is working correctly, let's write a test and check each of the <code>Node</code> values are present.</p>
<pre><code class="language-php">it('can parse all nodes', function () {
    $tokens = (new Lexer)-&gt;tokenise('=&gt; &lt;= + - echo $ \echo/');
    $parser = new Parser;

    expect($parser-&gt;parse($tokens))
        -&gt;toBeInstanceOf(Program::class)
        -&gt;getNodes()
        -&gt;sequence(
            fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(MoveRightNode::class),
            fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(MoveLeftNode::class),
            fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(IncrementNode::class),
            fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(DecrementNode::class),
            fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(EchoNode::class),
            fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(ReadByteNode::class),
            fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(WhileNode::class)
                -&gt;getNodes()
                -&gt;sequence(
                    fn (Expectation $expect) =&gt; $expect-&gt;toBeInstanceOf(EchoNode::class)
                ),
        );
});
</code></pre>
<h2>Execution</h2>
<p>Now that we have a nice structured set of nodes we can start to execute the program. Let's start with a &quot;simple&quot; program that accepts 2 numbers from the input and adds them together.</p>
<pre><code>$ ------------------------------------------------ =&gt; $ \ &lt;= + =&gt; - / &lt;= echo
</code></pre>
<p>Simple, right? Let me explain what the program is doing. I'll use <code>#0</code>, <code>#1</code>, etc to represent cells in the tape of memory.</p>
<p>We start by reading a single character of input into <code>#0</code>. The input itself will be a <code>string</code>, but we want to work with integers in the range <code>0</code> to <code>255</code>, so we'll store it as an ASCII byte using <code>ord()</code>.</p>
<p>The stream of <code>-</code> tokens will decrement the value in <code>#0</code> 48 times. The ASCII code for the number <code>2</code> is <code>50</code>, so decrementing 48 times will result in a value of <code>2</code> in <code>#0</code>. 48 isn't a magic number, that's just the ASCII code for <code>0</code>.</p>
<p>Moving to <code>#1</code>, we can read in a single character of input again. Then we start a loop.</p>
<p>The loop itself will move back to <code>#0</code>, increment the value and then move to <code>#1</code> again, decrementing <code>#1</code> and this will continue until <code>#1 === 0</code>.</p>
<p><code>#0</code> should now contain the sum of the 2 numbers provided which we can print using <code>echo</code>.</p>
<p>Hopefully you're still with me. If you are, let's start writing the <code>Interpreter</code> class.</p>
<pre><code class="language-php">class Interpreter
{
    protected array $tape = [];

    protected int $tp = 0;

    protected ?string $input = null;

    protected int $ip = 0;

    protected string $output = '';

    public function interpret(Program $program, ?string $input = null)
    {
        $this-&gt;tape = array_fill(0, 30_000, 0);;
        $this-&gt;tp = 0;
        $this-&gt;input = $input;
        $this-&gt;ip = 0;
        $this-&gt;output = '';

        foreach ($program-&gt;getNodes() as $node) {
            $this-&gt;node($node);
        }
    }
}
</code></pre>
<p>The <code>Interpreter</code> has a tape of memory stored in the <code>$tape</code> property, as well as a &quot;tape pointer&quot; which stores the current tape index. The <code>$ip</code> property is the &quot;input pointer&quot;. That is the current position in the input so that we can provide a single string of input and read the correct character when necessary.</p>
<p>All of the execution logic is written inside of <code>Interpreter::node()</code>.</p>
<pre><code class="language-php">class Interpreter
{
    // ...

    protected function node(Node $node): void
    {
        if ($node instanceof MoveRightNode) {
            $this-&gt;tp++;
        } elseif ($node instanceof MoveLeftNode) {
            $this-&gt;tp--;
        } elseif ($node instanceof IncrementNode) {
            if ($this-&gt;tape[$this-&gt;tp] === 255) {
                $this-&gt;tape[$this-&gt;tp] = 0;
            } else {
                $this-&gt;tape[$this-&gt;tp]++;
            }
        } elseif ($node instanceof DecrementNode) {
            if ($this-&gt;tape[$this-&gt;tp] === 0) {
                $this-&gt;tape[$this-&gt;tp] = 255;
            } else {
                $this-&gt;tape[$this-&gt;tp]--;
            }
        } elseif ($node instanceof ReadByteNode) {
            if ($this-&gt;input === null) {
                throw NoInputProvidedException::make();
            }

            $this-&gt;tape[$this-&gt;tp] = ord($this-&gt;input[$this-&gt;ip]);
            $this-&gt;ip++;
        } elseif ($node instanceof WhileNode) {
            while (true) {
                foreach ($node-&gt;getNodes() as $child) {
                    $this-&gt;node($child);
                }

                if ($this-&gt;tape[$this-&gt;tp] === 0) {
                    break;
                }
            }
        } elseif ($node instanceof EchoNode) {
            $this-&gt;output .= chr($this-&gt;tape[$this-&gt;tp]);
        }
    }
}
</code></pre>
<p>It's important to mention a few things here. Since Peso is using the same arithmetic logic as Brainf*ck, incrementing and decrementing the value in a cell is a &quot;wrapping operation&quot;. That means that when we reach <code>0</code> and try to decrement we wrap that around to <code>255</code> and when incrementing <code>255</code>, we wrap that around to <code>0</code>.</p>
<p>Looping is also fairly straightforward. We start an infinite loop and iterate over the child nodes in the loop. Once we have iterated over the child nodes, we will check to see if the current cell is equal to <code>0</code>. If it is, we break out, otherwise we start over from the top of the loop.</p>
<p>Writing a test for this is also fairly simple.</p>
<pre><code class="language-php">it('can add two numbers', function () {
    $tokens = (new Lexer)-&gt;tokenise('$ ------------------------------------------------ =&gt; $ \ &lt;= + =&gt; - / &lt;= echo');
    $program = (new Parser)-&gt;parse($tokens);
    
    $interpreter = new Interpreter;
    $interpreter-&gt;interpret($program, '12');

    expect($interpreter-&gt;getOutput())
        -&gt;toBe('3');
});
</code></pre>
<h2>Compiling</h2>
<p>Writing an interpreter is cool, but you might want to write a super duper complex Peso program, try to run it and find out that it's just too slow. We want Peso to be <em>blazingly fast</em> when necessary. To solve this (non-existent) problem, let's compile our Peso code to PHP!</p>
<p>To achieve this, we'll convert the <code>Program</code> into a valid snippet of PHP code and store it inside of a temporary file. The code doesn't need to be pretty, it just needs to work.</p>
<p>First step, a new <code>Compiler</code> class.</p>
<pre><code class="language-php">class Compiler
{
    public function compile(Program $program): Closure
    {
        $php = sprintf(&lt;&lt;&lt;'PHP'
        &lt;?php

        return function (?string $input = null): string {
            $tape = array_fill(0, 30_000, 0);
            $tp = 0;
            $ip = 0;
            $output = '';

            %s
        };
        PHP, $this-&gt;generate($program));

        $temp = tempnam(sys_get_temp_dir(), 'peso-');

        file_put_contents($temp, $php);

        return require $temp;
    }
}
</code></pre>
<p>The <code>Compiler::compile()</code> method accepts a <code>Program</code> and will generate a snippet of valid PHP code from the nodes. It will then write that PHP code to a temporary file and <code>require</code> it to get the <code>Closure</code> being returned.</p>
<p>That <code>Closure</code> can then be invoked with a string of input to evaluate the Peso code.</p>
<pre><code class="language-php">class Compiler
{
    // ...

    public function generate(Program $program): string
    {
        $code = '';

        foreach ($program-&gt;getNodes() as $node) {
            $code .= $this-&gt;node($node);
        }

        return $code;
    }

    protected function node(Node $node): string
    {
        if ($node instanceof MoveRightNode) {
            return '$tp++;';
        }
        
        if ($node instanceof MoveLeftNode) {
            return '$tp--;';
        }

        if ($node instanceof IncrementNode) {
            return &lt;&lt;&lt;'PHP'
            if ($tape[$tp] === 255) {
                $tape[$tp] = 0;
            } else {
                $tape[$tp]++;
            }
            PHP;
        }
        
        if ($node instanceof DecrementNode) {
            return &lt;&lt;&lt;'PHP'
            if ($tape[$tp] === 0) {
                $tape[$tp] = 255;
            } else {
                $tape[$tp]--;
            }
            PHP;
        } 
        
        if ($node instanceof ReadByteNode) {
            return &lt;&lt;&lt;'PHP'
            if ($input === null) {
                throw \Peso\Exceptions\NoInputProvidedException::make();
            }

            $tape[$tp] = ord($input[$ip]);
            $ip++;
            PHP;
        }

        if ($node instanceof WhileNode) {
            $code = 'while (true):';

            foreach ($node-&gt;getNodes() as $child) {
                $code .= $this-&gt;node($child);
            }

            return $code . &lt;&lt;&lt;'PHP'
                if ($tape[$tp] === 0) {
                    break;
                }
            endwhile;
            PHP;
        }

        if ($node instanceof EchoNode) {
            return &lt;&lt;&lt;'PHP'
            $output .= chr($tape[$tp]);
            PHP;
        }
    }
}
</code></pre>
<p>And if we write a test case for the <code>Compiler</code>...</p>
<pre><code class="language-php">it('can compile a program that adds two numbers', function () {
    $tokens = (new Lexer)-&gt;tokenise('$ ------------------------------------------------ =&gt; $ \ &lt;= + =&gt; - / &lt;= echo');
    $program = (new Parser)-&gt;parse($tokens);

    $compiler = new Compiler;
    $callback = $compiler-&gt;compile($program);

    expect($callback('12'))
        -&gt;toBe('3');
});
</code></pre>
<p>Everything passes and we now have a Brainf*ck inspired language that can be interpreted or compiled to PHP. Nifty!</p>
<h2>Finishing touches</h2>
<p>To take Peso to the next level, it makes sense to provide a command-line app that can execute a <code>.peso</code> file and read the program's input from <code>STDIN</code>.</p>
<pre><code class="language-php">#!/usr/bin/env php
&lt;?php

use Peso\Compiler;
use Peso\Exceptions\UnexpectedCharacterException;
use Peso\Exceptions\UnexpectedTokenException;
use Peso\Interpreter;
use Peso\Lexer;
use Peso\Parser;

$autoloaders = [__DIR__.'/../../autoload.php', __DIR__.'/../vendor/autoload.php'];
$file = null;

foreach ($autoloaders as $autoloader) {
    if (file_exists($autoloader)) {
        $file = $autoloader;
        break;
    }
}

if ($file === null) {
    echo &quot;error: failed to find autoloader\n&quot;;
    exit(1);
}

require_once $file;

if ($argc &lt;= 1 || in_array('--help', $argv)) {
    echo &quot;usage: peso [file]\n&quot;;
    exit(1);
}

$file = $argv[1];
$compile = in_array('--compile', $argv) || in_array('-c', $argv);

if (! file_exists($file)) {
    echo &quot;error: {$file} does not exist\n&quot;;
    exit(1);
}

$code = file_get_contents($file);

if (! $code) {
    return;
}

$lexer = new Lexer;

try {
    $tokens = $lexer-&gt;tokenise($code);
} catch (UnexpectedCharacterException $e) {
    echo &quot;lexer error: {$e-&gt;getMessage()}\n&quot;;
    exit(1);
}

$parser = new Parser;

try {
    $program = $parser-&gt;parse($tokens);
} catch (UnexpectedTokenException $e) {
    echo &quot;parser error: {$e-&gt;getMessage()}\n&quot;;
    exit(1);
}

stream_set_blocking(STDIN, false);

$input = trim(fgets(STDIN));
$interpreter = new Interpreter;
$compiler = new Compiler;

if ($compile) {
    echo $compiler-&gt;compile($program)($input);
} else {
    $interpreter-&gt;interpret($program, $input);
    echo $interpreter-&gt;getOutput();
}

echo &quot;\n&quot;;
</code></pre>
<p>Now we can execute Peso scripts using <code>bin/peso</code>, i.e. <code>bin/peso examples/add.peso</code>. Providing input to the command can be done via <code>STDIN</code>, i.e. <code>echo 12 | bin/peso examples/add.peso</code>.</p>
<p>The default execution method is using the <code>Interpreter</code>. If you want to use the <code>Compiler</code> instead, you just need to provide the <code>--compile</code> flag (<code>-c</code> shorthand).</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 12 May 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[PXP Progress Report #1]]></title>
                <link>https://ryangjchandler.co.uk/posts/pxp-progress-report-1</link>
                <description><![CDATA[<p>After a busy month or so moving house and working, I've picked the project back up and figured a progress report was worth writing since there are a lot of people interested in the project.</p>
<p>The first and most important update - the project isn't dead! It's still very much alive, but time is precious resource and since this is just a hobby project it's hard for me to justify spending lots of time working on it - it doesn't pay the bills.</p>
<p>Now because of that, the project is going to be taking a slight change of direction. The parser is written in Rust and the parser will always be written in Rust. I've spent too much time on the parser to just throw it all away.</p>
<p>But. Instead of writing all of PXP's tooling (static analysis, intellisense, formatting, etc) in Rust, I'm going to be taking a hybrid approach.</p>
<p>PHP is my bread and butter, so right now the focus is on making the parser written in Rust usable from a PHP project.</p>
<p>The process there is writing a set of &quot;bindings&quot;. I'm currently relying on FFI to do this and that process is going smoothly - I'm yet to do any benchmarks but I've got a feeling it'll still be a huge win in terms of performance.</p>
<p>Once the bindings are complete, they'll be open-sourced. The next stage will be using those bindings to write the transpiler. The transpiler is actually the simplest part in the project. It's more or less &quot;change X to Y&quot; or &quot;extract A from B&quot;.</p>
<p>The transpiler will then be open-sourced too. People will be able to start using it and trying to break it (please do try). There will also likely be some syntax highlighting for editors as well, no immediate guarantees (regular PHP highlighters will mostly work).</p>
<p>I then want to focus on the static analyser, since that will be necessary for editor/intellisense support. I started working on this already, but it was written in Rust and whilst I like to think I'm quite good with Rust these days, my velocity is still higher in PHP.</p>
<p>Writing the static analyser in PHP will make it much easier to distribute, extend and contribute to which is ultimately more important. If a tool is difficult to setup and use, nobody will use it.</p>
<p>That said, this is the end of the report. I'll aim to do these monthly or when something big happens.</p>
<p>I want to spend time on this project but can't feasibly do that without support. If you would like to support my work, consider <a href="https://github.com/sponsors/ryangjchandler/">sponsoring me on GitHub</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 27 Apr 2023 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Automatically running commands in Visual Studio Code projects]]></title>
                <link>https://ryangjchandler.co.uk/posts/automatically-running-commands-in-visual-studio-code-projects</link>
                <description><![CDATA[<p>Modern web development generally involves running various scripts in your terminal to build assets, analyse your code and more. It's incredibly annoying to run those commands manually everytime you open a project.</p>
<p>Thankfully it's possible to automate that process in Visual Studio Code using <code>tasks.json</code> file.</p>
<p>Let's say that I'm working on a Laravel project and want to have Vite running. The command for that would be <code>npm run dev</code>.</p>
<p>Inside of a new file called <code>.vscode/tasks.json</code>, we could add the following JSON.</p>
<pre><code class="language-json">{
    &quot;version&quot;: &quot;2.0.0&quot;,
    &quot;tasks&quot;: [
        {
            &quot;label&quot;: &quot;Run Vite&quot;,
            &quot;type&quot;: &quot;shell&quot;,
            &quot;command&quot;: &quot;npm run dev&quot;,
            &quot;presentation&quot;: {
                &quot;reveal&quot;: &quot;always&quot;,
                &quot;panel&quot;: &quot;new&quot;
            },
            &quot;runOptions&quot;: {
                &quot;runOn&quot;: &quot;folderOpen&quot;
            }
        }
    ]
}
</code></pre>
<p>This task will automatically run the <code>npm run dev</code> command when the project folder is opened. The next time it's opened, the task panel will show up alongside your regular terminal and that process will start automatically.</p>
<p>It is possible to specify an <code>npm</code> type of task, but I personally prefer using <code>shell</code> since it is the same command I'd use in my a terminal. It also means that you can run <em>anything</em> you want automatically.</p>
<p>Save your future self some time and setup some automated tasks!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 24 Mar 2023 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Applying a colored overlay to a background image]]></title>
                <link>https://ryangjchandler.co.uk/posts/applying-a-colored-overlay-to-a-background-image</link>
                <description><![CDATA[<p>I recently worked on a project that had a background image covering the entire body of the page. One of the differences was that the background also needed a colored overlay, in this case a black overlay with slight opacity.</p>
<p>I would normally do this using an absolutely positioned element stretching to all 4 corners of the page with a <code>z-index</code> lower than the <code>&lt;main&gt;</code> content of the page, but then you end up constantly working about stacking context problems.</p>
<p>After some digging I realised that you can pass multiple values to the <code>background-image</code> CSS property.</p>
<pre><code class="language-css">body {
    background-image: url('bg-img.jpg'), ...;
}
</code></pre>
<p>This makes it really simple to apply a colored overlay using a <code>linear-gradient()</code> between 2 identical colors, combined with the <code>background-blend-mode</code> property.</p>
<pre><code class="language-css">body {
    background-image: url('bg-img.jpg'), linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5));
    background-blend-mode: overlay;
}
</code></pre>
<p>This will place the gradient on top of the background image.</p>
<aside class="aside--left aside--context__note"><p>I've found that <code>overlay</code> works best with dark shades. If you're using a brighter color, you might also want to try <code>multiply</code>.</p></aside>
<p>If you use Tailwind, then you can use the <code>bg-blend-overlay</code> class to apply the blend mode.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 20 Mar 2023 00:00:00 +0000</pubDate>
                                    <category>CSS</category>
                            </item>
                    <item>
                <title><![CDATA[Blazingly fast Markdown parsing in PHP using FFI and Rust]]></title>
                <link>https://ryangjchandler.co.uk/posts/blazingly-fast-markdown-parsing-in-php-using-ffi-and-rust</link>
                <description><![CDATA[<p>Parsing and rendering Markdown as HTML is very common on the modern web. The content found on this very blog is written in Markdown and rendered to HTML using the <a href="https://github.com/thephpleague/commonmark"><code>league/commonmark</code></a> package and a few plugins.</p>
<p>I'm currently in the process of writing a book to accompany a video course. All of the content for that book is also written in Markdown, but I've started to notice a slowdown in build speed as the number of files and size of the files increases. The biggest bottleneck in the process is in fact the conversion of Markdown to HTML.</p>
<p>In this post, I'll go through the steps that I took to bind the excellent <code>comrak</code> Rust crate to my existing PHP build process via FFI to improve the performance of my book-building tool.</p>
<h2>What is FFI?</h2>
<p>FFI stands for &quot;Foreign Function Interface&quot;. When a language provides some form of FFI, it allows you to interact with functions written in a totally different programming language.</p>
<p>There are plenty of practical applications for FFI, for example:</p>
<ul>
<li>Progressively migrating from one language to another</li>
<li>Improving mission-critical code with more performant code</li>
<li>Using packages written in other languages</li>
</ul>
<p>In this case, we'll be using a package from another language to improve the performance of some PHP code.</p>
<h3>The <code>FFI</code> class</h3>
<p>PHP introduced support for FFI as part of the PHP 7.4 release with the addition of a new <code>FFI</code> class in the global namespace. The idea here is that we compile some Rust code into a shared library (<code>.so</code>, <code>.dylib</code>, <code>.dll</code>) and provide a C-style header declaration to let PHP know which structures and definitions are available as part of our code.</p>
<h2>Generating a shared library</h2>
<p>Let's say that we want to expose a Rust function that accepts 2 integers and returns the sum of those numbers.</p>
<pre><code class="language-rust">fn add(a: i64, b: i64) -&gt; i64 {
    return a + b;
}
</code></pre>
<p>To represent this Rust function in the style of a C function, we would need to define the signature of the function using C syntax.</p>
<pre><code class="language-c">long long add(long long a, long long b);
</code></pre>
<aside class="aside--left aside--context__info"><p>The <code>long long</code> type you see is the C way of defining a 64-bit integer. This is essentially the same thing as Rust's <code>i64</code> type.</p></aside>
<p>Assuming that the Rust project was created using <code>cargo init --lib</code>, we'll have a <code>src/lib.rs</code> file that will contain our Rust code. If the project is built using <code>cargo build</code>, the Rust compiler will product an <code>rlib</code> by default. This is a special library format specific to Rust and therefore no usable with FFI.</p>
<p>We need to tell the Rust compiler that we want to build a shared library. The way to do this is by adding a <code>crate-type</code> configuration key to the <code>Cargo.toml</code> file in the Rust project.</p>
<pre><code class="language-toml">[package]
name = &quot;php-comrak&quot;
version = &quot;0.1.0&quot;
edition = &quot;2021&quot;

[lib]
crate-type = [&quot;cdylib&quot;]

[dependencies]
</code></pre>
<p>The <code>cdylib</code> format will produce the shared library in a valid C-style format for most (if not all) FFI APIs. The generated file can be found in <code>target/debug</code> as something similar to <code>libcratename.dylib</code> (or <code>.so</code> and <code>.dll</code> on other platforms).</p>
<p>Although we have written a Rust function, it's not currently being exposed via the shared library. To expose the function, we need to tell Rust that we which to make it public and export it as a C-compatible function using the <code>extern</code> keyword.</p>
<pre><code class="language-rust">pub extern &quot;C&quot; fn add(a: i64, b: i64) -&gt; i64 {
    return a + b;
}
</code></pre>
<p>We can still use Rust's <code>i64</code> integer type since it knows how to compile that to C's <code>long long</code> equivalent.</p>
<p>Now let's hook it up to PHP using <code>FFI::cdef()</code>.</p>
<pre><code class="language-php">$ffi = FFI::cdef('long long add(long long a, long long b);', __DIR__ . '/target/debug/libphp_comrak.dylib');

echo $ffi-&gt;add(100, 200);
</code></pre>
<p>The first argument is the declaration of the function and the second argument is the path to the object file.</p>
<aside class="aside--right aside--context__note"><p>I'm on macOS so my shared library is using the <code>.dylib</code> extension. If you're on Linux, it'll be <code>.so</code>. Windows will produce <code>.dll</code> files.</p></aside>
<p>Running that PHP file in a terminal produces the following output:</p>
<pre><code>Fatal error: Uncaught FFI\ParserException: ';' expected, got '&lt;EOF&gt;' at line 1 in /.../php-comrak/main.php:3
Stack trace:
#0 /.../php-comrak/main.php(3): FFI::cdef('long long add(l...', '/...')
#1 {main}
  thrown in /.../php-comrak/main.php on line 3
</code></pre>
<p>What happened? The Rust file correctly defines that function and the header describes the function signature...</p>
<p>The culprit here is name mangling. Name mangling is a process that a compiler uses to avoid conflicts with function names during linking. To prevent mangling the name of the <code>add</code> function, an attribute needs to be added to the function itself.</p>
<pre><code class="language-rust">#[no_mangle]
pub extern &quot;C&quot; fn add(a: i64, b: i64) -&gt; i64 {
    return a + b;
}
</code></pre>
<p>Re-compiling the Rust code and re-executing the PHP code should now work.</p>
<pre><code class="language-sh">$ cargo build
$ php ./main.php
300
</code></pre>
<h2>Adding Comrak</h2>
<p>First thing to do is add the crate as a dependency of the project.</p>
<pre><code class="language-sh">$ cargo add comrak
</code></pre>
<p>Next we can define a new function called <code>compile</code> which will accept a string of Markdown and compile it into HTML.</p>
<pre><code class="language-rust">pub extern &quot;C&quot; fn compile(markdown: ?) -&gt; ? {
    // ...
}
</code></pre>
<p>But what type do we accept and return? This is where it starts to get more involved.</p>
<p>If this were a regular Rust function we'd probably use one of Rust's first-party string representations, <code>String</code> and <code>&amp;str</code>. The issue with those types is that they're not FFI-safe. Thankfully Rust provides some extra types as part of the <code>std::ffi</code> module.</p>
<p>Instead of <code>String</code>, we can use the <code>std::ffi::c_char</code> type, accepting and returning a raw pointer (<code>*const c_char</code>).</p>
<pre><code class="language-rust">use std::ffi::c_char;

#[no_mangle]
pub extern &quot;C&quot; fn compile(markdown: *const c_char) -&gt; *const c_char {
    // ...
}
</code></pre>
<p>To see if the code is working, we can just return the <code>markdown</code> value directly and then update our PHP code to call the new function.</p>
<pre><code class="language-rust">#[no_mangle]
pub extern &quot;C&quot; fn compile(markdown: *const c_char) -&gt; *const c_char {
    return markdown;
}
</code></pre>
<pre><code class="language-php">$ffi = FFI::cdef('const char* compile(const char* markdown);', __DIR__ . '/target/debug/libphp_comrak.dylib');

$markdown = &lt;&lt;&lt;'md'
## Hello, world!

Here is some **bold** and _italic_ text.
md;

echo $ffi-&gt;compile($markdown);
</code></pre>
<p>Compiling and executing produces the following:</p>
<pre><code class="language-md">$ cargo build
$ php ./main.php
## Hello, world!

Here is some **bold** and _italic_ text.%
</code></pre>
<p>Calling the <code>compile()</code> function returns <code>const char*</code> (a constant pointer to a character), PHP's FFI handling is smart enough to convert that into a regular PHP <code>string</code> for us.</p>
<p>Now that we know the FFI part is working, let's handle the conversion of a <code>const* c_char</code> into a Rust <code>&amp;str</code> type.</p>
<pre><code class="language-rust">let markdown = unsafe { CStr::from_ptr(markdown) }
    .to_str()
    .unwrap();
</code></pre>
<p>The use of an <code>unsafe</code> block is crucial here. Since we're using a raw pointer (<code>const* c_char</code>), Rust isn't able to do it's regular compile-time guarantees regarding memory safety. We're admitting to that by using the <code>unsafe</code> block to construct a <code>std::ffi::CStr</code>.</p>
<aside class="aside--left aside--context__info"><p>We don't need to wrap all of our code inside of an <code>unsafe</code> block because the <code>std::ffi::CStr</code> structure is a <strong>safe</strong> wrapper around a raw C string. That means any further operations can be done in a safe-context and the Rust compiler allows that.</p></aside>
<p>Comrak provides a very simple <code>markdown_to_html()</code> function that accepts the <code>&amp;str</code> stored inside of <code>markdown</code>, as well as some configuration options.</p>
<pre><code class="language-rust">let html = markdown_to_html(markdown, &amp;ComrakOptions::default());
</code></pre>
<p>There's no need to worry about the options right now, we'll use the sensible defaults that Comrak provides.</p>
<p>Now that we have a <code>String</code> containing the HTML, we need to convert it back into a <code>const* c_char</code>. That can be done using the <code>CString</code> structure.</p>
<p><code>CString</code> is to <code>CStr</code> as <code>String</code> is to <code>&amp;str</code>. <code>CString</code> represents an <em>owned</em> C-compatible string, whereas <code>CStr</code> represents a borrowed reference to an array of characters (bytes).</p>
<pre><code class="language-rust">return CString::new(html).unwrap().into_raw();
</code></pre>
<p>The <code>CString::new()</code> constructor can fail, so it needs to be unwrapped first. Once it is, we can grab a raw pointer to the underlying data and return it directly.</p>
<p>Here's the final function:</p>
<pre><code class="language-rust">use std::ffi::{c_char, CStr, CString};
use comrak::{markdown_to_html, ComrakOptions};

#[no_mangle]
pub extern &quot;C&quot; fn compile(markdown: *const c_char) -&gt; *const c_char {
    let markdown = unsafe { CStr::from_ptr(markdown) }
        .to_str()
        .unwrap();

    let html = markdown_to_html(markdown, &amp;ComrakOptions::default());
    
    return CString::new(html).unwrap().into_raw()
}
</code></pre>
<p>The PHP code doesn't need to be updated again since it already has the correct signature. All we need to do is re-compile the Rust code and execute the PHP code again.</p>
<pre><code class="language-html">$ cargo build
$ php ./main.php
&lt;h2&gt;Hello, world!&lt;/h2&gt;
&lt;p&gt;Here is some &lt;strong&gt;bold&lt;/strong&gt; and &lt;em&gt;italic&lt;/em&gt; text.&lt;/p&gt;
</code></pre>
<p>And there we go! We're parsing and compiling Markdown to HTML with Rust and FFI. Let's do some rudimentary benchmarks to see how it performs compared to <code>league/commonmark</code>.</p>
<p>The benchmark is focused on the actual parsing and compilation time, it doesn't include any file I/O or other irrelevant operations. Each benchmark was executed 10 times and the results you see below are the averages of those 10 runs.</p>
<table>
<thead>
<tr>
<th>Iterations</th>
<th><code>league/commonmark</code></th>
<th><code>comrak</code> &amp; FFI</th>
</tr>
</thead>
<tbody>
<tr>
<td>1,000</td>
<td>0.070 seconds</td>
<td>0.012 seconds</td>
</tr>
<tr>
<td>10,000</td>
<td>7.250 seconds</td>
<td>0.030 seconds</td>
</tr>
<tr>
<td>50,000</td>
<td>DNF</td>
<td>0.985 seconds</td>
</tr>
</tbody>
</table>
<p>Those benchmarks demonstrate the potential performance benefits of using FFI and a lower-level language at scale.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 13 Mar 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Disabling Composer's script process timeout]]></title>
                <link>https://ryangjchandler.co.uk/posts/disabling-composers-script-process-timeout</link>
                <description><![CDATA[<p>For repetitive processes in my projects, I typically use Composer's <code>script</code> functionality to make running scripts and executing binaries simpler for myself and my team.</p>
<p>One thing that I run into often is long-running processes, such as watcher scripts or background processes, exceeding Composer's default script timeout of 300 seconds. An example of where I see this most often is large test suites that can take more than 5 minutes to run, normally end-to-end tests.</p>
<pre><code class="language-json">{
    &quot;scripts&quot;: {
        &quot;e2e&quot;: &quot;./bin/run-tests.sh --browser&quot;
    }
}
</code></pre>
<p>To disable Composer's default timeout, you need to update the entry in the <code>scripts</code> section of your <code>composer.json</code> file to call the <code>Composer\\Config::disableProcessTimeout</code> method before running your own code.</p>
<pre><code class="language-json">{
    &quot;scripts&quot;: {
        &quot;e2e&quot;: [
            &quot;Composer\\Config::disableProcessTimeout&quot;,
            &quot;./bin/run-tests.sh --browser&quot;
        ],
    }
}
</code></pre>
<p>You can read more about this in Composer's <a href="https://getcomposer.org/doc/06-config.md#process-timeout">official documentation here</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 31 Jan 2023 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Basic Rules (Writing a static analyser for PHP in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/writing-a-static-analyser-for-php-in-rust-basic-rules</link>
                <description><![CDATA[<p>Now that we have a basic <code>Rule</code> API setup, we can start to implement some basic analysis rules. We're going to start with a simple <code>ValidFunctionRule</code> that checks all function calls to ensure the function actually exists.</p>
<p>The rule itself is relatively simple. We need to create a new <code>struct</code> and implement the <code>Rule</code> trait on it.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct ValidFunctionRule;

impl Rule for ValidFunctionRule {
    fn should_run(&amp;self, node: &amp;dyn Node) -&gt; bool {
        downcast::&lt;FunctionCallExpression&gt;(node).is_some()
    }

    fn run(&amp;mut self, node: &amp;mut dyn Node, definitions: &amp;DefinitionCollection) {
        todo!()
    }
}
</code></pre>
<p>The rule will only be looking at <code>FunctionCallExpression</code> nodes, so we can limit that down inside of <code>should_run()</code>.</p>
<p>The <code>run()</code> method can then execute and do the existence check on the <code>FunctionCallExpression.target</code>.</p>
<pre><code class="language-rust">fn run(&amp;mut self, node: &amp;mut dyn Node, definitions: &amp;DefinitionCollection) {
    let function_call_expression = downcast::&lt;FunctionCallExpression&gt;(node).unwrap();

    match function_call_expression.target.as_ref() {
        Expression::Identifier(Identifier::SimpleIdentifier(SimpleIdentifier { value: function_name, .. })) =&gt; {
            if definitions.get_function(function_name).is_none() {
                todo!()
            }
        },
        _ =&gt; return,
    }
}
</code></pre>
<p>Unwrapping the result from <code>downcast()</code> is safe since we have already limited down the node types inside of <code>should_run()</code>. To get rid of the <code>todo!()</code> in the method, we need to update the <code>Rule</code> to also accept the <code>MessageCollector</code> that we created in the previous part.</p>
<pre><code class="language-rust">pub trait Rule: Debug {
    fn should_run(&amp;self, node: &amp;dyn Node) -&gt; bool;
    fn run(&amp;mut self, node: &amp;mut dyn Node, definitions: &amp;DefinitionCollection, messages: &amp;mut MessageCollector);
}
</code></pre>
<p>Now the rule can add a message to the collector.</p>
<pre><code class="language-rust">fn run(&amp;mut self, node: &amp;mut dyn Node, definitions: &amp;DefinitionCollection, messages: &amp;mut MessageCollector) {
    let function_call_expression = downcast::&lt;FunctionCallExpression&gt;(node).unwrap();

    match function_call_expression.target.as_ref() {
        Expression::Identifier(Identifier::SimpleIdentifier(SimpleIdentifier { value: function_name, .. })) =&gt; {
            if definitions.get_function(function_name).is_none() {
                messages.add(format!(&quot;Function `{}` not found&quot;, function_name));
            }
        },
        _ =&gt; return,
    }
}
</code></pre>
<p>The rule itself can be registered with the analyser.</p>
<pre><code class="language-rust">fn run(args: AnalyseCommand) {
    // ...

    let mut analyser = Analyser::new(collection);
    analyser.add_rule(Box::new(rules::functions::valid_function::ValidFunctionRule));

    // ...
}
</code></pre>
<p>A simple PHP file with the code below will produce the following messages:</p>
<pre><code class="language-php">&lt;?php

foo();
</code></pre>
<pre><code class="language-sh">cargo run -- analyse ./playground/invalid-function.php
</code></pre>
<pre><code>[src/cmd/analyse.rs:29] messages = MessageCollector {
    file: &quot;./playground/invalid-function.php&quot;,
    messages: [
        &quot;Function `foo` not found&quot;,
    ],
}
</code></pre>
<aside class="aside--left aside--context__note"><p>This rule is only analysing function calls with simple identifiers, i.e. <code>foo()</code>, <code>bar()</code>. It doesn't analyse calls to a <code>Closure</code> stored inside of a variable or a dynamic function calls using <code>callable</code> value types.</p>
<p>Analysing those is a lot more involved and the type system isn't able to handle those yet.</p></aside>
<p>Since we've got some real messages, we might as well spend a couple of minutes improving the format of the output in the terminal. Let's go with tables for now and pull in the <code>prettytable-rs</code> crate to do the heavy lifting.</p>
<pre><code class="language-sh">cargo add prettytable-rs
</code></pre>
<pre><code class="language-rust">impl MessageCollector {
    // ...

    pub fn iter(&amp;self) -&gt; Iter&lt;String&gt; {
        self.messages.iter()
    }

    pub fn get_file(&amp;self) -&gt; &amp;str {
        self.file.as_str()
    }

    // ...
}
</code></pre>
<pre><code class="language-rust">fn run(args: AnalyseCommand) {
    // ...

    let messages = analyser.analyse(args.file, &amp;contents);

    let mut table = Table::new();
    table.add_row(row![messages.get_file()]);
    for message in messages.iter() {
        table.add_row(row![message]);
    }
    table.printstd();
}
</code></pre>
<p>And now the output looks like this:</p>
<pre><code>+-----------------------------------+
| ./playground/invalid-function.php |
+-----------------------------------+
| Function `foo` not found          |
+-----------------------------------+
</code></pre>
<p>Much nicer than Rust's default <code>dbg!()</code> output.</p>
<h2>Resolving Names</h2>
<p>The rule that we've just written is producing an error, but it's not entirely correct. If the PHP code is updated to the following:</p>
<pre><code class="language-php">&lt;?php

function foo() {
    
}

foo();
</code></pre>
<p>The analyser is still going to produce an error. The definition collector is saving a <code>FunctionDefinition</code> for <code>foo()</code> but it is storing it with a fully-qualified name <code>\foo</code>.</p>
<p>We need to take the same <code>resolve_name()</code> logic from the <code>DefinitionCollector</code> and add it to the <code>Analyser</code> somewhere. We can't simply add it to the <code>Analyser</code> because that will be used for multiple files, so instead we need to create some sort of <code>Scope</code> or <code>Context</code> structure that we can use for a single file.</p>
<p>I like the name <code>Context</code>, so let's go with that.</p>
<pre><code class="language-rust">#[derive(Debug, Clone)]
pub struct Context {
    namespace: ByteString,
    imports: Vec&lt;ByteString&gt;,
}

impl Context {
    pub fn new() -&gt; Self {
        Self {
            namespace: ByteString::default(),
            imports: Vec::new(),
        }
    }

    pub fn resolve_name(&amp;self, name: &amp;ByteString) -&gt; ByteString {
        // If the name is already fully qualified, return as is.
        if name.bytes.starts_with(b&quot;\\&quot;) {
            return name.clone();
        }

        let parts = name.split(|b| *b == b'\\').collect::&lt;Vec&lt;&amp;[u8]&gt;&gt;();
        let first_part = parts.first().unwrap();

        // Check each imported name to see if it ends with the first part of the
        // given identifier. If it does, we can assume you're referencing either
        // an imported namespace or class that has been imported.
        for imported_name in self.imports.iter() {
            if imported_name.ends_with(first_part) {
                let mut qualified_name = imported_name.clone();
                qualified_name.extend(&amp;name.bytes[first_part.len()..]);

                return qualified_name;
            }
        }

        // If we've reached this point, we have a simple name that
        // is not fully qualified and we have not imported it.
        // We can simply prepend the current namespace to it.
        let mut qualified_name = self.namespace.clone();
        qualified_name.extend(b&quot;\\&quot;);
        qualified_name.extend(&amp;name.bytes);

        qualified_name
    }

    pub fn set_namespace(&amp;mut self, namespace: ByteString) {
        self.namespace = namespace;
    }

    pub fn add_import(&amp;mut self, import: ByteString) {
        self.imports.push(import);
    }
}
</code></pre>
<p>Since a single-file could have multiple contexts, we'll use a <code>context_stack</code> on the <code>Analyser</code> to store them.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct Analyser {
    rules: Vec&lt;Box&lt;dyn Rule&gt;&gt;,
    definitions: DefinitionCollection,
    message_collector: MessageCollector,
    context_stack: Vec&lt;Context&gt;,
}

impl Analyser {
    pub fn new(definitions: DefinitionCollection) -&gt; Self {
        Self {
            rules: Vec::new(),
            definitions,
            message_collector: MessageCollector::default(),
            context_stack: Vec::new(),
        }
    }

    pub fn analyse(&amp;mut self, file: String, contents: &amp;[u8]) -&gt; MessageCollector {
        self.message_collector = MessageCollector::new(file);

        let parse_result = parse(contents);
        if let Err(error) = parse_result {
            self.message_collector.add(error.to_string());
            return self.message_collector.clone();
        }

        let mut ast = parse_result.unwrap();

        self.context_stack.push(Context::new());
        self.visit_node(&amp;mut ast).unwrap();

        return self.message_collector.clone();
    }

    pub fn add_rule(&amp;mut self, rule: Box&lt;dyn Rule&gt;) {
        self.rules.push(rule);
    }
}

impl Visitor&lt;()&gt; for Analyser {
    fn visit(&amp;mut self, node: &amp;mut dyn Node) -&gt; Result&lt;(), ()&gt; {
        let mut context = self.context_stack.last_mut().unwrap();

        for rule in &amp;mut self.rules {
            if rule.should_run(node) {
                rule.run(node, &amp;self.definitions, &amp;mut self.message_collector, &amp;mut context);
            }
        }

        Ok(())
    }
}
</code></pre>
<p>Now when we run the rule on the code from earlier, it won't produce any messages because the call to <code>foo()</code> is being resolved to <code>\foo</code> which is the fully-qualified name of the function itself.</p>
<p>But what if we now create two separate PHP files - one with a namespaced function and the other importing that namespaced function and calling it? Well, the analyser will fail again.</p>
<pre><code class="language-php">&lt;?php

namespace App;

function foo() {

}
</code></pre>
<pre><code class="language-php">&lt;?php

use function App\foo;

foo();
</code></pre>
<p>The first problem is that the current <code>Context</code> isn't storing any imported names. We can add a check for <code>use</code> statements in the <code>Analyser</code> and if we come across one, we can add it to the <code>Context</code>.</p>
<pre><code class="language-rust">impl Visitor&lt;()&gt; for Analyser {
    fn visit(&amp;mut self, node: &amp;mut dyn Node) -&gt; Result&lt;(), ()&gt; {
        let mut context = self.context_stack.last_mut().unwrap();

        if let Some(BracedNamespace { name: Some(SimpleIdentifier { value, .. }), .. }) = downcast::&lt;BracedNamespace&gt;(node) {
            let mut namespace = ByteString::from(b&quot;\\&quot;);
            namespace.extend(&amp;value.bytes);
            context.set_namespace(namespace);
        }

        if let Some(UnbracedNamespace { name: SimpleIdentifier { value, .. }, .. }) = downcast::&lt;UnbracedNamespace&gt;(node) {
            let mut namespace = ByteString::from(b&quot;\\&quot;);
            namespace.extend(&amp;value.bytes);
            context.set_namespace(namespace);
        }

        if let Some(GroupUseStatement { prefix, uses, .. }) = downcast::&lt;GroupUseStatement&gt;(node) {
            for Use { name, .. } in uses {
                let mut prefixed_name = prefix.value.clone();
                prefixed_name.extend(b&quot;\\&quot;);
                prefixed_name.extend(&amp;name.value.bytes);

                context.add_import(prefixed_name);
            }
        }

        if let Some(UseStatement { uses, .. }) = downcast::&lt;UseStatement&gt;(node) {
            for Use { name, .. } in uses {
                let mut qualified_name = ByteString::from(b&quot;\\&quot;);
                qualified_name.extend(&amp;name.value.bytes);
                context.add_import(qualified_name);
            }
        }

        for rule in &amp;mut self.rules {
            if rule.should_run(node) {
                rule.run(node, &amp;self.definitions, &amp;mut self.message_collector, &amp;mut context);
            }
        }

        Ok(())
    }
}
</code></pre>
<p>There's some code duplication from the <code>DefinitionCollector</code> here but we can come back to tidy this up later on. This does fix the issue with importing functions from other namespaces, which is perfect!</p>
<h2>Native Functions</h2>
<p>If we try to analyse the following PHP code:</p>
<pre><code class="language-php">abs(-1);
</code></pre>
<p>The analyser will currently tell us that the function <code>abs()</code> doesn't exist. But what's the problem? That function is a native PHP one, it should definitely exist! Well, the issue is our <code>DefinitionCollector</code> isn't able to detect native PHP functions because they're not defined anywhere in the PHP code of our project.</p>
<p>Thankfully this is something that other tools have also encountered in the past, which means there are stub PHP files available with all of PHP's native functions, classes, interfaces, etc.</p>
<aside class="aside--right aside--context__info"><p>Stub files are syntactically correct PHP files, most commonly used to provide tools with definitions related to magic methods, macros and native functions from PHP extensions.</p></aside>
<p>PHPStan has a public repository with a collection of stubs automatically taken from PHP's codebase. There are a couple of ways we can get the analyser to scan for these files:</p>
<ol>
<li>Embed the files inside of the binary at compile-time.</li>
<li>Require the stubs package as part of our project and let the <code>DefinitionCollector</code> handle them like regular PHP files.</li>
</ol>
<p>I'm going to opt for the second approach to keep things simple. Embedding the files is slightly more complicated and requires using a third-party crate to embed directories, since Rust only supports embedding single-files out of the box.</p>
<p>A quick <code>composer</code> command will bring those stubs into our project.</p>
<pre><code class="language-sh">composer require phpstan/php-8-stubs --dev
</code></pre>
<p>Trying to analyse that same PHP code now will expose another problem. The definition collector doesn't have support for all of PHP's types just yet. Now is a good time to start adding some more types in, so let's do that.</p>
<p>We first want to identify what types are missing, so instead of just doing a <code>todo!()</code> we can add some additional information to the output.</p>
<pre><code class="language-rust">fn map_type(&amp;self, data_type: Option&lt;&amp;ParsedType&gt;) -&gt; Option&lt;Type&gt; {
    data_type.map(|t| match t {
        ParsedType::Named(_, name) =&gt; Type::Named(self.resolve_name(name)),
        ParsedType::Float(_) =&gt; Type::Float,
        ParsedType::Boolean(_) =&gt; Type::Bool,
        ParsedType::Integer(_) =&gt; Type::Int,
        ParsedType::String(_) =&gt; Type::String,
        ParsedType::Array(_) =&gt; Type::Array,
        ParsedType::Mixed(_) =&gt; Type::Mixed,
        _ =&gt; todo!(&quot;unhandled type: {:?}&quot;, t),
    })
}
</code></pre>
<p>And after running the analyse command and adding any missing types, we end up with this:</p>
<pre><code class="language-rust">#[derive(Debug, Clone)]
pub enum Type {
    String,
    Int,
    Float,
    Array,
    Mixed,
    Bool,
    Object,
    Void,
    False,
    True,
    Null,
    Callable,
    Static,
    Iterable,
    Nullable(Box&lt;Self&gt;),
    Named(ByteString),
    Union(Vec&lt;Self&gt;),
}
</code></pre>
<pre><code class="language-rust">fn map_type(&amp;self, data_type: Option&lt;&amp;ParsedType&gt;) -&gt; Option&lt;Type&gt; {
    data_type.map(|t| match t {
        ParsedType::Named(_, name) =&gt; Type::Named(self.resolve_name(name)),
        ParsedType::Float(_) =&gt; Type::Float,
        ParsedType::Boolean(_) =&gt; Type::Bool,
        ParsedType::Integer(_) =&gt; Type::Int,
        ParsedType::String(_) =&gt; Type::String,
        ParsedType::Array(_) =&gt; Type::Array,
        ParsedType::Mixed(_) =&gt; Type::Mixed,
        ParsedType::Void(_) =&gt; Type::Void,
        ParsedType::Object(_) =&gt; Type::Object,
        ParsedType::Nullable(_, data_type) =&gt; Type::Nullable(Box::new(self.map_type(Some(data_type)).unwrap())),
        ParsedType::Union(data_types) =&gt; {
            let mut types = Vec::new();

            for data_type in data_types {
                types.push(self.map_type(Some(data_type)).unwrap());
            }

            Type::Union(types)
        },
        ParsedType::False(_) =&gt; Type::False,
        ParsedType::True(_) =&gt; Type::True,
        ParsedType::Null(_) =&gt; Type::Null,
        ParsedType::Callable(_) =&gt; Type::Callable,
        ParsedType::StaticReference(_) =&gt; Type::Static,
        ParsedType::Iterable(_) =&gt; Type::Iterable,
        _ =&gt; todo!(&quot;unhandled type: {:?}&quot;, t),
    })
}
</code></pre>
<p>There are still some types missing, such as <code>never</code> and intersection types, those will be added when we need them.</p>
<p>Analysing the <code>abs()</code> example once more, no messages are added and we can now successfully analyse PHP's native functions.</p>
<h2>Next steps</h2>
<p>Now that we have some of the base level work done for analysis, the next part will start to focus on storing variables types inside of <code>Context</code>. We'll start to analyse expressions and calculate the return type of an expression based on the it's type.</p>
<p>All of the code for this part can be <a href="https://github.com/pxp-lang/statan/tree/part-4/basic-rules">found on GitHub</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 27 Jan 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Rules (Writing a static analyser for PHP in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/writing-a-static-analyser-for-php-in-rust-rules</link>
                <description><![CDATA[<p>In this shorter part of the series, we'll start to build up an API for our analyser's rules. The idea here is that we want to be able to store as much information as we'd like on the rule itself, but still have a consistent API for executing the rule.</p>
<p>The best way to do this in the form of a trait. Traits in Rust behave like a mixture of PHP's abstract classes and interfaces. You can define contractual methods that the implementing structure must define, whilst also providing default implementations for methods.</p>
<p>Let's think about what our <code>Rule</code> will need to do.</p>
<p>The first thing <code>Rule</code> needs to do is check whether or not it should be executed for a particular statement or expressions in the AST. Let's call this method <code>should_run()</code>.</p>
<pre><code class="language-rust">pub trait Rule: Debug {
    fn should_run(&amp;self, node: &amp;dyn Node) -&gt; bool;
}
</code></pre>
<p>The second method will be responsible for actually checking the <code>Node</code>. We'll keep it simple and only pass in the <code>Node</code> and <code>DefinitionCollection</code> since we don't have any form of <code>Scope</code> just yet.</p>
<pre><code class="language-rust">pub trait Rule: Debug {
    fn should_run(&amp;self, node: &amp;dyn Node) -&gt; bool;
    fn run(&amp;mut self, node: &amp;dyn Node, definitions: &amp;DefinitionCollection);
}
</code></pre>
<p>Right now, the <code>run()</code> method doesn't need to return anything. Soon enough, it will be able to write error messages to some sort of buffer that will later be output in the console.</p>
<p>With the <code>Rule</code> trait in place, we should create a generic <code>Analyser</code> structure that stores all of the registered rules. The rules will be stored inside of a <code>Vec&lt;Box&lt;dyn Rule&gt;&gt;</code>.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct Analyser {
    pub rules: Vec&lt;Box&lt;dyn Rule&gt;&gt;,
}
</code></pre>
<aside class="aside--left aside--context__info"><p>Since we want to store anything that implements the <code>Rule</code> trait, we need to wrap all of those structures in a <code>Box</code>. Trait objects (<code>dyn Trait</code>) in Rust are zero-sized, meaning the compiler isn't able to reliably allocate memory for them on the stack.</p>
<p>Wrapping them in <code>Box</code> will result in a heap-allocation where knowing the size at compile-time isn't required. This is also required when you want to implement a recursive structure, such as an AST or linked list since it's incredibly difficult to calculate the size of a potentially infinitely recursive bit of data.</p></aside>
<p>Let's also add some helper methods to make registering rules easier.</p>
<pre><code class="language-rust">impl Analyser {
    pub fn new() -&gt; Self {
        Self {
            rules: Vec::new(),
        }
    }

    pub fn add_rule(&amp;mut self, rule: Box&lt;dyn Rule&gt;) {
        self.rules.push(rule);
    }
}
</code></pre>
<p>The API here is a little annoying since you're required to wrap the <code>Rule</code> in a <code>Box</code> yourself, but I'm okay with that.</p>
<p>Now that we have an <code>Analyser</code>, we can provide it with the <code>DefinitionCollection</code> that we have already obtained. This will be provided via the constructor.</p>
<pre><code class="language-rust">impl Analyser {
    pub fn new(definitions: DefinitionCollection) -&gt; Self {
        Self {
            rules: Vec::new(),
            definitions,
        }
    }

    // ...
}
</code></pre>
<p>Let's also initialise an <code>Analyser</code> in the command handler.</p>
<pre><code class="language-rust">pub fn run(_: AnalyseCommand) {
    let files = discoverer::discover(&amp;[&quot;php&quot;], &amp;[&quot;.&quot;]).unwrap();
    let mut collector = DefinitionCollector::new();

    for file in files {
        let contents = std::fs::read(&amp;file).unwrap();
        let mut ast = pxp_parser::parse(&amp;contents).unwrap();

        collector.scan(&amp;mut ast);
    }

    let collection = collector.collect();
    let mut analyser = Analyser::new(collection);
}
</code></pre>
<p>We should also start to think about an API for storing errors and messages from the analyser. This structure will be passed along to each <code>Rule</code> that gets executed and will be used to push messages to the output. For now, we can call this the <code>MessageCollector</code>.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct MessageCollector {
    file: String,
    messages: Vec&lt;String&gt;,
}

impl MessageCollector {
    pub fn new(file: String) -&gt; Self {
        Self {
            file,
            messages: Vec::new(),
        }
    }

    pub fn add(&amp;mut self, message: impl Into&lt;String&gt;) {
        self.messages.push(message.into());
    }
}
</code></pre>
<aside class="aside--right aside--context__info"><p>Accepting a value that implements the <code>Into&lt;String&gt;</code> trait will allow us to use <code>String</code>, <code>&amp;str</code> or a custom <code>Message</code> object instead of being strictly limited to <code>String</code>.</p></aside>
<p>Each file that gets analysed will have it's own <code>MessageCollector</code>. Those will then get collected into their own <code>Vec&lt;MessageCollector&gt;</code> that we can iterate over to output in the terminal.</p>
<pre><code class="language-rust">impl Analyser {
    //...

    pub fn analyse(&amp;mut self, file: String, contents: &amp;[u8]) -&gt; MessageCollector {
        let mut message_collector = MessageCollector::new(file);

        let parse_result = parse(contents);
        if let Err(error) = parse_result {
            message_collector.add(error.to_string());
            return message_collector;
        }

        let mut ast = parse_result.unwrap();

        return message_collector;
    }

    // ...
}
</code></pre>
<p>The <code>Analyser</code> is now able to accept a filename and the contents of that file, parse it and return a <code>MessageCollector</code>. We're starting to do a little bit of error handling now too.</p>
<p>If the parser fails and returns an <code>Err(ParseError)</code>, we can convert the <code>ParseError</code> to a string, add it to the <code>MessageCollector</code> and output the error in the console.</p>
<p>Let's hook this up to the command to see if the parser errors are produced correctly.</p>
<pre><code class="language-rust">pub fn run(args: AnalyseCommand) {
    let files = discoverer::discover(&amp;[&quot;php&quot;], &amp;[&quot;.&quot;]).unwrap();
    let mut collector = DefinitionCollector::new();

    for file in files {
        let contents = std::fs::read(&amp;file).unwrap();
        let mut ast = pxp_parser::parse(&amp;contents).unwrap();

        collector.scan(&amp;mut ast);
    }

    let collection = collector.collect();
    let mut analyser = Analyser::new(collection);

    let contents = read(&amp;args.file).unwrap();
    let messages = analyser.analyse(args.file, &amp;contents);

    dbg!(messages);
}
</code></pre>
<p>If we create a bad PHP file with a syntax error:</p>
<pre><code class="language-php">&lt;?php

1 +
</code></pre>
<p>This should produce a parser error.</p>
<pre><code class="language-sh">cargo run -- analyse ./playground/parse-error.php
</code></pre>
<pre><code class="language-rust">[src/cmd/analyse.rs:27] messages = MessageCollector {
    file: &quot;./playground/parse-error.php&quot;,
    messages: [
        &quot;[E002] Error: unexpected end of file on line 3 column 4\n&quot;,
    ],
}
</code></pre>
<p>And there we go! The parser error is now being added to the collector. The formatting of that error could use a little love still, since it's using the format that the parser provides out of the box but that's a problem for a future version of me.</p>
<h2>Next steps</h2>
<p>In the next part, we'll start to actually write our first <code>Rule</code> and add in the necessary bits and pieces to make that work.</p>
<p>All of the code for this step can be found on <a href="https://github.com/pxp-lang/statan/tree/part-3/rules">GitHub</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 26 Jan 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Definitions (Writing a static analyser for PHP in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/writing-a-static-analyser-for-php-in-rust-definitions</link>
                <description><![CDATA[<p>In this part of the series, we'll start working on the definition collection process for the analyser. We'll learn about the parser, visitors and more.</p>
<p>Let's start by installing the parser. We'll be using the <a href="https://github.com/pxp-lang/parser">PXP parser</a> since it is a superset and supports all of PHP as well as extended language features for PXP. It's also less work to use this parser now, as opposed to using the regular PHP one and changing to the PXP one in the future.</p>
<pre><code class="language-sh">cargo add pxp-parser --git https://github.com/pxp-lang/parser --branch main
</code></pre>
<p>The PXP parser hasn't had official releases at this point in time, so we'll pull it from GitHub.</p>
<h2>Discovering files</h2>
<p>This early in development, we can make some basic assumptions to make things easier. In this instance, we'll assume that the command is being executed from the root of a project, such that <code>./vendor</code> is a valid path.</p>
<p>With this assumption in mind, to start discovering files, we need to recursively search the current directory for PHP files. Thankfully I've already developed a crate to do just this, so it's time to get it installed.</p>
<pre><code class="language-sh">cargo install discoverer
</code></pre>
<p>It's also time to make a new module in the project to store any code related to definitions and their discovery. The new file will be <code>src/definitions/mod.rs</code>.</p>
<p>To get a list of file paths, we just need to call the <code>discoverer::discover()</code> function. Let's do that inside of the <code>analyse::run()</code> function.</p>
<pre><code class="language-rust">let files = discoverer::discover(&amp;[&quot;php&quot;], &amp;[&quot;.&quot;]).unwrap();
</code></pre>
<p>We're looking for <code>php</code> files in the current directory (<code>.</code>). There's a lack of error handling here but that's okay for now.</p>
<h2>Parsing files</h2>
<p>Before we start writing the <code>DefinitionCollector</code> logic, we need actually parse the files we've discovered.</p>
<pre><code class="language-rust">let files = discoverer::discover(&amp;[&quot;php&quot;], &amp;[&quot;.&quot;]).unwrap();

for file in files {
    let contents = std::fs::read(&amp;file).unwrap();
    let ast = pxp_parser::parse(&amp;contents).unwrap();
}
</code></pre>
<p>The initial implementation of the analyser is going to be purely synchronous, so we don't need to worry about processing files in parallel or anything like that. We can write incredibly crude code and come back to optimise later.</p>
<p>The <code>pxp_parser::parse()</code> function essentially accepts anything that can be converted into <code>&amp;[u8]</code>. In our case, we're reading the file into a <code>Vec&lt;u8&gt;</code> which can be converted into a slice. The parser will do its thing and return a <code>Result&lt;Vec&lt;Statement&gt;, ParseError&gt;</code>. Remember, there's no error handling just yet so we'll <code>.unwrap()</code> and assume everything is okay.</p>
<h2><code>DefinitionCollector</code></h2>
<p>Now that we've got an AST for a given file, we can start to collect definitions. This will be handled by a single structure named <code>DefinitionCollector</code>. The AST for each file will be passed along to a method on the structure and the nodes will be analysed.</p>
<p>If you remember from the <a href="/posts/writing-a-static-analyser-for-php-in-rust-overview">overview post</a>, there are a couple of things that the <code>DefinitionCollector</code> needs to keep track of - the current namespace, as well as any names imported by a <code>use</code> statement.</p>
<p>We can define the new structure like so:</p>
<pre><code class="language-rust">use pxp_parser::lexer::byte_string::ByteString;

#[derive(Debug)]
pub struct DefinitionCollector {
    current_namespace: ByteString,
    imported_names: Vec&lt;ByteString&gt;,
}
</code></pre>
<p><strong>Note</strong>: a small implementation detail here is that the parser doesn't store strings as <code>String</code> or <code>&amp;str</code>. PHP source code doesn't <em>need</em> to be valid UTF-8. To workaround this, the parser uses a custom <code>ByteString</code> structure that stores characters in a <code>Vec&lt;u8&gt;</code>.</p>
<p>The first method the collector needs is a constructor, typically called <code>new</code>.</p>
<pre><code class="language-rust">impl DefinitionCollector {
    pub fn new() -&gt; Self {
        Self {
            current_namespace: ByteString::default(),
            imported_names: Vec::new(),
        }
    }
}
</code></pre>
<p>We'll initialise the <code>current_namespace</code> to an empty <code>ByteString</code>, this way we don't need to worry about unwrapping an <code>Option</code> and can always safely prefix a name with an empty string. The <code>imported_names</code> field will be empty to start with too.</p>
<p>While we're on the topic of constructors, we might as well create a new instance of the <code>DefinitionCollector</code> in the command's function and store it in a mutable variable.</p>
<pre><code class="language-rust">use statan::definitions::collector::DefinitionCollector;

use crate::AnalyseCommand;

pub fn run(command: AnalyseCommand) {
    let files = discoverer::discover(&amp;[&quot;php&quot;], &amp;[&quot;.&quot;]).unwrap();
    let mut collector = DefinitionCollector::new();

    for file in files {
        let contents = std::fs::read(&amp;file).unwrap();
        let ast = pxp_parser::parse(&amp;contents).unwrap();
    }
}
</code></pre>
<p>To actually do the collection, we'll add a <code>scan()</code> method to the collector as well and pass in a mutable reference to the AST. The reference needs to be mutable since that is what the parser's visitor API expects.</p>
<pre><code class="language-rust">impl DefinitionCollector {
    pub fn new() -&gt; Self {
        Self {
            current_namespace: ByteString::default(),
            imported_names: Vec::new(),
        }
    }

    pub fn scan(&amp;mut self, ast: &amp;mut Vec&lt;Statement&gt;) {
        
    }
}
</code></pre>
<pre><code class="language-rust">pub fn run(command: AnalyseCommand) {
    let files = discoverer::discover(&amp;[&quot;php&quot;], &amp;[&quot;.&quot;]).unwrap();
    let mut collector = DefinitionCollector::new();

    for file in files {
        let contents = std::fs::read(&amp;file).unwrap();
        let mut ast = pxp_parser::parse(&amp;contents).unwrap();
        
        collector.scan(&amp;mut ast);
    }
}
</code></pre>
<p>Next up is traversing the given AST. The parser provides a <code>Visitor</code> trait that we can implement on the <code>DefinitionCollector</code>, the <code>scan</code> method will just defer everything to the visitor.</p>
<pre><code class="language-rust">impl Visitor&lt;()&gt; for DefinitionCollector {
    fn visit(&amp;mut self, node: &amp;mut dyn Node) -&gt; Result&lt;(), ()&gt; {
        Ok(())
    }
}
</code></pre>
<p>If you're paying attention to the code, you'll see that the <code>visit()</code> method receives <code>&amp;dyn mut Node</code>. The parser has a special <code>Node</code> API that is used for various types of nodes in the AST, including statements and expressions. The benefit of using this API is that we don't need to write individual methods to handle <code>Statement</code>, <code>Expression</code>, <code>Identifier</code>, etc. We can use a single method and cast the <code>node</code> to a specific form when necessary.</p>
<p>We first want to check if the current node is a <code>Namespace</code>. We can use the parser's <code>downcast()</code> function to handle this, passing in a generic parameter as the target type for the cast.</p>
<pre><code class="language-rust">impl Visitor&lt;()&gt; for DefinitionCollector {
    fn visit(&amp;mut self, node: &amp;mut dyn Node) -&gt; Result&lt;(), ()&gt; {
        if let Some(BracedNamespace { name: Some(SimpleIdentifier { value, .. }), .. }) = downcast::&lt;BracedNamespace&gt;(node) {
            let mut namespace = ByteString::from(b&quot;\\&quot;);
            namespace.extend(&amp;value.bytes);
            self.current_namespace = namespace;
        } else if let Some(UnbracedNamespace { name: SimpleIdentifier { value, .. }, .. }) = downcast::&lt;UnbracedNamespace&gt;(node) {
            let mut namespace = ByteString::from(b&quot;\\&quot;);
            namespace.extend(&amp;value.bytes);
            self.current_namespace = namespace;
        }

        Ok(())
    }
}
</code></pre>
<p>We can take advantage of Rust's deep pattern matching capabilities to reach down into the fields on these structures and reduce some of the nested <code>if</code> statements that would otherwise be required. We also need to check against 2 different types of <code>Node</code> here since PHP has 2 ways of defining a namespace.</p>
<pre><code class="language-php">// Unbraced syntax
namespace Foo;

// Braced syntax
namespace Foo {
    // ...
}
</code></pre>
<p>With the brace syntax, it's also possible to omit the namespace's name altogether and explicitly scope the block to the global namespace. If that wasn't the case, we could match against a single pattern instead.</p>
<p>To make the namespaces fully-qualified, we also need to prepend a single <code>\</code> to the name.</p>
<p>PHP also has a couple of ways to import names.</p>
<pre><code class="language-php">// Single use statement.
use Foo\Bar;

// Multi-use statement.
use Foo\Bar, Foo\Baz;

// Grouped use statement.
use Foo\{Bar, Baz};
</code></pre>
<p>You can also specifically import <code>function</code> and <code>const</code> types, but the definition collector doesn't really care about those because it's not possible to use those as parameter types, return types, etc, but the variance in syntax will mean we need to handle a couple of different statement types again.</p>
<pre><code class="language-rust">if let Some(GroupUseStatement { prefix, uses, .. }) = downcast::&lt;GroupUseStatement&gt;(node) {
    // ...           
}

if let Some(UseStatement { uses, .. }) = downcast::&lt;UseStatement&gt;(node) {
    // ...
}
</code></pre>
<p>Both of these statements contain a <code>Vec&lt;Use&gt;</code>, the only extra bit of logic needed for <code>GroupUseStatement</code> is prefixing. It should be easy to start putting names into the list of <code>imported_names</code>.</p>
<pre><code class="language-rust">if let Some(GroupUseStatement { prefix, uses, .. }) = downcast::&lt;GroupUseStatement&gt;(node) {
    for Use { name, .. } in uses {
        let mut prefixed_name = prefix.value.clone();
        prefixed_name.extend(b&quot;\\&quot;);
        prefixed_name.extend(&amp;name.value.bytes);

        self.imported_names.push(prefixed_name);
    }
}

if let Some(UseStatement { uses, .. }) = downcast::&lt;UseStatement&gt;(node) {
    for Use { name, .. } in uses {
        let mut qualified_name = ByteString::from(b&quot;\\&quot;);
        qualified_name.extend(&amp;name.value.bytes);
        self.imported_names.push(qualified_name);
    }
}
</code></pre>
<h2>Definitions</h2>
<p>There's a couple of ways we could structure the definitions themselves. We could create a <code>Definition</code> enumeration that has members for each type of definitions, or we could create separate structures for each type of definition and store them in separate fields.</p>
<p>I personally prefer the second option since it should improve lookup time by reducing the number of items that needs to be filtered through. Let's start with the simplest definition, a <code>FunctionDefinition</code>.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct FunctionDefinition {
    pub name: ByteString,
    pub parameters: Vec&lt;Parameter&gt;,
    pub return_type: Option&lt;Type&gt;,
}
</code></pre>
<p>Functions have parameters, so we'll need a structure for that too.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct Parameter {
    pub name: ByteString,
    pub type_: Option&lt;Type&gt;,
}
</code></pre>
<p>As well as a <code>Type</code> enumeration that will represent all the types that are analyser understands. The parser does have it's own <code>Type</code> enum too, but it won't support everything we need at this point.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub enum Type {
    String,
    Int,
    Float,
    Array,
    Mixed,
    Bool,
    Named(ByteString),
}
</code></pre>
<p>The <code>Type</code> enumeration will only support PHP's most basic types for now. Adding support for unions, intersections and more importantly generics will be easy to do later on.</p>
<p>We'll also need somewhere to store the definitions. Let's create a <code>DefinitionCollection</code>.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct DefinitionCollection {
    functions: Vec&lt;FunctionDefinition&gt;,
}
</code></pre>
<p>The <code>DefinitionCollector</code> can now hold a single <code>DefinitionCollection</code> and we'll start to push add some items to it.</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct DefinitionCollector {
    current_namespace: ByteString,
    imported_names: Vec&lt;ByteString&gt;,
    collection: DefinitionCollection,
}

impl DefinitionCollector {
    pub fn new() -&gt; Self {
        Self {
            current_namespace: ByteString::default(),
            imported_names: Vec::new(),
            collection: DefinitionCollection::default(),
        }
    }

    // ...
}
</code></pre>
<p>To make the API a little nicer, we can define an <code>add_function()</code> method on the collection.</p>
<pre><code class="language-rust">impl DefinitionCollection {
    pub fn add_function(&amp;mut self, function: FunctionDefinition) {
        self.functions.push(function);
    }
}
</code></pre>
<p>In the collector, we need to check if the current node is a <code>FunctionStatement</code>. If it is, we can start to add information to a <code>FunctionDefinition</code> and store it inside of the collection.</p>
<pre><code class="language-rust">if let Some(FunctionStatement { name, parameters, return_type, .. }) = downcast::&lt;FunctionStatement&gt;(node) {
    let name = self.qualify_name(&amp;name.value);
    let parameters = parameters.parameters.inner.iter().map(|p| {
        Parameter {
            name: p.name.name.clone(),
            type_: self.map_type(p.data_type.as_ref()),
        }
    }).collect::&lt;Vec&lt;Parameter&gt;&gt;();
    let return_type = if let Some(ReturnType { data_type, .. }) = return_type {
        self.map_type(Some(data_type))
    } else {
        None
    };

    self.collection.add_function(FunctionDefinition { name, parameters, return_type })
}
</code></pre>
<p>We first convert the function's name into a qualified name. The list of function parameters are then converted into <code>Parameter</code> values. If the function has a return type, we also map that into the analyser's own <code>Type</code> enumeration.</p>
<p>A set of additional utility methods have been added as well - <code>qualify_name()</code>, <code>resolve_name()</code> and <code>map_type()</code>.</p>
<p><code>qualify_name()</code> simply prepends the given string with the current namespace, producing a fully-qualified name.</p>
<pre><code class="language-rust">fn qualify_name(&amp;self, name: &amp;ByteString) -&gt; ByteString {
    let mut qualified_name = self.current_namespace.clone();
    qualified_name.extend(b&quot;\\&quot;);
    qualified_name.extend(&amp;name.bytes);

    qualified_name
}
</code></pre>
<p><code>resolve_name()</code> is a little more complex and handles name resolution. This isn't as simple as doing a lookup on the list of <code>imported_names</code>, since PHP supports a few different ways of referencing names.</p>
<p>You can import a single named item and reference it:</p>
<pre><code class="language-php">use Closure;

function invoke(Closure $closure) {}
</code></pre>
<p>You can also reference a fully-qualified name:</p>
<pre><code class="language-php">function invoke(\Closure $closure) {}
</code></pre>
<p>You can even import a namespace and use a qualified name.</p>
<pre><code class="language-php">use App\Models;

function do_something(Models\User $user) {}
</code></pre>
<p>And finally, if an imported name doesn't match the given identifier, we assume you're referencing something in the current namespace. The <code>resolve_name()</code> method handles these edge-cases.</p>
<pre><code class="language-rust">fn resolve_name(&amp;self, name: &amp;ByteString) -&gt; ByteString {
    // If the name is already fully qualified, return as is.
    if name.bytes.starts_with(b&quot;\\&quot;) {
        return name.clone();
    }

    let parts = name.split(|b| *b == b'\\').collect::&lt;Vec&lt;&amp;[u8]&gt;&gt;();
    let first_part = parts.first().unwrap();

    // Check each imported name to see if it ends with the first part of the
    // given identifier. If it does, we can assume you're referencing either
    // an imported namespace or class that has been imported.
    for imported_name in self.imported_names.iter() {
        if imported_name.ends_with(&amp;first_part) {
            let mut qualified_name = imported_name.clone();
            qualified_name.extend(&amp;name.bytes[first_part.len()..]);

            return qualified_name;
        }
    }

    // If we've reached this point, we have a simple name that
    // is not fully qualified and we have not imported it.
    // We can simply prepend the current namespace to it.
    let mut qualified_name = self.current_namespace.clone();
    qualified_name.extend(b&quot;\\&quot;);
    qualified_name.extend(&amp;name.bytes);

    qualified_name
}
</code></pre>
<p>The final utility function, <code>map_type()</code>, takes an <code>Option&lt;ParsedType&gt;</code> and converts it into the analyser's own <code>Type</code> enumeration.</p>
<pre><code class="language-rust">match data_type {
    Some(t) =&gt; Some(match t {
        ParsedType::Named(_, name) =&gt; Type::Named(self.resolve_name(name)),
        ParsedType::Float(_) =&gt; Type::Float,
        ParsedType::Boolean(_) =&gt; Type::Bool,
        ParsedType::Integer(_) =&gt; Type::Int,
        ParsedType::String(_) =&gt; Type::String,
        ParsedType::Array(_) =&gt; Type::Array,
        ParsedType::Mixed(_) =&gt; Type::Mixed,
        _ =&gt; todo!(),
    }),
    None =&gt; None,
}
</code></pre>
<p><strong>Note</strong>: There's plenty of room for optimisation in these methods but they serve their purpose right now and will allow us to move on. It's a waste of time getting bogged down in optimisation tricks this early in a project.</p>
<p>Now that we have some functions being stored in the collection, it makes sense to add a <code>collect()</code> method to the collector that returns the <code>DefinitionCollection</code> we've been working with.</p>
<pre><code class="language-rust">pub fn collect(&amp;self) -&gt; DefinitionCollection {
    self.collection.clone()
}
</code></pre>
<p>Instead of messing with lifetimes and references right now, we'll use <code>.clone()</code>. It's not a difficult task to come back and change this later on to improve performance and memory usage.</p>
<p>We also need to update the <code>scan()</code> method to actually start traversing the AST. We can loop over the AST and pass each statement along to the <code>Visitor</code> implementation.</p>
<pre><code class="language-rust">pub fn scan(&amp;mut self, ast: &amp;mut Vec&lt;Statement&gt;) {
    self.current_namespace = ByteString::default();
    self.imported_names = Vec::new();

    for statement in ast.iter_mut() {
        self.visit_node(statement).unwrap();
    }
}
</code></pre>
<p>It's important that we reset the <code>current_namespace</code> and <code>imported_names</code>. The <code>DefinitionCollector</code> won't be unique to a file so we need to reset the state between scans.</p>
<p>If we create 2 separate PHP files, <code>a.php</code> and <code>b.php</code>, each containing a function with their respective names and run the analyser on just one of those files, we can dump out the collection and see that both functions were discovered by the collector.</p>
<pre><code class="language-php">use App\Foo;

function a(Foo $foo) {}
</code></pre>
<pre><code class="language-php">use App\Models;

function b(Models\User $user, \Closure $closure) {}
</code></pre>
<pre><code class="language-sh">cargo run -- analyse ./playground/a.php
</code></pre>
<p>We get the following output from the debug dump:</p>
<pre><code>[src/cmd/analyse.rs:17] collection = DefinitionCollection {
    functions: [
        FunctionDefinition {
            name: &quot;\b&quot;,
            parameters: [
                Parameter {
                    name: &quot;$user&quot;,
                    type_: Some(
                        Named(
                            &quot;\App\Models\User&quot;,
                        ),
                    ),
                },
                Parameter {
                    name: &quot;$closure&quot;,
                    type_: Some(
                        Named(
                            &quot;\Closure&quot;,
                        ),
                    ),
                },
            ],
            return_type: None,
        },
        FunctionDefinition {
            name: &quot;\a&quot;,
            parameters: [
                Parameter {
                    name: &quot;$foo&quot;,
                    type_: Some(
                        Named(
                            &quot;\App\Foo&quot;,
                        ),
                    ),
                },
            ],
            return_type: None,
        },
    ],
}
</code></pre>
<p>Exactly what we expected! There are two functions in the collection and all of the parameters have been picked up correctly.</p>
<p>The name resolution is working too. Names referencing partially imported namespaces are fully-qualified, explicit imports are qualified and references to already fully-qualified names are resolved correctly.</p>
<h2>Next steps</h2>
<p>The next thing to do is replicate the logic above and do the same for classes, traits, interfaces and enumerations. It's pretty repetitive so I won't include the code in this post, but if you're interested in what the result looks like, all of the code for this part is <a href="https://github.com/pxp-lang/statan/tree/part-2/definitions">available on GitHub</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 25 Jan 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Overview (Writing a static analyser for PHP in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/writing-a-static-analyser-for-php-in-rust-overview</link>
                <description><![CDATA[<p>In this new series, I'd like to go over the process of writing a static analyser for PHP in the <a href="https://www.rust-lang.org/">Rust programming language</a>. We'll start by talking about what a static analyser is, the set of generic processes the program takes and how to actually write one in Rust.</p>
<p>This post will cover the basics of static analysis and layout the plan for our own engine.</p>
<h2>What is static analysis?</h2>
<p>Static analysis is the process of analysing source code by examining its structure and syntax, without executing the program. This type of analysis can be used to find bugs, security vulnerabilities, and other issues in your code prior to execution.</p>
<h2>How does a static analyser work?</h2>
<p>The majority of static analysis tools will use an abstract syntax tree (AST) that represents the lexical structure of your code. Let's take the following PHP code and produce a pseudo abstract syntax tree.</p>
<pre><code class="language-php">function name(): string {
    return &quot;Ryan&quot;;
}

$name = name();
</code></pre>
<p>A parser will take this string of code and produce something similar to the structure below:</p>
<pre><code class="language-rust">FunctionStatement {
    name: &quot;name&quot;,
    parameters: [],
    return_type: &quot;string&quot;,
    body: [
        ReturnStatement {
            value: String(&quot;Ryan&quot;),
        }
    ],
},
ExpressionStatement {
    expression: Assign {
        target: Variable(&quot;$name&quot;),
        value: CallExpression {
            target: Identifier(&quot;name&quot;),
            arguments: [],
        }
    }
}
</code></pre>
<p>By obtaining this reusable and definitive representation of the code, a program is able to reliably look at certain properties and fields during analysis.</p>
<h3>Finding definitions</h3>
<p>A &quot;definition&quot; is any form of structure in your code that can be referenced, instantiated or invoked. In PHP's case, that would be normally be a <code>class</code> or <code>function</code>. PHP also has traits, interfaces and enumerations which would be discovered too.</p>
<p>The analyser will find every single PHP file in your project, including any <code>vendor</code> files, then send each one through some form of definition collector. The job of the collector is to parse the code, analyse the AST and find one of the structure mentioned above.</p>
<p>Once a definition has been found, it will be further analysed to pull out any information the analyser needs. Let's take a look at an example from a fake Laravel codebase.</p>
<pre><code class="language-php">namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\User;

class Post extends Model 
{
    /** @return BelongsTo&lt;User&gt; */
    public function user(): BelongsTo
    {
        return $this-&gt;belongsTo(User::class);
    }
}
</code></pre>
<p>The collector will parse this file and start to recursively look at each statement.</p>
<p>It first encounters the <code>namespace</code>, taking the name and storing it to use later on. Then the <code>use</code> statements are seen and each of those references are temporarily stored so that fully-qualified names (FQNs) can be resolved when necessary.</p>
<p>Once it reaches the <code>class</code> statement, the collector starts to do some <em>real</em> work. The first thing it does is grab the name of the class and turn it into a fully-qualified name. That's done by prefixing the class name with the current namespace, i.e. <code>App\Models\User</code>.</p>
<p>Since the class inherits from <code>Model</code>, it also needs to resolve the fully-qualified name for that too. The first check is for any imported classes that have the name <code>Model</code>, which works in this case.</p>
<p>Whilst the collector is here, it can also start to build up some information about the methods, properties and constants on the class. That's all pretty self explanatory and follows the same general pattern as above. The result of that work is a near-flat structure of all definitions across the codebase.</p>
<pre><code class="language-rust">[
    &quot;App\\Models\\Class&quot; =&gt; Class {
        name: &quot;App\\Models\\Class&quot;,
        extends: &quot;Illuminate\\Database\\Eloquent\\Model&quot;,
        methods: [
            &quot;user&quot; =&gt; Method {
                name: &quot;user&quot;,
                visibility: Public,
                parameters: [],
                return_type: &quot;Illuminate\\Database\\Eloquent\\Relations\\BelongsTo&quot;,
            }
        ]
    }
]
</code></pre>
<p><strong>Note</strong>: the collector doesn't do any analysis of the code. It won't check for valid parent classes, return types, etc. It's purely a collection phase to find out what is defined in a project's codebase.</p>
<h3>User code</h3>
<p>As mentioned above, the collector will analyse your entire codebase, including any third-party dependencies found in the <code>vendor</code> folder. This is essential to ensure the analyser has all of the information it needs.</p>
<p>When it comes to actually analysing your own code though, the analyser doesn't need to waste time analysing the third-party stuff, so instead it will skip over <code>vendor</code> and any other ignored paths and focus solely on the code that you've written.</p>
<p>Once again, the analyser will build up a list of files in your project and start to analyse each one independently. Most engines will provide a &quot;rule&quot; API that is used to separate out the logic for each check in the analyser.</p>
<p>The rule itself will respond to a particular type of node in the AST and only execute its logic on that node. Let's write a rule with some pseudo PHP code to check that the arguments passed to a function are the correct type so that we can explore the various APIs available to a rule.</p>
<pre><code class="language-php">function add(int $a, int $b): int {
    return $a + $b;
}

add(&quot;one&quot;, 2);
</code></pre>
<p>Let's pretend the AST produces a <code>CallExpression</code> for the function call to <code>add()</code>. Our rule will need to tell the analyser that it only cares about that particular type of expression.</p>
<pre><code class="language-php">class FunctionArgumentRule implements Rule
{
    public function shouldRun(Node $node): bool
    {
        return $node instanceof CallExpression;
    }

    public function run(Node $node, Scope $scope, Reporter $reporter): void
    {
        // Analysing calls to anonymous function requires a little
        // more work, so we'll skip those for now.
        if (! $node-&gt;target instanceof SimpleIdentifier) {
            return;
        }

        $definition = $scope-&gt;getFunction($node-&gt;target);

        // In the case where we can't find the definition,
        // we can return early to avoid any errors below.
        // A separate rule will handle these invalid calls.
        if ($definition === null) {
            return;
        }

        $parameters = $definition-&gt;getParameters();

        if (count($node-&gt;arguments) &lt; count($parameters)) {
            $reporter-&gt;report(
                sprintf('Function %s expects %d arguments, only got %d.', $node-&gt;target-&gt;value, count($parameters), count($node-&gt;arguments))
            );
        }

        // As this is just an example, we'll assume that all 
        // of the arguments being passed to the function are
        // positional and ignore any named arguments.
        foreach ($definition-&gt;getParameters() as $position =&gt; $parameter) {
            $parameterType = $parameter-&gt;getType();

            if ($parameterType === null || $parameterType-&gt;isMixed()) {
                continue;
            }

            $argument = $node-&gt;arguments[$position];
            $argumentType = $scope-&gt;getTypeOfExpression($argument);

            if (! $parameterType-&gt;isCompatibleWith($argumentType)) {
                $reporter-&gt;report(
                    sprintf('Argument #%d (%s) must be of type %s, got %s.', $position, $parameter-&gt;getName(), $parameterType-&gt;stringify(), $argumentType-&gt;stringify())
                );
            }
        }
    }
}
</code></pre>
<p>With this pseudo-analyser API, you can begin to see how the analyser works under-the-hood.</p>
<p>The rule will receive some sort of &quot;scope&quot; or &quot;environment&quot; object that stores information about where the node is located. It holds informations about the variables in the scope, the types of variables and can be used to find definitions.</p>
<p>Searching for definitions is also important since that will be at the core of most typechecking rules. The scope will have a reference to the definitions collected earlier on in the process and be able to do arbitrary lookups when necessary.</p>
<p>It will first check to see if a function exists in the current namespace, e.g. in the namespace <code>App</code>, a call to function <code>foo()</code> will first check for a function with the fully-qualified name <code>App\foo</code>.</p>
<p>If that function doesn't exist, it will then check for any imported functions with the name <code>foo</code>, e.g. <code>use function Package\foo</code>. Finally, it will look for a function defined in the global namespace called <code>foo</code> - this is normally where a lookup will land when analysing native PHP functions.</p>
<p>Most analysers will have a standardised API for representing types as well. There could be dedicated objects for PHP's scalar types (<code>string</code>, <code>int</code>, etc) and then more complex objects for generic types like <code>Collection&lt;T&gt;</code> or <code>array&lt;K, V&gt;</code>. It's important that these types are able to validate their own compatibility with another type object and be able to handle inheritance, etc.</p>
<p>Another detail in the pseudo-implementation above is the <code>Reporter</code>. This object is purely used for reporting issues / errors back to the user and will generally be scoped to the current file being analysed.</p>
<h2>Why write another static analyser?</h2>
<p>With a lot of existing art in this area (PHPStan, Psalm, Phan, etc), you might be wondering to yourself &quot;Why write another static analyser?&quot;... that's an excellent question! There's been a huge boom in the JavaScript ecosystem over the last few years with lots of new tools being written in lower-level languages such as Rust, Go and Zig. The same boom is yet to happen in the PHP ecosystem and I'd like to be one of the first catalysts in that movement.</p>
<p>By choosing a language such as Rust for a tool, you can bring memory safety and excellent performance to the table. PHP has improved a lot in the performance department over the years, but it will never reach the speeds of a systems programming language.</p>
<p>Alongside the speed and memory safety, I'm also developing a superset of PHP called <a href="https://pxplang.org/">PXP</a>. Part of this project involved writing a PHP parser in Rust and an extension of that parser to support the new superset. Given I already have a huge chunk of the work done, it makes sense to continue on this path and write more tools in Rust, not only as a learning experience for me but for all readers too.</p>
<p>The static analyser itself will play a big part in PXP's transpiler and allow us to do all sort of crazy things.</p>
<p>I'm not a Rust expert, but I've been using it for long enough now that I'm able to take on the challenge of writing these larger, complex systems.</p>
<h2>The plan for this analysis engine</h2>
<p>The rest of this series will cover the various phases in writing a static analyser. Before I get too far into the project itself, it's a good idea to come up with a plan of action and figure out the milestones and goals.</p>
<p>The initial goal for the analysis engine it to replicate PHPStan's lowest level of analysis (<a href="https://github.com/phpstan/phpstan-src/blob/1.10.x/conf/config.level0.neon">configuration on GitHub</a>). This includes the following:</p>
<ul>
<li>Validating function calls (function exists, number of arguments, argument types)</li>
<li>Validating class instantiation (class exists, number of constructor arguments, argument types)</li>
<li>Validating inheritance (ensuring parent class exists, abstract methods implemented)</li>
<li>Validating interface implementations (ensuring interface exists, contract methods implements)</li>
<li>Validating enums (missing backed type, validating case values, no abstract methods, no <code>__toString()</code>)</li>
<li>Validating method calls (static and instance methods, number of arguments, argument types)</li>
<li>Validating mathematical operations between invalid types, e.g. <code>string + int</code>.</li>
</ul>
<p>All development will be open-source and available on GitHub. A link to the repository will be provided in the next post.</p>
<h2>Epilogue</h2>
<p>I'm excited to start working on this project and see where it goes. I hope that you'll learn a thing or two about static analysis and Rust, perhaps you'll even contribute to the project at some point.</p>
<p>Posts will likely come out once a week to allow for development time in between, as well as any feedback from readers and those interested.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 23 Jan 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Setup (Writing a static analyser for PHP in Rust)]]></title>
                <link>https://ryangjchandler.co.uk/posts/writing-a-static-analyser-for-php-in-rust-setup</link>
                <description><![CDATA[<p>Welcome back to the series. This post is going to be a short one focused on setting up the Rust application and the command-line interface.</p>
<p>The goal is to get a boilerplate Rust project created, install <code>clap</code> and scaffold out a couple of commands.</p>
<p>In typical developer fashion, we need to the most important thing first and think of a name for the project. Let's go with <strong>Statan</strong>.</p>
<pre><code class="language-sh">cargo new statan
</code></pre>
<p>This will generate a <code>statan</code> folder with Cargo setup and a basic <code>main.rs</code> file.</p>
<p>There are quite a few options when it comes to argument parsing and command-line libraries in Rust. The most popular one is Clap, so we'll be using that. It can be installed with Cargo:</p>
<pre><code class="language-sh">cargo add clap --features derive
</code></pre>
<p>We'll want the <code>derive</code> feature enabled so that we can use Clap's derive macros, dramatically simplifying the setup process.</p>
<p>The first step in setting up Clap is creating a struct to hold the command-line arguments.</p>
<pre><code class="language-rust">use clap::Parser;

#[derive(Debug, Parser)]
struct Arguments {

}

fn main() {
    let arguments = Arguments::parse();
}
</code></pre>
<p>The CLI will be subcommand based. Thankfully, Clap provides a <code>Subcommand</code> macro that we can attach to an enumeration and it'll handle the rest.</p>
<pre><code class="language-rust">use clap::{Parser, Subcommand};

#[derive(Debug, Parser)]
struct Arguments {
    #[clap(subcommand)]
    command: Command,
}

#[derive(Debug, Subcommand)]
enum Command {
    #[clap(about = &quot;Analyse a file.&quot;)]
    Analyse,
}

fn main() {
    let arguments = Arguments::parse();
}
</code></pre>
<p>If we run the <code>cargo run -- --help</code> command, the <code>analyse</code> command should show up in the output.</p>
<pre><code>Usage: statan &lt;COMMAND&gt;

Commands:
  analyse  Analyse a file.
  help     Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
</code></pre>
<p>And if we run <code>cargo run -- analyse --help</code>, there will be some basic output too:</p>
<pre><code>Analyse a file.

Usage: statan analyse

Options:
  -h, --help  Print help
</code></pre>
<p>The first iteration of the <code>analyse</code> command will only support analysing a single file. To add the argument to the command, all we need to do is add a field to the <code>Command::Analyse</code> member with a macro.</p>
<pre><code class="language-rust">#[derive(Debug, Subcommand)]
enum Command {
    #[clap(about = &quot;Analyse a file.&quot;)]
    Analyse(AnalyseCommand)
}

#[derive(Debug, Parser)]
pub struct AnalyseCommand {
    #[clap(help = &quot;The file to analyse.&quot;)]
    file: String,
}
</code></pre>
<p>Each command will have it's own module in the application exposing a single <code>run</code> function. I typically like to place them under <code>src/cmd/[cmd].rs</code>.</p>
<p>The <code>main</code> function needs to be updated to defer handling to the correct function.</p>
<pre><code class="language-rust">use clap::{Parser, Subcommand};

mod cmd;

// ...

fn main() {
    let arguments = Arguments::parse();

    match arguments.command {
        Command::Analyse(args) =&gt; cmd::analyse::run(args),
    }
}
</code></pre>
<p>The <code>src/cmd/analyse.rs</code> file contains the function itself:</p>
<pre><code class="language-rust">use crate::AnalyseCommand;

pub fn run(command: AnalyseCommand) {
    
}
</code></pre>
<p>And the help output for the subcommand reflects the new argument:</p>
<pre><code>Analyse a file.

Usage: statan analyse &lt;FILE&gt;

Arguments:
  &lt;FILE&gt;  The file to analyse.

Options:
  -h, --help  Print help
</code></pre>
<p>Just like that, we've got a simple command-line interface to our new program. In the next part, we can start writing the business logic behind the analyser.</p>
<p><a href="https://github.com/pxp-lang/statan/tree/part-1/setup">The code for this part is public and can be found on GitHub</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 23 Jan 2023 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[2022: A year in review]]></title>
                <link>https://ryangjchandler.co.uk/posts/2022-a-year-in-review</link>
                <description><![CDATA[<h2>Personal</h2>
<p>Not much has happened in my personal life this year. We're due to move house again soon, but other than that nothing major has changed.</p>
<h2>Work</h2>
<p>I'm still a full-time developer at <a href="https://surewise.com">Surewise</a>. I've spent 2022 working on new systems and improving existing ones. We're continuing to adopt Livewire and Alpine.js across our stack.</p>
<p>We did upgrade to PHP 8.1 this year and will be looking to upgrade to PHP 8.2 early in 2023.</p>
<h3>Freelance</h3>
<p>My freelance adventures continued into 2022 and I've kept up with last years pace quite well. This will continue into 2023 as well as I continue to work on TALL related projects.</p>
<h2>Open-source</h2>
<p>It's been a bit of a quiet year on the OSS side of things. I've continued to maintain my projects and packages on <a href="https://github.com/ryangjchandler">GitHub</a> and have started working on a couple of new ones.</p>
<p>With my day job and freelance work, it's sometimes hard to find time for OSS work. When I do get time to work on non-work related things, I tend to focus on passion projects and things that I'm interested in.</p>
<p>The most noteworthy project that I've worked on this year is probably <a href="https://github.com/php-rust-tools/parser">a PHP parser written in Rust</a>. I broke ground on this project in July and worked on it here and there. The progression has increased dramatically over the last month or so with some help from <a href="https://twitter.com/azjezz">Saif (azjezz)</a> who has done lots of refactoring on the project and several optimizations, as well as adding support for things that were missing. So thank you!</p>
<p>My goal in 2023 is to explore the realm of Rust-powered tooling for PHP even more. I've got a &quot;small&quot; list of projects, some of which I've already started to experiment with:</p>
<ul>
<li>Linter</li>
<li>Code formatter</li>
<li>Static analysis</li>
<li>Superset</li>
</ul>
<p>Our cousins in JavaScript-land have been taking advantage of faster tooling for a couple of years now and there's been very few attempts at doing the same for PHP. I'd like to be the pioneer of this effort and take the first steps into this unexplored realm of productive PHP tooling.</p>
<h2>Epilogue</h2>
<p>As always, I want to say a huge thank you to everybody who has supported my OSS work, blog posts and <a href="https://github.com/sponsors/ryangjchandler">sponsored me on GitHub</a>. The continued support helps maintain my existing projects and packages, as well the development of new ones.</p>
<p>I set some more goals last year, I managed to complete one of those:</p>
<ul>
<li>Reach 5,000 followers on Twitter.</li>
</ul>
<p>I definitely wrote some more blog posts and streamed on YouTube but the consistency wasn't great.</p>
<p>I won't set myself any content related goals for 2023, but I would still like to speak at a conference. That would be pretty cool.</p>
<p>We'll see how that turns out in 2023.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[4 things I'd like to see in a future version of PHP]]></title>
                <link>https://ryangjchandler.co.uk/posts/4-things-id-like-to-see-in-a-future-version-of-php</link>
                <description><![CDATA[<p>Newer versions of PHP have introduced some excellent language features that bring it closer to other modern programming languages. We now have enums, match expressions, union and intersection types and much more.</p>
<p>Despite all of that, there are definitely still things that I'd personally like to see added to PHP. In this blog post, I'd like to cover a few of those things and provide some idealistic code snippets of what those features might look like.</p>
<h2>1. Type aliases</h2>
<p>A type alias is a way of giving a new name to an existing type, or set of types. They can sometimes improve readability in your code through more definitive naming and reduce duplication.</p>
<p>They can be found in languages such as TypeScript and Rust. Below is an example of what I imagine type aliases to look in PHP, in the context of a Filament trait where we tend to have lots of union types.</p>
<pre><code class="language-php">type LabelValue = string | null | Closure;

trait HasLabel
{
    protected LabelValue $label;

    public function label(LabelValue $label): string
    {
        $this-&gt;label = $label;

        return $this;
    }

    public function getLabel(): string
    {
        return $this-&gt;evaluate($this-&gt;label);
    }
}
</code></pre>
<p>The type alias above is what you would call &quot;transparent&quot;. This means that at runtime, the type <code>LabelValue</code> is treated exactly the same as <code>string | null | Closure</code>.</p>
<p>The transparency of the type means that you could alias <code>string</code> to something like <code>Name</code> and still be able to pass is to another function that expects a <code>string</code>.</p>
<p>The opposite to a transparent type alias is an opaque one. An example of a language with opaque type aliases is Hack. The major difference between a transparent and opaque type is how the underlying value is treated by the type system.</p>
<pre><code class="language-php">type Counter = int;
</code></pre>
<p>The <code>Counter</code> type above is essentially a regular <code>int</code>. If the language treated this as an opaque type, you wouldn't be allowed to do any normal integer operations on the value since the type assigned to the value would be <code>Counter</code>, not <code>int</code>. No addition, subtraction, etc allowed.</p>
<p>With the introduction of union, intersection and DNF types (PHP 8.2), type aliases could be a huge step forward when it comes to code deduplication and clarity.</p>
<h2>2. Multi-line match arms</h2>
<p>The <code>match</code> expression was introduce in PHP 8.0 and is a nicer way of conditionally doing something or computing a value based on a subject or result of an expression.</p>
<p><a href="/posts/all-about-match-expressions">(I have a whole blog post about match expressions if you want to read it)</a></p>
<p>Most people compare match expressions to switch statements. In a lot of cases they have the same result, with the added benefit of being more performant and concise.</p>
<p>The one drawback of match expressions is that you're limited to just a single expression in the &quot;result&quot; side of an arm.</p>
<pre><code class="language-php">$name = &quot;Ryan&quot;;

match ($name) {
    &quot;Ryan&quot; =&gt; &quot;Hey, I know you!&quot;,
};
</code></pre>
<p>The right-hand side of that double arrow can only be a single expression. You can't put a block of code and return a value, perhaps with further condition checks.</p>
<p>In an ideal world, you'd be able to do something like this:</p>
<pre><code class="language-php">match ($foo) {
    &quot;bar&quot; =&gt; {
        if ($baz) {
            // Do something here.
        }

        // Do something else and return a value.
    }
}
</code></pre>
<p>The original RFC for match expressions did briefly mention blocks of code on the right-hand side, but the semantics are difficult to get right.</p>
<p>Rust has implicit returns where you omit the semi-colon at the end of a statement, but PHP doesn't have that kind of behaviour anywhere else in the language.</p>
<p>You could allow using <code>return</code> to return a value from the block, but that's kind of confusing since <code>return</code> is explicitly for functions.</p>
<p>My own personal suggestion would be using <code>yield</code>. This keyword is already used to return a value from a block of code (generator functions) back to the caller / iterator, such that you're not actually returning and exiting from the function itself.</p>
<p>It would make perfect sense to use the same keyword in this scenario, since you are in fact yielding a value out of the block without returning from the lexical scope where the match expression is being used. The intent is clear, especially compared to implicit returns (sorry, Rust).</p>
<pre><code class="language-php">$message = match ($name) {
    &quot;Ryan&quot; =&gt; {
        if (logged_in()) {
            yield &quot;Welcome back, Ryan&quot;;
        }

        yield &quot;Hey Ryan, you need to log in again!&quot;;
    }
};

echo $message;
</code></pre>
<p>If this syntax and functionality eventually made it into the language, there's no reason you couldn't take it a step further and allow &quot;yielding blocks&quot; elsewhere like variables assignments.</p>
<pre><code class="language-php">$message = {
    if ($foo) {
        yield $bar;
    }

    yield $baz;
};
</code></pre>
<p><em>I'm interested in what people actually think about this syntax. I'd be very open to submitting an RFC and prototyping an implementation. Let me know on <a href="https://twitter.com/ryangjchandler">Twitter</a>.</em></p>
<h2>3. Generics</h2>
<p><img src="https://media0.giphy.com/media/pWEA23mJm9485IXhFV/giphy.gif" alt="" /></p>
<p>I know, I know. People have been banging on about generics in PHP for years. There has been an <a href="https://wiki.php.net/rfc/generics">RFC</a>, plenty of discussion and research on <a href="https://github.com/PHPGenerics/php-generics-rfc/issues">GitHub</a> and even OSS <a href="https://github.com/mrsuh/php-generics">attempts at bringing it to the language with tooling</a>. I'm sure you can cope with me banging on about it for a few more minutes.</p>
<p>PHP's type system has come a long way since the release of PHP 7.0. We can type function parameters, class properties, return types, the lot. We don't have a need for doc comments in these cases anymore, if anything they just add noise.</p>
<pre><code class="language-php">/**
 * @template T
 */
final class Collection
{
    /**
     * @var array&lt;T&gt;
     */
    private array $values = [];

    /**
     * @param T $value
     */
    public function push(mixed $value): self
    {
        $this-&gt;values[] = $value;

        return $this;
    }

    /**
     * @return array&lt;T&gt;
     */
    public function all(): array
    {
        return $this-&gt;values;
    }
}
</code></pre>
<p>It's all visual noise. Sure, it gives you static type-safety when you use PHPStan, but it could all be more concise. Compare it to this:</p>
<pre><code class="language-php">final class Collection&lt;T&gt;
{
    protected array&lt;T&gt; $values = [];

    public function push(T $value): self
    {
        $this-&gt;values[] = $value;
    }

    public function all(): array&lt;T&gt;
    {
        return $this-&gt;values;
    }
}
</code></pre>
<p>That's 50% less lines of code, just in one file. Let's take a look at how you'd instantiate one of these generic classes with both syntaxes.</p>
<p>With the doc comment syntax, instantiation looks like a normal <code>new</code> expression.</p>
<pre><code class="language-php">$users = new Collection();
</code></pre>
<p>If you wanted to specify the type of the collection at this point, you'd need yet another comment above the variable.</p>
<pre><code class="language-php">/**
 * @var Collection&lt;User&gt;
 */
$users = new Collection();
</code></pre>
<p>Compare that to the &quot;native&quot; looking syntax:</p>
<pre><code class="language-php">$users = new Collection&lt;User&gt;();
</code></pre>
<p>Let's go one level deeper again. What if you had this collection and wanted to pass it to a method somewhere?</p>
<pre><code class="language-php">class CollectionFriend
{
    /**
     * @param Collection&lt;User&gt; $collection
     */
    public function doSomethingWithUserCollection(Collection $collection)
    {
        //
    }
}
</code></pre>
<p>And another doc comment. The &quot;native&quot; syntax?</p>
<pre><code class="language-php">class CollectionFriend
{
    public function doSomethingWithUserCollection(Collection&lt;User&gt; $collection)
    {
        //
    }
}
</code></pre>
<p>It's clearer and cleaner.</p>
<p>Moving away from the syntax side of things, let's talk about the implementation strategy.</p>
<p>There are a few ways that generics can be implemented in programming languages - <strong>monomorphization</strong>, <strong>reification</strong> and <strong>type erasure</strong>.</p>
<h3>Monomorphization</h3>
<p>This is an automated process that takes your generic usage of a class and creates an additional dedicated class, specifically typed against the generic parameters at compile / runtime.</p>
<p>In the case of our <code>Collection&lt;User&gt;</code>, anytime you reference that specific type of collection, PHP will replace it will an identical class called <code>Collection_User</code> for example. Everywhere you use <code>T</code> (in methods, properties, etc), it will get replaced with <code>User</code>. This is the approach that Rust takes with generics and for a compiled language it's not a huge deal because your program is already being compiled, so there's less overhead on real runtime performance.</p>
<h3>Reificiation</h3>
<p>This process is closer to how PHP's type system currently operates. If you had a function that accepted a <code>string</code>, PHP will evaluate the type of the argument at runtime and throw a type error if it's wrong.</p>
<p>Reified generics would do the exact same thing. PHP would keep track of the type of value inside of our <code>Collection</code> and if we tried to push something that wasn't a <code>User</code>, it would throw a type error.</p>
<p>There's still some performance and memory overhead here because PHP is going to keep track of more things at runtime and need to do deeper type checking.</p>
<h3>Type erasure</h3>
<p>Python recently got support for static typing through the <code>typing</code> module and it uses type erasure to remove all of those types at runtime and only check them at compile time / with static analyzers.</p>
<p>In reality, this is going to be only option that has near-zero impact on runtime performance since PHP won't ever check the generic types when you interact with them. It'll forget about them and perhaps just check that the object is of the correct type, the same way it does now.</p>
<p>The natural follow-up question to this approach is &quot;Why bother putting the types there if they're not going to be checked by PHP anyway?&quot;</p>
<p>Excellent question! Here's my answer...</p>
<p>If you're already in a scenario where you're using doc comments to create generic classes, then I can almost guarantee that you're also using a static analyzer outside of PHP (PHPStan, Psalm, Phan, etc).</p>
<p>Type erased generics will behave the exact same way as your existing doc comments, with the exception that it's naturally all part of the language's syntax instead.</p>
<h2>4. Pattern matching on value types</h2>
<p>I'm sure you've written quite a few <code>is_array()</code>, <code>is_string()</code> or <code>$var instanceof SomeClass</code> checks before. My biggest gripe with these checks is the inconsistency between checking non-object types such as strings and integers and object types.</p>
<pre><code class="language-php">if ($var is int|array) {
    //
}
</code></pre>
<p>This would be equivalent to the below.</p>
<pre><code class="language-php">if (is_int($var) || is_array($var)) {
    
}
</code></pre>
<p>You'd essentially have this sort of syntax:</p>
<pre><code>&lt;subject&gt; is &lt;type_string&gt;
</code></pre>
<p>Where the type string is any valid type you can add to a parameter, property or return type.</p>
<h2>Summary</h2>
<p>And that's my short list of a few things I'd like to see added to PHP in the future.</p>
<p>Out of the 4 things above, the least likely is probably generics. The most likely additions are pattern matching on values types (<a href="https://wiki.php.net/rfc/pattern-matching">RFC</a>) and multi-line match arms.</p>
<p>If you weren't already aware, I'm currently working on a <a href="https://github.com/php-rust-tools/parser">PHP parser written in Rust</a>. One of my goals with this parser is to fully support the PHP language but also add extensions behind feature flags to support things such as generics, type aliases, etc.</p>
<p>I've started a <a href="https://github.com/orgs/php-rust-tools/repositories">GitHub organisation</a> which will be the home for all of these endeavours, so follow along if you're interested.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 07 Dec 2022 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Caching chunks of your Blade templates]]></title>
                <link>https://ryangjchandler.co.uk/posts/caching-chunks-of-your-blade-templates</link>
                <description><![CDATA[<p>As your application grows it's likely that your Blade templates will become more and more complex. With complexity will also likely come performance penalties, especially if you're doing large loops or rendering large components in your templates.</p>
<p>One way of tackling this in application code is by caching things, whether it's a database query, call to an external service or some heavy computational logic. Out of the box, Blade doesn't have any caching mechanism beyond pre-compiling templates into plain PHP.</p>
<p>That's where my <code>blade-cache-directive</code> package comes into play! With this package you can cache a chunk of your Blade template and avoid unnecessary recompilation in future renders.</p>
<p>Begin by installing the package with Composer.</p>
<pre><code class="language-sh">composer require ryangjchandler/blade-cache-directive
</code></pre>
<p>Now find the part of your Blade template that you'd like to cache and wrap it in a <code>@cache</code> directive.</p>
<pre><code class="language-blade">@cache('heavy-bit-of-blade')
    @foreach($someLargeArray as $_)
        {{-- ... --}}
    @endforeach
@endcache
</code></pre>
<p>And now your Blade is being cached. The default TTL (time to live) set by the package is 3600 seconds, or 60 minutes. If you want to change this, you can pass a second argument to the directive.</p>
<pre><code class="language-blade">@cache('heavy-bit-of-blade', 60)
    @foreach($someLargeArray as $_)
        {{-- ... --}}
    @endforeach
@endcache
</code></pre>
<p>Now it will only be cached for 60 seconds. Valid values for the TTL are the same as Laravel's own <code>Cache</code> methods.</p>
<p>One more thing to note. Since this package uses Laravel's <code>Cache</code> setup, clearing the cached chunk of Blade is as simple as calling <code>Cache::forget('heavy-bit-of-blade')</code> or clearing the application cache on deployment.</p>
<p>You can read more about this package <a href="https://github.com/ryangjchandler/blade-cache-directive">on GitHub</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 10 Nov 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Adding feature flags to your Laravel project]]></title>
                <link>https://ryangjchandler.co.uk/posts/adding-feature-flags-to-your-laravel-project</link>
                <description><![CDATA[<p>Feature flags allow you to remotely enable and disable features without deploying new code. They can be toggled at an application level and apply to all users or be scoped to a single user.</p>
<p>Adding them to your Laravel application is incredibly simple thanks to my <a href="https://github.com/ryangjchandler/laravel-feature-flags"><code>ryangjchandler/laravel-feature-flags</code></a> package.</p>
<p>Begin by installing the package with Composer and running the migrations:</p>
<pre><code class="language-sh">composer require ryangjchandler/laravel-feature-flags
php artisan vendor:publish --tag=&quot;feature-flags-migrations&quot;
php artisan migrate
</code></pre>
<p>This will create a new <code>feature_flags</code> table in your application's database.</p>
<p>All methods are called through the <code>RyanChandler\LaravelFeatureFlags\Facades\Features</code> facade. To create your first flag, call <code>Features::add()</code>.</p>
<pre><code class="language-php">use RyanChandler\LaravelFeatureFlags\Facades\Features;

Features::add('show-share-buttons');
</code></pre>
<p>This will create a <strong>global</strong> feature flag called <code>show-share-buttons</code>. To check if this flag is enabled or disabled, you can use the <code>Features::enabled()</code> and <code>Features::disabled()</code> methods.</p>
<pre><code class="language-php">if (Features::enabled('show-share-buttons')) {
    // ...
}
</code></pre>
<p>It's probably quite common to conditionally render parts of your Blade templates based on a feature flag. The package also provides a Blade directive that simplifies things.</p>
<pre><code class="language-blade">@feature('show-share-buttons')
    &lt;a href=&quot;https://twitter.com&quot;&gt;
        Twitter
    &lt;/a&gt;
@endfeature
</code></pre>
<h3>Changing the state of a flag</h3>
<p>To change the state of a flag, use the <code>Features::enable()</code> and <code>Features::disable()</code> methods.</p>
<pre><code class="language-php">Features::enable('show-share-buttons');
Features::disable('show-share-buttons');
</code></pre>
<p>These methods use an <code>updateOrCreate()</code> call behind the scenes so if the flag doesn't exist, it will be created automatically.</p>
<p>If you simply want to toggle the state of a flag, i.e. via a button click, you can use the <code>Features::toggle()</code> method instead.</p>
<h3>Model flags</h3>
<p>All the examples so far have shown you how to handle global flags. There will definitely be cases where you want flags to be scoped to a single model, e.g. a <code>User</code> or <code>Team</code>.</p>
<p>To keep the API and method calls consistent, the package takes advantage of named arguments to create a modifiable method signature. This means that all of the method calls mentioned above will still work for models, you just need to provide a named <code>for</code> argument and model that implements the <code>RyanChandler\LaravelFeatureFlags\Models\Contracts\HasFeatures</code> interface.</p>
<p>Here's an example of a <code>User</code> model that is compatible.</p>
<pre><code class="language-php">use RyanChandler\LaravelFeatureFlags\Models\Contracts\HasFeatures;

class User extends Authenticatable implements HasFeatures
{
    // ...
}
</code></pre>
<p>This interface defines a few methods that need to be implemented on the class. To save you the hassle of writing them yourself, you can use the <code>RyanChandler\LaravelFeatureFlags\Models\Concerns\WithFeatures</code> trait to implement the methods for you.</p>
<pre><code class="language-php">use RyanChandler\LaravelFeatureFlags\Models\Contracts\HasFeatures;
use RyanChandler\LaravelFeatureFlags\Models\Concerns\WithFeatures;

class User extends Authenticatable implements HasFeatures
{
    use WithFeatures;
}
</code></pre>
<p>You can now call all of the same methods on <code>Features</code> and provide a named <code>for</code> argument.</p>
<pre><code class="language-php">Features::add('show-social-buttons', for: $user)
Features::enable('show-social-buttons', for: $user)
Features::disable('show-social-buttons', for: $user)
Features::toggle('show-social-buttons', for: $user)
Features::enabled('show-social-buttons', for: $user)
Features::disabled('show-social-buttons', for: $user)
</code></pre>
<h2>Filament integration</h2>
<p>If you're using <a href="https://filamentphp.com">Filament</a>, there is an additional package that provides a simple UI for managing feature flags. You can find out more in the <a href="https://github.com/ryangjchandler/filament-feature-flags">GitHub repository's README file</a>.</p>
<p><img src="https://github.com/ryangjchandler/filament-feature-flags/raw/main/art/table.png" alt="" /></p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 12 Oct 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Building a custom color palette field in Filament - Part 3]]></title>
                <link>https://ryangjchandler.co.uk/posts/building-a-custom-color-palette-field-in-filament-part-3</link>
                <description><![CDATA[<p>Let's spruce up our field a little bit and add some extra methods of customisation.</p>
<p>There might be certain scenarios where you want to store the name instead of the actual color code in your applications. This could be useful if you are building a CMS and want to conditionally apply classes to an element based on the name of a color instead of the color code, avoiding the need for inline styles in your markup.</p>
<p>To achieve this, we'll add a new <code>storeColorName()</code> method to the field and adjust the field's functionality accordingly.</p>
<pre><code class="language-php">class ColorPalette extends Field
{
    // ...

    protected bool | Closure $shouldStoreColorName = false;

    // ...

    public function storeColorName(bool | Closure $condition = true): static
    {
        $this-&gt;shouldStoreColorName = $condition;

        return $this;
    }

    public function shouldStoreColorName(): bool
    {
        return (bool) $this-&gt;evaluate($this-&gt;shouldStoreColorName);
    }
}
</code></pre>
<p>And making some changes in the Blade view:</p>
<pre><code class="language-blade">@php
    $shouldStoreColorName = $shouldStoreColorName();
@endphp

&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div x-data=&quot;{ state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }} }&quot; class=&quot;flex items-center space-x-4&quot;&gt;
        @foreach($getOptions() as $color =&gt; $label)
            @php($value = $shouldStoreColorName ? $label : $color)

            &lt;button
                type=&quot;button&quot;
                x-on:click=&quot;state = @js($value)&quot;
                class=&quot;rounded-full w-8 h-8 border border-gray-300 relative inline-flex items-center justify-center&quot;
                x-bind:class=&quot;{
                    'ring-2 ring-gray-300 ring-offset-2': state === @js($value),
                }&quot;
                style=&quot;background: {{ $color }}&quot; title=&quot;{{ $label }}&quot;
            &gt;
                &lt;span class=&quot;sr-only&quot;&gt;
                    {{ $label }}
                &lt;/span&gt;

                &lt;span x-show=&quot;state === @js($value)&quot; x-cloak&gt;
                    &lt;x-heroicon-o-check class=&quot;w-4 h-4 text-gray-400&quot; /&gt;
                &lt;/span&gt;
            &lt;/button&gt;
        @endforeach
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>When selecting an option now it will use the color's name instead of the color code.</p>
<h2>Allowing additional color selection</h2>
<p>In some cases you might want your users to select their own color. Modern web browsers provide a color picker input type which we can use to do this.</p>
<p>Let's start by adding a method like before:</p>
<pre><code class="language-php">class ColorPalette extends Field
{
    // ...
    
    protected bool | Closure $canChooseCustomColors = false;

    // ...

    public function allowCustomColors(bool | Closure $condition = true): static
    {
        $this-&gt;canChooseCustomColors = $condition;

        return $this;
    }

    public function canChooseCustomColors(): bool
    {
        return (bool) $this-&gt;evaluate($this-&gt;canChooseCustomColors);
    }
}
</code></pre>
<p>And again, make some changes in the Blade view:</p>
<pre><code class="language-blade">@php
    $shouldStoreColorName = $shouldStoreColorName();
@endphp

&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div x-data=&quot;{ state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }} }&quot; class=&quot;flex space-x-4&quot;&gt;
        @foreach($getOptions() as $color =&gt; $label)
            @php($value = $shouldStoreColorName ? $label : $color)

            &lt;button
                type=&quot;button&quot;
                x-on:click=&quot;state = @js($value)&quot;
                class=&quot;rounded-full w-8 h-8 border border-gray-300 relative inline-flex items-center justify-center&quot;
                x-bind:class=&quot;{
                    'ring-2 ring-gray-300 ring-offset-2': state === @js($value),
                }&quot;
                style=&quot;background: {{ $color }}&quot; title=&quot;{{ $label }}&quot;
            &gt;
                &lt;span class=&quot;sr-only&quot;&gt;
                    {{ $label }}
                &lt;/span&gt;

                &lt;span x-show=&quot;state === @js($value)&quot; x-cloak&gt;
                    &lt;x-heroicon-o-check class=&quot;w-4 h-4 text-gray-400&quot; /&gt;
                &lt;/span&gt;
            &lt;/button&gt;
        @endforeach

        @if($canChooseCustomColors() &amp;&amp; ! $shouldStoreColorName)
            &lt;div class=&quot;flex border bg-gray-50 rounded-lg&quot;&gt;
                &lt;input type=&quot;color&quot; name=&quot;{{ $getStatePath() }}.custom&quot; x-model.lazy=&quot;state&quot; class=&quot;block h-full p-0 rounded-l-lg&quot;&gt;
                &lt;div class=&quot;text-xs font-medium px-2 inline-flex items-center&quot;&gt;
                    &lt;span&gt;Select Color&lt;/span&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        @endif
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>Alpine.js is handling the state changes on the color input and with some styling we can get it to look like a single input still. Here's the result:</p>
<p><img src="./part-3-custom-colors.png" alt="" /></p>
<p>Whilst we're here we should add a method that lets you change the custom color selector's label.</p>
<pre><code class="language-php">class ColorPalette extends Field
{
    // ...

    protected string | Closure $customColorLabel = 'Select Color';

    // ...

    public function customColorLabel(string | Closure $label): static
    {
        $this-&gt;customColorLabel = $label;

        return $this;
    }

    public function getCustomColorLabel(): string
    {
        return (string) $this-&gt;evaluate($this-&gt;customColorLabel);
    }
}
</code></pre>
<p>And updating the Blade view really simple:</p>
<pre><code class="language-blade">@php
    $shouldStoreColorName = $shouldStoreColorName();
@endphp

&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div x-data=&quot;{ state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }} }&quot; class=&quot;flex space-x-4&quot;&gt;
        @foreach($getOptions() as $color =&gt; $label)
            @php($value = $shouldStoreColorName ? $label : $color)

            &lt;button
                type=&quot;button&quot;
                x-on:click=&quot;state = @js($value)&quot;
                class=&quot;rounded-full w-8 h-8 border border-gray-300 relative inline-flex items-center justify-center&quot;
                x-bind:class=&quot;{
                    'ring-2 ring-gray-300 ring-offset-2': state === @js($value),
                }&quot;
                style=&quot;background: {{ $color }}&quot; title=&quot;{{ $label }}&quot;
            &gt;
                &lt;span class=&quot;sr-only&quot;&gt;
                    {{ $label }}
                &lt;/span&gt;

                &lt;span x-show=&quot;state === @js($value)&quot; x-cloak&gt;
                    &lt;x-heroicon-o-check class=&quot;w-4 h-4 text-gray-400&quot; /&gt;
                &lt;/span&gt;
            &lt;/button&gt;
        @endforeach

        @if($canChooseCustomColors() &amp;&amp; ! $shouldStoreColorName)
            &lt;div class=&quot;flex border bg-gray-50 rounded-lg&quot;&gt;
                &lt;input type=&quot;color&quot; name=&quot;{{ $getStatePath() }}.custom&quot; x-model.lazy=&quot;state&quot; class=&quot;block h-full p-0 rounded-l-lg&quot;&gt;
                &lt;div class=&quot;text-xs font-medium px-2 inline-flex items-center&quot;&gt;
                    &lt;span&gt;{{ $getCustomColorLabel() }}&lt;/span&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        @endif
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>And there we have it. A pretty powerful and useful <code>ColorPalette</code> field that lets you select a color from a fixed list of options and also choose your own custom colors.</p>
<p>Hopefully you found this mini-series helpful and learned a thing or two.</p>
<p>If you want to use this field in your own projects without rebuilding it, it's available for free on GitHub. You can find installation and usage instructions <a href="https://github.com/ryangjchandler/filament-color-palette">in the repository</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 06 Oct 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Building a custom color palette field in Filament - Part 2]]></title>
                <link>https://ryangjchandler.co.uk/posts/building-a-custom-color-palette-field-in-filament-part-2</link>
                <description><![CDATA[<p>Time to start changing the state on the form! But first, some base knowledge.</p>
<p>All <em>fields</em> in a Filament form have a unique &quot;state path&quot;. The state path is the location on the Livewire component that contains your form where the current value / state of your field can be found.</p>
<p>The state path for a form field can be retrieved using the <code>getStatePath()</code> method. This can be called from the field class itself or inside of a Blade view by invoking the <code>$getStatePath</code> variable.</p>
<p>Let's start by making the color buttons update the state of the field. We'll be using Alpine to do this instead of Livewire's own <code>wire:</code> directives.</p>
<pre><code class="language-blade">&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div
        x-data=&quot;{ state: $wire.entangle('{{ $getStatePath() }}') }&quot;
        class=&quot;flex items-center space-x-4&quot;
    &gt;
        @foreach($getOptions() as $color =&gt; $label)
            &lt;button
                type=&quot;button&quot;
                x-on:click=&quot;state = @js($color)&quot;
                class=&quot;rounded-full w-8 h-8 border border-gray-500&quot;
                style=&quot;background: {{ $color }}&quot; title=&quot;{{ $label }}&quot;
            &gt;
                &lt;span class=&quot;sr-only&quot;&gt;
                    {{ $label }}
                &lt;/span&gt;
            &lt;/button&gt;
        @endforeach
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>On my test form component, I've added an <code>updatedColor</code> hook that will get called when the state is updated.</p>
<pre><code class="language-php">public function updatedColor()
{
    dd($this-&gt;color);
}
</code></pre>
<p>And this is the result...</p>
<p><img src="https://ryangjchandler.co.uk/storage/KUU4zVpdY1nxJgzypdQsK99Fhag6jwckhwIQ4zhu.gif" alt="" /></p>
<p>The <code>dd()</code> is being reached and the property at the state path is being updated. Nifty!</p>
<p>Writing super optimal fields is important in Filament since any unnecessary state updates will result in back and forth Livewire requests and multiple re-renders. If I choose an option, 1 request is going to be sent to update the state. If I then realise that it's the wrong option and choose another, a second request will be sent to update the state again.</p>
<p>These duplicated requests aren't always necessary and Filament fields generally follow a defer-first approach. If you're not familiar with Livewire's deferred binding system, <a href="https://laravel-livewire.com/docs/2.x/properties#deferred-updating">read the documentation</a>.</p>
<p>Fields in Filament are responsible for their own state binding method (reactive, deferred or lazy). To get the current binding modifier, we can use the <code>$applyStateBindingModifiers()</code> function.</p>
<p>This function accepts a single string which will be the method or directive you'd like to apply the modifiers to. In our case, it's going to be the <code>entangle()</code> method on <code>$wire</code>.</p>
<p>Updating the code inside of the Blade view looks something like this:</p>
<pre><code class="language-blade">&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div x-data=&quot;{ state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }} }&quot; class=&quot;flex items-center space-x-4&quot;&gt;
        @foreach($getOptions() as $color =&gt; $label)
            &lt;button
                type=&quot;button&quot;
                x-on:click=&quot;state = @js($color)&quot;
                class=&quot;rounded-full w-8 h-8 border border-gray-500&quot;
                style=&quot;background: {{ $color }}&quot; title=&quot;{{ $label }}&quot;
            &gt;
                &lt;span class=&quot;sr-only&quot;&gt;
                    {{ $label }}
                &lt;/span&gt;
            &lt;/button&gt;
        @endforeach
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>Admittedly this code is a little hard to read at first with the string concatenation and escaping of single quotes. All it's doing is building up the same <code>entangle('{{ $getStatePath() }}')</code> string as before and sending it through <code>$applyStateBindingModifiers()</code>.</p>
<p>On a simple <code>ColorPalette::make()</code> call, this will result in the <code>.defer</code> modifier being applied to the <code>$wire.entangle()</code> call meaning any state changes are deferred until the next Livewire action is invoked, normally saving the form or changing the state of a reactive field.</p>
<p>To make the field reactive again, you just need to call <code>-&gt;reactive()</code> on the field itself, i.e.</p>
<pre><code class="language-php">ColorPalette::make('color')
    -&gt;reactive(),
</code></pre>
<h2>Visual display of selected option</h2>
<p>Functionally speaking the field is working. Visually though, it's impossible to tell which option is selected. Let's change this by applying a ring to the selected option as well as a checkmark.</p>
<p>We can use Alpine again to conditionally apply classes to the button, since we already have a reference to the current <code>state</code>.</p>
<pre><code class="language-blade">&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div x-data=&quot;{ state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }} }&quot; class=&quot;flex items-center space-x-4&quot;&gt;
        @foreach($getOptions() as $color =&gt; $label)
            &lt;button
                type=&quot;button&quot;
                x-on:click=&quot;state = @js($color)&quot;
                class=&quot;rounded-full w-8 h-8 border border-gray-300 appearance-none inline-flex items-center justify-center&quot;
                x-bind:class=&quot;{
                    'ring-2 ring-gray-300 ring-offset-2': state === @js($color),
                }&quot;
                style=&quot;background: {{ $color }}&quot; title=&quot;{{ $label }}&quot;
            &gt;
                &lt;span class=&quot;sr-only&quot;&gt;
                    {{ $label }}
                &lt;/span&gt;

                &lt;span x-show=&quot;state === @js($color)&quot; x-cloak&gt;
                    &lt;x-heroicon-o-check class=&quot;w-4 h-4 text-gray-400&quot; /&gt;
                &lt;/span&gt;
            &lt;/button&gt;
        @endforeach
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>Using <code>x-bind:class</code> and <code>x-show</code> we can conditionally add classes to the button and toggle a checkmark icon from <a href="https://heroicons.com">Heroicons</a>.</p>
<p>The final result looks like this:</p>
<p><img src="https://ryangjchandler.co.uk/storage/otKgLqLVZvuDhvzXSXmmAxkqzfJvjzbCpDgMBDqG.png" alt="" /></p>
<p>In the next and final part of this series, we'll look at some extra methods we can add to <code>ColorPalette</code> to make it more developer friendly.</p>
<p>Hello, Twitter!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 05 Oct 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Building a custom color palette field in Filament - Part 1]]></title>
                <link>https://ryangjchandler.co.uk/posts/building-a-custom-color-palette-field-in-filament-part-1</link>
                <description><![CDATA[<p>To accept an array of options on the field, we need to declare a new method on the class. This method will accept an array of <code>$options</code> and store it in a property on the object also called <code>$options</code>.</p>
<pre><code class="language-php">class ColorPalette extends Field
{
    // ...

    protected array $options = [];

    public function options(array $options): static
    {
        $this-&gt;options = $options;

        return $this;
    }
}
</code></pre>
<p>We can now pass an array of options to the field in our form:</p>
<pre><code class="language-php">ColorPalette::make('color')
    -&gt;options([
        '#ffffff' =&gt; 'White',
        '#000000' =&gt; 'Black',
    ]),
</code></pre>
<h2>Retrieving the options</h2>
<p>All fields and form components in Filament are actually just Blade components under the hood. This means we can define public methods on our <code>ColorPalette</code> class and they will be sent through to the Blade view as invokable variables.</p>
<p>Let's add a <code>getOptions()</code> method to the field that returns the array of options given to the field.</p>
<pre><code class="language-php">class ColorPalette extends Field
{
    // ...

    public function getOptions(): array
    {
        return $this-&gt;options;
    }
}
</code></pre>
<p>Now inside of our Blade view, we can call this method and loop over the returned <code>array</code>.</p>
<pre><code class="language-blade">&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div class=&quot;flex items-center space-x-4&quot;&gt;
        @foreach($getOptions() as $color =&gt; $label)
            &lt;button type=&quot;button&quot; class=&quot;rounded-full w-8 h-8 border border-gray-500&quot; style=&quot;background: {{ $color }}&quot; title=&quot;{{ $label }}&quot;&gt;
                &lt;span class=&quot;sr-only&quot;&gt;
                    {{ $label }}
                &lt;/span&gt;
            &lt;/button&gt;
        @endforeach
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>Using inline styles, we can change the background color of the button to the option's color. For accessibility reasons, we'll also output the <code>$label</code> provided but only for screenreaders.</p>
<p>And just like that, we're rendering the color options on the page.</p>
<p><img src="https://ryangjchandler.co.uk/storage/8EAeJZk4HcZwkOCpBsRapez5WHEl5MOX0Z802Rvi.png" alt="" /></p>
<h3>Adding support for computed options</h3>
<p>In its current state, the <code>ColorPalette</code> field can only accept a static array of color options. This causes problems when you want to change the color options based on the value of another field or the record you're working on.</p>
<p>This is where Filament's incredibly powerful <a href="https://filamentphp.com/docs/2.x/forms/advanced#using-closure-customisation">Closure customisation</a> system comes into play. By widening the type of the <code>$options</code> argument to also accept <code>Closure</code> values, we can allow developers to provide a computed list of options instead of a static list.</p>
<p>There are a few steps to make this work. The first being widening the types on the class itself.</p>
<pre><code class="language-php">class ColorPalette extends Field
{
    // ...

    protected array | Closure $options = [];

    public function options(array | Closure $options): static
    {
        $this-&gt;options = $options;

        return $this;
    }

    // ...
}
</code></pre>
<p>The <code>ColorPalette::options()</code> method now accepts an <code>array</code> or <code>Closure</code> through a <a href="https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.composite.union">union type</a>. This allows us to do this:</p>
<pre><code class="language-php">Select::make('theme')
    -&gt;reactive()
    -&gt;options([
        'minimal' =&gt; 'Minimal',
        'abstract' =&gt; 'Abstract',
    ]),
ColorPalette::make('color')
    -&gt;options(function (callable $get) {
        if ($get('theme') === 'abstract') {
            return [
                '#ff69b4' =&gt; 'Hot Pink',
                '#32cd32' =&gt; 'Lime Green',
            ];
        }

        return [
            '#ffffff' =&gt; 'White',
            '#000000' =&gt; 'Black',
        ];
    })
</code></pre>
<p>Now the <code>ColorPalette</code> field's options will be updated and computed based on the option selected in the <code>Select</code> field above it. Or will they?</p>
<p>There's one more thing we need to do. We need to actually invoke the <code>Closure</code>. Thankfully, Filament has a smooth <code>evaluate()</code> API which will invoke a <code>Closure</code> and provide some standardised arguments depending on the context you're evaluating it in.</p>
<p>Instead of returning <code>$this-&gt;options</code> inside of <code>getOptions()</code>, we can return send the value through <code>$this-&gt;evaluate()</code> and return the result of that instead.</p>
<pre><code class="language-php">class ColorPalette extends Field
{
    // ...
    
    public function getOptions(): array
    {
        return $this-&gt;evaluate($this-&gt;options);
    }
}
</code></pre>
<p>In the next part, we'll hook up our buttons and start persisting state to the form / Livewire component.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 04 Oct 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Building a custom color palette field in Filament - Part 0]]></title>
                <link>https://ryangjchandler.co.uk/posts/building-a-custom-color-palette-field-in-filament-part-0</link>
                <description><![CDATA[<p>In this short series of blog posts, I'll show you how to create a custom Filament field.</p>
<p>The field we'll be building is a color palette field that lets you select a color from a fixed list of options. Such a simple field will cover the basics of rendering a field and syncing the selected option with the property on the form itself.</p>
<p>Here's an example of the field's API:</p>
<pre><code class="language-php">ColorPalette::make('color')
    -&gt;options([
        '#ffffff' =&gt; 'White',
        '#000000' =&gt; 'Black',
    ]),
</code></pre>
<p>The color options will be an array of colors and labels. The label will be used to show a tooltip when hovering over the chosen color and the color value itself will be used to render the option.</p>
<h2>Generating the boilerplate</h2>
<p>To generate an empty field, run the <code>php artisan make:form-field</code> command.</p>
<pre><code>$ php artisan make:form-field

Name (e.g. `RangeSlider`):
&gt; ColorPalette

Successfully created ColorPalette!
</code></pre>
<p>This command is provided by the <code>filament/forms</code> package and will generate a basic <code>Field</code> class and corresponding Blade view.</p>
<p>Open up the new <code>app/Forms/Components/ColorPalette.php</code> file and you should see this:</p>
<pre><code class="language-php">&lt;?php

namespace App\Forms\Components;

use Filament\Forms\Components\Field;

class ColorPalette extends Field
{
    protected string $view = 'forms.components.color-palette';
}
</code></pre>
<p>The field is already setup to render a particular Blade view, so let's also take a look at that.</p>
<pre><code class="language-blade">&lt;x-forms::field-wrapper
    :id=&quot;$getId()&quot;
    :label=&quot;$getLabel()&quot;
    :label-sr-only=&quot;$isLabelHidden()&quot;
    :helper-text=&quot;$getHelperText()&quot;
    :hint=&quot;$getHint()&quot;
    :hint-icon=&quot;$getHintIcon()&quot;
    :required=&quot;$isRequired()&quot;
    :state-path=&quot;$getStatePath()&quot;
&gt;
    &lt;div x-data=&quot;{ state: $wire.entangle('{{ $getStatePath() }}') }&quot;&gt;
        &lt;!-- Interact with the `state` property in Alpine.js --&gt;
    &lt;/div&gt;
&lt;/x-forms::field-wrapper&gt;
</code></pre>
<p>The boilerplate code inside of the Blade view might be a bit overwhelming at first, but it's actually Filament doing a lot of the heavy lifting for us. It's configuring the field wrapper (the component that renders the label, helper text, etc) and also gives us a basic Alpine component with the field's property already &quot;entangled&quot;.</p>
<p>If we render this almost empty field inside of a form, you'll see something like this.</p>
<p><img src="https://ryangjchandler.co.uk/storage/ChS0IM8oFD98D3d0VPExa91mu6x9Zh0zFrzpDQjj.png" alt="" /></p>
<p>In the next part, we'll add a method to the field that accepts an array of options and start rendering some option buttons to the front-end.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 03 Oct 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Building a custom Filament view component]]></title>
                <link>https://ryangjchandler.co.uk/posts/building-a-custom-filament-view-component</link>
                <description><![CDATA[<p>Out of the box, Filament provides a tonne of components that you can use in your application. Sometimes you might need something a little extra. Let's look at how I built a <code>DescriptionList</code> component for one of my own projects.</p>
<p>We start off by creating a new <code>Component</code> class. I'm going to do this manually inside of <code>app/Forms/Components</code>.</p>
<pre><code class="language-php">&lt;?php

namespace App\Forms\Components;

use Filament\Forms\Components\Component;

class DescriptionList extends Component
{
    public static function make(): static
    {
        return new static();
    }
}
</code></pre>
<p>The first thing we need to do is specify the view that your component uses. This is done via a <code>$view</code> property on the class.</p>
<pre><code class="language-php">class DescriptionList extends Component
{
    protected string $view = 'filament.forms.components.description-list';
}
</code></pre>
<p>I tend to structure my views the same way the classes are structured, with the exception of placing it inside of an extra top-level <code>filament</code> folder for separation from other folders in my application.</p>
<p>The <code>DescriptionList</code> components is going to loop over an array of key value pairs where the key is used as the term <code>&lt;dt&gt;</code> and the value is used as the description <code>&lt;dd&gt;</code>. Let's add a method to the component that accepts that array.</p>
<pre><code class="language-php">class DescriptionList extends Component
{
    protected string $view = 'filament.forms.components.description-list';

    protected array $items = [];

    public function items(array $items): static
    {
        $this-&gt;items = $items;
        
        return $this;
    }
}
</code></pre>
<p>Now in your form, we can use the component:</p>
<pre><code class="language-php">protected function getFormSchema(): array
{
    return [
        DescriptionList::make('overview')
            -&gt;items([
                'Name' =&gt; $this-&gt;user-&gt;name,
                'Email' =&gt; $this-&gt;user-&gt;email,
            ]),
    ];
}
</code></pre>
<p>Inside of our view we can start to output some values, but how do we get those values?</p>
<p>Fields and components in Filament are actually all Blade components under the hood, which means all public properties and methods get passed to the view as variables. We can add a new <code>getItems()</code> method to the component class and invoke that inside of our Blade view.</p>
<pre><code class="language-php">class DescriptionList extends Component
{
    protected string $view = 'filament.forms.components.description-list';

    protected array $items = [];

    // ...

    public function getItems(): array
    {
        return $this-&gt;items;
    }
}
</code></pre>
<pre><code class="language-blade">&lt;dl&gt;
    @foreach($getItems() as $term =&gt; $description)
        &lt;dt&gt;{{ $term }}&lt;/dt&gt;
        &lt;dd&gt;{{ $description }}&lt;/dd&gt;
    @endforeach
&lt;/dl&gt;
</code></pre>
<p>And we have some data being rendered now, cool! Let's take this a step further and look at using <code>Closure</code> objects to allow more dynamic lists of data.</p>
<p>The first step is changing what values we accept on our <code>items()</code> method.</p>
<pre><code class="language-php">class DescriptionList extends Component
{
    protected string $view = 'filament.forms.components.description-list';

    protected array | Closure $items = [];

    public function items(array | Closure $items): static
    {
        $this-&gt;items = $items;
        
        return $this;
    }
}
</code></pre>
<p>If we use a union type to also accept a <code>Closure</code>, users will be able to use <a href="https://filamentphp.com/docs/2.x/forms/advanced#using-closure-customisation">closure customisation</a> to generate dynamic sets of data based on other fields or the current record.</p>
<pre><code class="language-php">protected function getFormSchema(): array
{
    return [
        DescriptionList::make()
            -&gt;items(function (Model $record, Closure $get) {
                $items = [
                    'Name' =&gt; $record-&gt;name,
                    'Email' =&gt; $record-&gt;email,
                ];

                if (!! $get('show_dangerous_things')) {
                    $items['Password'] = magical_function_to_reverse_sha256_hash($record-&gt;password);
                }

                return $items;
            }),
    ];
}
</code></pre>
<p>The <code>getItems()</code> method also needs to be updated to handle the new <code>Closure</code> object. Filament provides a handy <code>evaluate()</code> method which will take in a value and if it happens to be a <code>Closure</code>, it will run it through Laravel's service container and pass through an array of handy argument such as <code>$record</code>, <code>$get</code>, etc.</p>
<p>If the value provided to <code>evaluate()</code> isn't invokable, it will just return it as is meaning our <code>array</code> types will still work as expected.</p>
<pre><code class="language-php">class DescriptionList extends Component
{
    public function getItems(): array
    {
        return $this-&gt;evaluate($this-&gt;items);
    }
}
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 23 Sep 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Compiling PHP's conditional statements to Rust]]></title>
                <link>https://ryangjchandler.co.uk/posts/compiling-phps-conditional-statements-to-rust</link>
                <description><![CDATA[<p>Welcome back to the series. It's time to take another step into compilation land and look at compiling PHP's conditional statements (<code>if</code> statements) into Rust code.</p>
<p>The goal for this post will be compiling the following code:</p>
<pre><code class="language-php">$guess = readline(&quot;Guess a number between 1 and 3: &quot;);
$number = rand(1, 3);

if ($guess == $number) {
    echo &quot;You guessed the number correctly, well done!&quot;;
} else {
    echo &quot;The correct answer is &quot; . $number . &quot;. Better luck next time!&quot;;
}
</code></pre>
<p>Before we start writing some Rust, let's analyze the code and look at the things we'll need to implement.</p>
<p>At the very top of the script we've got some variable assignments. This is a type of expression so we'll need to add some new code to the <code>compile_expression()</code> function.</p>
<p>On the right-hand side of those assignments we're calling some native / first-party PHP functions. These don't exist in our runtime at the moment, so we'll need to implement those in Rust land as part of our <code>runtime.rs</code> file.</p>
<p>We then reach the conditional statements. We'll need to handle the compilation of the structure itself, along with the expressions used inside of blocks.</p>
<p>The condition in our <code>if</code> statement uses the <code>==</code> operator which is referred to as an <strong>infix</strong> operator. The <code>compile_expression()</code> will need to be updated to handle this new type of expression as well. We'll also need to keep in mind that Rust doesn't have any concept of loose or strict comparisons, instead we'll need to implement thing logic ourself.</p>
<p>Let start by supporting the assignment expression and writing our own implementations of <code>readline()</code> and <code>rand()</code>.</p>
<h2>Assignment expressions</h2>
<p>An assignment expression in the Rust code will be represented with a <code>let</code> statement. PHP variables are all mutable but Rust lets us redeclare and rebind a variable after its original definition with another <code>let</code> statement. Here's an example.</p>
<pre><code class="language-rust">let foo = 1;
let foo = 2;
</code></pre>
<p>The second binding will replace the original without needing to make the original assignment mutable. Let's add this code to <code>compile_expression()</code>.</p>
<pre><code class="language-rust">fn compile_expression(expression: &amp;Expression) -&gt; Result&lt;String, CompileError&gt; {
    let result = match expression {
        // ...
        Expression::Assign(target, value) =&gt; {
            format!(&quot;let {} = {};&quot;, compile_expression(target)?, compile_expression(value)?)
        },
        _ =&gt; todo!(),
    };

    Ok(result)
}
</code></pre>
<p>If we try to run this code, there will actually be an unimplemented / todo panic earlier on in the code. Our parser actually stores random expressions like an assignment inside of a statement, so we need to tell <code>compile_statement()</code> to send our expression statements through the <code>compile_expression()</code> function.</p>
<pre><code class="language-rust">fn compile_statement(statement: &amp;Statement, source: &amp;mut String) -&gt; Result&lt;(), CompileError&gt; {
    match statement {
        // ...
        Statement::Expression { expr } =&gt; {
            source.push_str(&amp;compile_expression(expr)?);
        },
        _ =&gt; todo!(),
    };

    Ok(())
}
</code></pre>
<p>The next thing to do is add a new <code>Int</code> type to the <code>PhpValue</code> enumeration and compile integer expressions. This is so we can eventually call the <code>rand()</code> function.</p>
<pre><code class="language-rust">fn compile_expression(expression: &amp;Expression) -&gt; Result&lt;String, CompileError&gt; {
    let result = match expression {
        // ...
        Expression::Int(i) =&gt; format!(&quot;PhpValue::from({})&quot;, i),
        _ =&gt; todo!(),
    };

    Ok(result)
}
</code></pre>
<p>And updating our <code>PhpValue</code> enumeration to support creation from an <code>i64</code>.</p>
<pre><code class="language-rust">enum PhpValue {
    String(String),
    Int(i64),
}

impl From&lt;i64&gt; for PhpValue {
    fn from(value: i64) -&gt; Self {
        Self::Int(value)
    }
}
</code></pre>
<p>Let's write some native PHP functions in Rust. We'll start with <code>readline()</code>.</p>
<p>This function accepts an optional string which will be printed before asking for user input. We'll make this argument required for now since our compiler doesn't know how to handle optional arguments just yet.</p>
<pre><code class="language-rust">pub fn readline(prompt: PhpValue) -&gt; PhpValue {
    print!(&quot;{}&quot;, prompt);

    std::io::stdout().flush().unwrap();

    let mut result = String::new();
    std::io::stdin().lock().read_line(&amp;mut result).unwrap();

    PhpValue::from(result.trim_end())
}
</code></pre>
<p>We flush <code>stdout()</code> so that any previous <code>print!()</code> calls reach the terminal before we lock it for input. We then read in a line of text from the terminal and store it inside of the <code>result</code> variable.</p>
<p>Rust's <code>read_line()</code> method will also include the <code>\n</code> character at the end of the string so using a <code>.trim_end()</code> call will tidy that up.</p>
<p>Time for the <code>rand()</code> function. This is going to require a third-party crate since I don't particularly want to write my own PRNG. We'll be using the defacto <code>rand</code> crate.</p>
<pre><code class="language-rust">use rand::Rng;

fn rand(from: PhpValue, to: PhpValue) -&gt; PhpValue {
    let from: i64 = from.into();
    let to: i64 = to.into();

    let mut rng = rand::thread_rng();

    PhpValue::from(rng.gen_range(from..to))
}
</code></pre>
<p>For type conversions between native Rust types and <code>PhpValue</code>, we'll start to implement <code>Into&lt;T&gt;</code> traits. Rust will call the appropriate method based on the inferred type or provided type of the target, in this case the <code>from</code> and <code>to</code> values are both <code>i64</code> so it will call the <code>Into&lt;i64&gt;</code> method.</p>
<pre><code class="language-rust">impl Into&lt;i64&gt; for PhpValue {
    fn into(self) -&gt; i64 {
        match self {
            Self::Int(i) =&gt; i,
            _ =&gt; todo!(),
        }
    }
}
</code></pre>
<h2>Compiling <code>if</code> statements</h2>
<p>This might sound a complex task but since we're compiling from one language to another, we can actually take advantage of Rust's own conditional statements. We'll just be translating one syntax to another.</p>
<p>Updating <code>compile_statement()</code> to support conditionals is quite simple:</p>
<pre><code class="language-rust">fn compile_statement(statement: &amp;Statement, source: &amp;mut String) -&gt; Result&lt;(), CompileError&gt; {
    match statement {
        // ...
        Statement::If { condition, then, else_ifs, r#else } =&gt; {
            source.push_str(&quot;if &quot;);
            source.push_str(&amp;compile_expression(condition)?);
            source.push('{');

            for statement in then {
                compile_statement(statement, source)?;
            }

            source.push('}');

            if let Some(r#else) = r#else {
                source.push_str(&quot;else {&quot;);
                for statement in r#else {
                    compile_statement(statement, source)?;
                }
                source.push('}');
            }
        },
        _ =&gt; todo!(),
    };

    Ok(())
}
</code></pre>
<p>It doesn't support any <code>elseif</code> conditions at the moment since those don't exist in our sample code. For now it compiles the initial <code>if</code> statement and checks to see if there is a valid <code>else</code> statement at the end. If there is it compiles that too.</p>
<p>We'll also need to support equality checks inside of <code>compile_expression()</code>. There's a couple of ways to do this.</p>
<ol>
<li>Manually implement <code>PartialEq</code> on the <code>PhpValue</code> enumeration and perform the equality comparisons there.</li>
<li>Write our own <code>.eq()</code> and <code>.identical()</code> methods since PHP has some type juggling rules that would be easier to implement here.</li>
</ol>
<p>I'm going to go with option 2 here since I think there will be more long-term flexibility when compared to Rust's own <code>PartialEq</code> trait. Right now the compiler only needs to know about loose comparisons so we'll only implement the <code>eq()</code> method.</p>
<pre><code class="language-rust">impl PhpValue {
    pub fn eq(&amp;self, other: Self) -&gt; bool {
        match (self, &amp;other) {
            (Self::Int(a), Self::String(b)) | (Self::String(b), Self::Int(a)) =&gt; match b.parse::&lt;i64&gt;() {
                Ok(b) =&gt; *a == b,
                _ =&gt; false,
            },
            _ =&gt; todo!(),
        }
    }
}
</code></pre>
<p>The result of <code>readline()</code> should be a string so the compiler only needs to support loose comparisons between <code>Int</code> and <code>String</code> right now. Rust doesn't let you do this natively so the first step is to try and parse an <code>i64</code> from the given <code>String</code>.</p>
<p>If that is successful, the result of the function will be an equality check between the <code>a</code> and <code>b</code>. If it fails it means the <code>String</code> couldn't be converted into an <code>i64</code> and it's impossible for the values to be equal.</p>
<p>Now for the expression compilation itself.</p>
<pre><code class="language-rust">fn compile_expression(expression: &amp;Expression) -&gt; Result&lt;String, CompileError&gt; {
    let result = match expression {
        // ...
        Expression::Infix(lhs, op, rhs) =&gt; {
            let lhs = compile_expression(lhs)?;
            let rhs = compile_expression(rhs)?;

            match op {
                InfixOp::Equals =&gt; format!(&quot;{}.eq({})&quot;, lhs, rhs),
                _ =&gt; todo!(),
            }
        },
        Expression::Variable(var) =&gt; var.to_string(),
        _ =&gt; todo!(),
    };

    Ok(result)
}
</code></pre>
<p>The compiler didn't know how to handle variables either so that has been added too.</p>
<p>The last type of expression the compiler needs to understand is string concatenation. This is another type of infix operation so it's a case of adding another pattern to the <code>match</code> expression.</p>
<pre><code class="language-rust">fn compile_expression(expression: &amp;Expression) -&gt; Result&lt;String, CompileError&gt; {
    let result = match expression {
        // ...
        Expression::Infix(lhs, op, rhs) =&gt; {
            let lhs = compile_expression(lhs)?;
            let rhs = compile_expression(rhs)?;

            match op {
                InfixOp::Equals =&gt; format!(&quot;{}.eq({})&quot;, lhs, rhs),
                InfixOp::Concat =&gt; format!(&quot;_php_concat({}, {})&quot;, lhs, rhs),
                _ =&gt; todo!(),
            }
        },
        // ...
        _ =&gt; todo!(),
    };

    Ok(result)
}
</code></pre>
<p>Instead of mutating existing <code>PhpValue</code> values the runtime will create an entirely new one from 2 separate <code>PhpValue</code> arguments. This function needs to be written in the <code>runtime.rs</code> file alongside our <code>_php_echo()</code> function.</p>
<pre><code class="language-rust">fn _php_concat(left: PhpValue, right: PhpValue) -&gt; PhpValue {
    format!(&quot;{}{}&quot;, left, right).into()
}
</code></pre>
<p>In the previous post we implemented the <code>Display</code> trait for <code>PhpValue</code> which allows us to natively use the enumerations inside of Rust's first-party formatting macros such as <code>format!()</code>, <code>print!()</code> and <code>println!()</code>.</p>
<p>With all of that done, it's time to compile the file! And it doesn't work.</p>
<h2>Using dependencies</h2>
<p>If you haven't read the first blog post, the way this compiler works is by essentially concatenating the compiled PHP code with a <code>runtime.rs</code> file which is written inside of the <code>phpc</code> crate. That file is then stored inside of a temporary directory and compiled using <code>rustc</code> directly.</p>
<p>The problem with this approach is that we can't use any external dependencies inside of the <code>runtime.rs</code> file because they're not going to be linked against during compilation.</p>
<p>One potential solution to this problem is generating a static object file for the runtime and linking against that when compiling the PHP code. As the dependency list grows though the number of libraries that would need to be compiled would grow quite quickly.</p>
<p>I'm instead going to go down the route of ditching <code>rustc</code> and using <code>cargo</code> to build the project instead. The benefit here is that we can let <code>cargo</code> do all of the heavy lifting instead and run away from the <code>rustc</code> API.</p>
<p>I won't go over each step individually but will just paste the new <code>main</code> function code here.</p>
<pre><code class="language-rust">fn main() {
    let args = Args::from_args();

    println!(&quot;&gt; Compiling PHP script...&quot;);

    let compiled = compile(args.file.clone()).unwrap();

    let path = std::path::Path::new(&amp;args.file);
    let file_stem = path.file_stem().unwrap().to_str().unwrap();
    
    let temp_dir = std::env::temp_dir();
    let temp_path = format!(&quot;{}{}&quot;, temp_dir.to_str().unwrap(), Uuid::new_v4());

    println!(&quot;&gt; Initialising Cargo project in {}...&quot;, &amp;temp_path);

    std::fs::create_dir(&amp;temp_path).unwrap();

    let mut cmd = Command::new(&quot;cargo&quot;);
    cmd.args([&quot;init&quot;, &quot;.&quot;, &quot;--name&quot;, &amp;file_stem])
        .current_dir(&amp;temp_path);

    match cmd.output() {
        Ok(o) =&gt; {
            print!(&quot;{}&quot;, String::from_utf8_lossy(&amp;o.stdout));
        },
        Err(e) =&gt; {
            eprintln!(&quot;Failed to generate Cargo project. Error: {:?}&quot;, e);
            exit(1);
        },
    };

    let cargo_stub = include_str!(&quot;../../phpc_runtime/Cargo.toml&quot;).replace(&quot;phpc_runtime&quot;, file_stem);

    println!(&quot;&gt; Modifying Cargo configuration...&quot;);

    match std::fs::write(format!(&quot;{}/Cargo.toml&quot;, &amp;temp_path), cargo_stub) {
        Ok(_) =&gt; {},
        Err(e) =&gt; {
            eprintln!(&quot;Failed to modify Cargo configuration. Error: {:?}&quot;, e);
            exit(1);
        },
    };

    let runtime_stub = include_str!(&quot;../../phpc_runtime/src/lib.rs&quot;);
    
    println!(&quot;&gt; Writing runtime module...&quot;);

    match std::fs::write(format!(&quot;{}/src/runtime.rs&quot;, &amp;temp_path), runtime_stub) {
        Ok(_) =&gt; {},
        Err(e) =&gt; {
            eprintln!(&quot;Failed to write runtime library. Error: {:?}&quot;, e);
            exit(1);
        }
    };

    println!(&quot;&gt; Writing compiled PHP code...&quot;);

    match std::fs::write(format!(&quot;{}/src/main.rs&quot;, &amp;temp_path), compiled) {
        Ok(_) =&gt; {},
        Err(e) =&gt; {
            eprintln!(&quot;Failed to write compiled PHP code. Error: {:?}&quot;, e);
            exit(1);
        },
    };

    println!(&quot;&gt; Compiling project with Cargo...&quot;);

    let mut cmd = Command::new(&quot;cargo&quot;);
    cmd.args([&quot;build&quot;, &quot;--release&quot;])
        .current_dir(&amp;temp_path);

    match cmd.output() {
        Ok(o) =&gt; {
            if o.status.success() {
                print!(&quot;{}&quot;, String::from_utf8_lossy(&amp;o.stdout));
            } else {
                print!(&quot;{}&quot;, String::from_utf8_lossy(&amp;o.stderr));
            }
        },
        Err(e) =&gt; {
            eprintln!(&quot;Failed to compile project with Cargo. Error: {:?}&quot;, e);
            exit(1);
        },
    };
}
</code></pre>
<p>The error handling of commands could be a lot tidier if there was a wrapper around the <code>Command</code> API, but this will do for now. The <code>Cargo.toml</code> file for the PHP project is taken from a new <code>phpc_runtime</code> crate and modified slightly.</p>
<p>Dependencies are now compiled into our project correctly, but there's still a problem. The compiled Rust code isn't memory safe!</p>
<p>The problematic code is coming from our equality expression. We're moving the value out of the current block into the <code>.eq()</code> function which means we can no longer reference it in the main flow of execution. A hacky fix is just to clone the value before we send it through, that way the original value isn't actually being used and a freshly allocated one is instead.</p>
<pre><code class="language-rust">fn compile_expression(expression: &amp;Expression) -&gt; Result&lt;String, CompileError&gt; {
    let result = match expression {
        // ...
        Expression::Infix(lhs, op, rhs) =&gt; {
            let lhs = compile_expression(lhs)?;
            let rhs = compile_expression(rhs)?;

            match op {
                InfixOp::Equals =&gt; format!(&quot;{}.eq(({}).clone())&quot;, lhs, rhs),
                InfixOp::Concat =&gt; format!(&quot;_php_concat({}, {})&quot;, lhs, rhs),
                _ =&gt; todo!(),
            }
        },
        // ...
        _ =&gt; todo!(),
    };

    Ok(result)
}
</code></pre>
<blockquote>
<p>A better way of doing this is probably with a smart pointer or even a garbage collector. Since we're still prototyping this code a <code>.clone()</code> is fine and won't hurt anybody.</p>
</blockquote>
<p>The project successfully compiles but the executable hasn't been moved into the current working directory. A bit of extra logic at the end of the <code>main()</code> function should sort this.</p>
<pre><code class="language-rust">fn main() {
    // ...

    let executable_path = format!(&quot;{}/target/release/{}&quot;, &amp;temp_path, &amp;file_stem);

    match std::fs::copy(executable_path, format!(&quot;./{}&quot;, &amp;file_stem)) {
        Ok(_) =&gt; {
            println!(&quot;&gt; Executable copied.&quot;);
        },
        Err(e) =&gt; {
            eprintln!(&quot;Failed to copy executable file. Error: {:?}&quot;, e);
            exit(1);
        },
    };
}
</code></pre>
<p>Compiling the project now will create a new <code>guess-a-number</code> file in the current directory. Executing that file and trying to guess a number results in this:</p>
<pre><code class="language-sh">$ ~ ./guess-a-number
Guess a number between 1 and 3: 1
You guessed the number correctly, well done!%
</code></pre>
<p>Here's a list of the things that accomplished:</p>
<ul>
<li>Compile variable assignments.</li>
<li>Write a native PHP function in Rust.</li>
<li>Compile <code>if</code> and <code>else</code> statements.</li>
<li>Migrate project compilation to Cargo to allow use of external crates.</li>
</ul>
<p>All in all this was a pretty successful article. Again, if you made it to the end then thank you.</p>
<p>Until next time.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 01 Aug 2022 00:00:00 +0000</pubDate>
                                    <category>Programming Languages</category>
                            </item>
                    <item>
                <title><![CDATA[Experimentally compiling PHP code to Rust]]></title>
                <link>https://ryangjchandler.co.uk/posts/experimentally-compiling-php-code-to-rust</link>
                <description><![CDATA[<h2>Preface</h2>
<p>Some of you might already know that I've been working on a handwritten PHP parser in Rust. The project is called <a href="https://github.com/ryangjchandler/trunk">Trunk (source code on GitHub)</a>.</p>
<p>I've been working on the parser for a couple of weeks at the time of writing this blog post and it's already come a long way. It's able to parse functions, classes, interfaces and much more. It's still miles from being a compliant PHP parser comparable to Nikita's <code>nikic/php-parser</code> package, but the journey has been fun so far and it's amazing how many weird things you can find out about a language by parsing its grammar.</p>
<p>Since the parser is now able to handle some basic programs, I thought it would be worthwhile taking it for a spin to see what the API is like and to look for improvements. Dogfooding, if you want a single word.</p>
<p>My original plan was to work on an experimental runtime and interpreter for the language. That's quite a huge undertaking and there would be very little benefit to a new runtime at this point in time.</p>
<p>Instead I started to think about a compiler for PHP. Something that runs ahead of execution time (AOT). My friend <a href="https://twitter.com/timmrgn">Tim Morgan</a> is the creator of <a href="https://github.com/natalie-lang/natalie">Natalie</a>, an implementation of the Ruby language that compiles to C++ and then compiles into a native binary. I've contributed to Natalie a little over the last year or so and it's truly inspiring the work that Tim is doing.</p>
<p>You can probably see where this is going...</p>
<h2>The idea</h2>
<p>Inspired by Tim's work on Natalie, I'm going to start an experiment where I take my handwritten PHP parser and try to write a compiler that turns PHP code into Rust and then compiles that Rust code into a native executable using <code>rustc</code>.</p>
<p>Let's look at a simple example:</p>
<pre><code class="language-php">function get_name() {
    return &quot;Ryan&quot;;
}

echo get_name();
</code></pre>
<p>A PHP script like this would eventually compile into some Rust code that looks something like this:</p>
<pre><code class="language-rust">fn get_name() -&gt; PhpResult&lt;PhpValue&gt; {
    return Ok(PhpValue::from(&quot;Ryan&quot;));
}

fn main() -&gt; PhpResult&lt;()&gt;  {
    _php_echo(get_name()?);
}
</code></pre>
<p>That Rust code could then be stored somewhere and compiled using the Rust compiler, <code>rustc</code>.</p>
<p>No more boring introductions. Let's look at some code.</p>
<blockquote>
<p><strong>Disclaimer</strong>: The following code is incredibly naive and purely for prototyping purposes. There's plenty of rough edges that will need to be ironed out before calling this a &quot;good idea&quot; or &quot;achievable project&quot;.</p>
</blockquote>
<h2>Parsing the code</h2>
<p>I've already got a parser that is capable of understanding the PHP code above. The API is pretty simple, so I decided to just build a small CLI that would accept a file path and send it through the parser to obtain an abstract syntax tree (AST). I'm using the excellent <code>structopt</code> crate here for argument parsing.</p>
<pre><code class="language-rust">use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = &quot;phpc&quot;, about = &quot;Compile a PHP script to Rust.&quot;)]
struct Args {
    file: String,
}

fn main() {
    let args = Args::from_args();
}
</code></pre>
<p>This is all written inside of a <code>main.rs</code> file. I prefer to separate the CLI interface code from the actual logic of the program, so the below code is written inside of <code>lib.rs</code> inside of the same folder.</p>
<pre><code class="language-rust">use trunk_lexer::Lexer;
use trunk_parser::Parser;

pub fn compile(file: String) -&gt; Result&lt;String, CompileError&gt; {
    let contents = match std::fs::read_to_string(file) {
        Ok(contents) =&gt; contents,
        Err(_) =&gt; return Err(CompileError::FailedToReadFile),
    };

    let mut lexer = Lexer::new(None);
    let tokens = lexer.tokenize(&amp;contents).unwrap();

    let mut parser = Parser::new(tokens);
    let ast = parser.parse().unwrap();

    Ok(String::new())
}

#[derive(Debug)]
pub enum CompileError {
    FailedToReadFile,
}
</code></pre>
<p>The code takes in a file path and gets a list of tokens using the <code>Lexer</code> structure. The tokens are then sent through the parser to retrieve the AST.</p>
<blockquote>
<p>The usage of <code>unwrap()</code> isn't great because the program will just panic. A good refactoring opportunity here would be transforming any errors returned from the lexer and parser into <code>CompileError</code> values instead.</p>
</blockquote>
<p>This function can now be called from <code>main.rs</code>.</p>
<pre><code class="language-rust">use structopt::StructOpt;
use phpc::compile;

#[derive(Debug, Structopt)]
#[structopt(name = &quot;phpc&quot;, about = &quot;Compile a PHP script to Rust.&quot;)]
struct Args {
    file: String,
}

fn main() {
    let args = Args::from_args();
    let compiled = compile(args.file);

    dbg!(compiled);
}
</code></pre>
<h2>The <code>main</code> conundrum</h2>
<p>PHP is a procedural programming language. It's really a scripting language. As such, it doesn't enforce the usage of a <code>main()</code> function. The same can be seen in other languages like JavaScript and Python.</p>
<p>Rust on the otherhand requires you to define an <code>fn main()</code> somewhere so that the binary knows where to start executing your code. The example PHP code shown further up in this blog post has a single function definition and then an arbitrary statement outside of any known structure.</p>
<p>Think of those arbitrary statements as parts inside of the pseudo <code>main()</code> function. The best way to force this structure is by segmenting and partitioning the AST into 2 separate smallers ASTs.</p>
<p>The first will contain any function definitions (for now) and the other will contain all of the rogue statements. That way all of the function definitions can be compiled first and the rest can be compiled inside of an <code>fn main()</code> to keep Rust happy.</p>
<pre><code class="language-rust">use trunk_parser::{Parser, Statement};

pub fn compile(file: String) -&gt; Result&lt;String, CompileError&gt; {
    // ...

    let mut parser = Parser::new(tokens);
    let ast = parser.parse().unwrap();

    let (fns, main): (Vec&lt;_&gt;, Vec&lt;_&gt;) = ast.iter().partition(|statement| match statement {
        Statement::Function { .. } =&gt; true,
        _ =&gt; false,
    });

    // ...
}
</code></pre>
<p>The <code>partition()</code> method returns a tuple containing 2 new ASTs. Rust needs some helper understanding the types - the fancy <code>Vec&lt;_&gt;</code> syntax just tells the typechecker that the generic type inside of <code>Vec&lt;T&gt;</code> is the same as the type inside of the iterator itself (call it a placeholder).</p>
<p>Now it's time for some string building!</p>
<h2>Bare minimal compilation</h2>
<p>Compiling our AST into Rust code is just a case of looping over all of the statements and concatenating a bunch of strings. Famous last words, lol.</p>
<p>Let's start with a <code>compile_function()</code> method that accepts a <code>Statement</code> and <code>&amp;mut String</code>.</p>
<pre><code class="language-rust">fn compile_function(function: &amp;Statement, source: &amp;mut String) -&gt; Result&lt;(), CompileError&gt; {
    let (name, params, body) = match function {
        Statement::Function { name, params, body, .. } =&gt; (name, params, body),
        _ =&gt; unreachable!(),
    };

    source.push_str(&quot;fn &quot;);
    source.push_str(&amp;name.name);
    source.push('(');

    for param in params {
        source.push_str(match &amp;param.name {
            Expression::Variable(n) =&gt; &amp;n,
            _ =&gt; unreachable!(),
        });
        source.push_str(&quot;: PhpValue, &quot;);
    }

    source.push_str(&quot;) -&gt; PhpValue {&quot;);

    for statement in body {
        compile_statement(statement, source)?;
    }

    source.push('}');

    Ok(())
}
</code></pre>
<p>This function is going to extract some values from the <code>Statement</code> and return a tuple that we can unpack. There's some boilerplate code to output the <code>fn</code> keyword along with its name.</p>
<p>The function then needs a list of parameters. We don't really care about parameter types right now because all of our values are going to be represented by a single <code>PhpValue</code> type in the Rust code anyway.</p>
<p>It also needs a return type which will also be a <code>PhpValue</code>. It's then just a case of looping over all of the statements inside of the function and compiling those before closing off the function itself.</p>
<p>Pretty simple so far... let's implement a minimal <code>compile_statement()</code> function too.</p>
<pre><code class="language-rust">fn compile_statement(statement: &amp;Statement, source: &amp;mut String) -&gt; Result&lt;(), CompileError&gt; {
    match statement {
        Statement::Return { value } =&gt; {
            source.push_str(&quot;return&quot;);
            if let Some(value) = value {
                source.push(' ');
                source.push_str(&amp;compile_expression(value)?);
            } else {
                todo!();
            }
            source.push(';');
        },
        _ =&gt; todo!(),
    };

    Ok(())
}
</code></pre>
<p>Our example <code>get_name()</code> function only contains a <code>return</code> statement so we'll just implement that for now. It's more string building here, with the addition of a new <code>compile_expression()</code> function too.</p>
<p>You might notice that we're actually pushing the result of <code>compile_expression()</code> onto the string instead of passing through a mutable reference to <code>source</code>. This is important since we might want to compile an expression arbitrarily without modifying the source code.</p>
<p>We've got another function to write so let's do that real quick.</p>
<pre><code class="language-rust">fn compile_expression(expression: &amp;Expression) -&gt; Result&lt;String, CompileError&gt; {
    let result = match expression {
        Expression::ConstantString(value) =&gt; {
            format!(r#&quot;PhpValue::from(&quot;{}&quot;)&quot;#, value)
        }
        _ =&gt; todo!(),
    };

    Ok(result)
}
</code></pre>
<p>Still implementing the bare minimum here. The <code>get_name()</code> function returns a constant string which will be able to directly convert into a <code>PhpValue</code> type with some traits later on. The <code>format!()</code> macro returns a <code>String</code> so we can just keep it simple and avoid any temporary variables.</p>
<p>Time to wire it all up inside of the <code>compile()</code> function.</p>
<pre><code class="language-rust">fn compile(file: String) -&gt; Result&lt;String, CompileError&gt; {
    // ...

    let mut source = String::new();

    for function in fns {
        compile_function(function, &amp;mut source)?;
    }

    Ok(source)
}
</code></pre>
<p>Create an empty <code>String</code>, loop through the function statements, compile them, return the generated source code.</p>
<p>Running the example code through the program now will dump the generated Rust code into the terminal. It looks like this:</p>
<pre><code class="language-sh">cargo run --bin phpc -- ./phpc/samples/blog.php
</code></pre>
<pre><code>[phpc/src/main.rs:14] compiled = Ok(
    &quot;fn get_name() -&gt; PhpValue {return PhpValue::from(\&quot;Ryan\&quot;);}&quot;,
)
</code></pre>
<p>Our function has been generated with a rather ugly return statement inside! Visible progress - love it. Time to get the <code>main()</code> function.</p>
<h2>Compiling the entrypoint</h2>
<p>Before looping through the main statements, we need to add the boilerplate code. This can all go inside of the <code>compile()</code> function for now.</p>
<pre><code class="language-rust">pub fn compile(file: String) -&gt; Result&lt;String, CompileError&gt; {
    // ...

    source.push_str(&quot;fn main() {&quot;);

    for statement in main {
        compile_statement(statement, &amp;mut source)?;
    }

    source.push('}');

    Ok(source)
}
</code></pre>
<p>Running this code will cause some panics since we've not implemented all of our statements. We need to add in support for <code>echo</code>.</p>
<pre><code class="language-rust">fn compile_statement(statement: &amp;Statement, source: &amp;mut String) -&gt; Result&lt;(), CompileError&gt; {
    match statement {
        // ...
        Statement::Echo { values } =&gt; {
            for value in values {
                source.push_str(&quot;_php_echo(&quot;);
                source.push_str(&amp;compile_expression(value)?);
                source.push_str(&quot;);&quot;);
            }
        },
        _ =&gt; todo!(),
    };

    Ok(())
}
</code></pre>
<p>Trying to compile the example code again triggers another panic, this time it's the new call to <code>compile_expression()</code>. The compiler doesn't know how to generate Rust code for calling PHP functions.</p>
<pre><code class="language-rust">fn compile_expression(expression: &amp;Expression) -&gt; Result&lt;String, CompileError&gt; {
    let result = match expression {
        // ...
        Expression::Call(target, args) =&gt; {
            let mut buffer = String::new();

            buffer.push_str(&amp;compile_expression(target)?);
            buffer.push('(');

            for arg in args {
                buffer.push_str(&amp;compile_expression(arg)?);
                buffer.push_str(&quot;, &quot;);
            }

            buffer.push(')');
            buffer
        },
        Expression::Identifier(i) =&gt; i.to_string(),
        _ =&gt; todo!(),
    };

    Ok(result)
}
</code></pre>
<p>The code above should be pretty self-explanatory at this point. A <code>Call</code> expression has a target and list of arguments. The target is also an <code>Expression</code> so needs to be compiled, as well as the arguments.</p>
<p>In the example script, the target is just an identifier so the function needs to know how to compile that as well. Luckily it just needs to output the name of the identifer as a literal string. The <code>.to_string()</code> method call is required to generate a non-referential string.</p>
<p>Running the example script through the compiler one more time generates the following Rust code.</p>
<pre><code class="language-sh">cargo run --bin phpc -- ./phpc/samples/blog.php
</code></pre>
<pre><code>[phpc/src/main.rs:14] compiled = Ok(
    &quot;fn get_name() -&gt; PhpValue {return PhpValue::from(\&quot;Ryan\&quot;);}fn main() {_php_echo(get_name());}&quot;,
)
</code></pre>
<p>A little harder to read now but the <code>main()</code> function exists and has the expected code inside of it. Woop woop!</p>
<h2>The runtime</h2>
<p>The compiler is pretty smart now. It can take an incredibly complex PHP script and generate valid Rust code. Or can it?</p>
<p>The answer is of course <strong>no</strong>. The Rust code is referencing a weird <code>PhpValue</code> type that doesn't actually exist in the generated code. There are a few potential ways to solve this but I'm going to go with the simplest and fastest way - a &quot;runtime&quot; file.</p>
<p>This runtime file will contain all of the code needed to actually run PHP code. It's going to be house the <code>PhpValue</code> type as well as any internal functions that handle PHP concepts, such as <code>_php_echo()</code>.</p>
<p>Rust makes this really simple as well with the <code>include_str!()</code> macro. This macro is evaluated at compile time and takes in a file path. The contents of that file are then embedded into the program and can be assigned to a variable.</p>
<p>Adding that code into the <code>compile()</code> function looks like this:</p>
<pre><code class="language-rust">pub fn compile(file: String) -&gt; Result&lt;String, CompileError&gt; {
    // ...

    let mut source = String::new();
    source.push_str(include_str!(&quot;./runtime.rs&quot;));

    // ...

    Ok(source)
}
</code></pre>
<p>The top of the generated code will now include everything inside of the <code>runtime.rs</code> file.</p>
<p>This file can now house the runtime information such as <code>PhpValue</code> and <code>_php_echo()</code>.</p>
<pre><code class="language-rust">use std::fmt::Display;

enum PhpValue {
    String(String),
}

impl From&lt;&amp;str&gt; for PhpValue {
    fn from(value: &amp;str) -&gt; Self {
        Self::String(value.into())
    }
}

impl Display for PhpValue {
    fn fmt(&amp;self, f: &amp;mut std::fmt::Formatter&lt;'_&gt;) -&gt; std::fmt::Result {
        match self {
            Self::String(string) =&gt; write!(f, &quot;{}&quot;, string),
            _ =&gt; todo!(),
        }
    }
}

fn _php_echo(value: PhpValue) {
    print!(&quot;{value}&quot;);
}
</code></pre>
<p>The only type of PHP value that the example script uses is a <code>string</code>, so the <code>PhpValue</code> can just have a single variant.</p>
<p>I want the <code>PhpValue</code> type to be smart and understand conversions from native Rust types. That's where the generic <code>From</code> trait comes in. It tells the Rust compiler how to convert a <code>&amp;str</code> into a <code>PhpValue</code>.</p>
<p><code>PhpValue</code> also implements the <code>Display</code> trait which will allow the struct to be formatted with Rust's first party macros such as <code>write!()</code>, <code>print!()</code> and <code>println!()</code>. An added bonus of implementing <code>Display</code> is that you get a <code>.to_string()</code> method on the implementor for free.</p>
<p>The <code>_php_echo()</code> function takes in a value and just prints it out using <code>print!()</code>.</p>
<h2>Compiling with <code>rustc</code></h2>
<p>The compiler has just about everything it needs to compile the example PHP script. The last step is teaching the CLI how to take the compiled code and write it to disk and then send that file through Rust's compiler, <code>rustc</code>.</p>
<pre><code class="language-rust">fn main() {
    let args = Args::from_args();
    let compiled = compile(args.file.clone()).unwrap();

    let path = std::path::Path::new(&amp;args.file);
    let temp = std::env::temp_dir();
    let file_stem = path.file_stem().unwrap().to_str().unwrap();
    let file_path = format!(&quot;{}{}.rs&quot;, temp.to_str().unwrap(), &amp;file_stem);

    std::fs::write(&amp;file_path, compiled).unwrap();

    println!(&quot;Compiled code written to {}...&quot;, &amp;file_path);
    println!(&quot;Generating binary...&quot;);

    std::process::Command::new(&quot;rustc&quot;)
        .args([file_path, &quot;-o&quot;.to_string(), file_stem.to_string()])
        .output()
        .expect(&quot;Failed to compile with rustc&quot;);
}
</code></pre>
<p>The file name is converted into a <code>Path</code> instance. This gives us a handy <code>file_stem()</code> method that returns the file name without the extension. A full file path is then generated using a temporary directory, the file name and <code>.rs</code> file extension.</p>
<p>All of the compiled code is then written to that temporary file path and printed in the terminal for debugging purposes.</p>
<p>A new <code>Command</code> is then created targeting the global <code>rustc</code> binary. The <code>file_path</code> is provided as the input file and the output is set using the <code>-o</code> flag followed by the name of the binary. For convenience the binary is named after the original input file to the compiler.</p>
<p>The <code>Command</code> then executes and will panic if it fails to read any output. This is pretty poor since even if <code>rustc</code> fails to compile because of bad Rust code, the <code>phpc</code> program will be successful. It'll do for now though.</p>
<h2>The moment you've all been waiting for</h2>
<p>It's time to compile the example script...</p>
<pre><code class="language-sh">cargo run --bin phpc -- ./phpc/samples/blog.php
</code></pre>
<pre><code>Compiled code written to /var/folders/52/3xkzr5_s1zbczrn85z2kqfv40000gn/T/blog.rs...
Generating binary...
</code></pre>
<p>And it works as expected. In the current working directory is a new <code>blog</code> file which can be executed in the terminal.</p>
<pre><code class="language-sh">./blog
</code></pre>
<pre><code>Ryan%
</code></pre>
<p>Absolute sorcery! Four lines of incredibly simple PHP code were parsed with a handwritten parser, compiled into a Rust file with a novel compiler and compiled into a native binary using Rust's own toolchain.</p>
<p>Please, please, please, remember that this is just a prototype and proof of concept right now. I'm most definitely going to continue the development of this alongside the parser, but right now it's still a proof of concept!</p>
<p>There's plenty of hurdles to jump before it becomes remotely useful for anybody. Already my mind is thinking &quot;How will it handle <code>require</code> and <code>include</code>?&quot;, &quot;What about conditionally defining functions?&quot;, &quot;How do you even represent a PHP interface with Rust code!?&quot; and &quot;I forgot about closures...&quot;.</p>
<p>I'm going to continue writing about my journey developing Trunk, no matter the outcome. Regardless of the success with the compiler, the parser work will continue and I'm sure we'll find lots of other interesting projects to experiment with too.</p>
<p>If you made it this far without drifting off and getting some sleep, thank you. If you're interested in viewing the commit that contains all of this code, you can <a href="https://github.com/ryangjchandler/trunk/commit/8d1394bd3d95c310d4a805e3321d2a574b82434b">view it here on GitHub</a>. There are some bits of deleted code in there too from my original attempt at this, ignore that.</p>
<p>Until next time.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 31 Jul 2022 00:00:00 +0000</pubDate>
                                    <category>Programming Languages</category>
                            </item>
                    <item>
                <title><![CDATA[Macros in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/macros-in-laravel</link>
                <description><![CDATA[<p>Laravel's <code>Illuminate\Support\Macroable</code> trait allows you extend classes at runtime with custom methods. The idea is that you provide a named <code>Closure</code>, or <code>callable</code> value, which can then be invoked using PHP's <code>__call()</code> and <code>__callStatic()</code> magic methods.</p>
<p>Let's take a look at an example using a <code>Collection</code>.</p>
<pre><code class="language-php">$collection = collect([
    'foo' =&gt; [
        'bar' =&gt; [
            'baz' =&gt; 'bob',
        ],
    ],
]);

$collection-&gt;get('foo.bar.baz')
</code></pre>
<p>I want this code to take the dot-notated path and return the value. The <code>Collection</code> object doesn't support this though. One solution would be swapping out the <code>Collection::get()</code> call for a <code>data_get()</code> call.</p>
<pre><code class="language-php">$baz = data_get($collection, 'foo.bar.baz');
</code></pre>
<p>That does actually work since the <code>data_get()</code> function has some special logic for <code>Collection</code> objects. From a readability point of view, it's not quite as nice though. The <code>Collection</code> object is known for its fluency and method chaining and this bit of code doesn't fit into that pattern.</p>
<p>Let's add a macro the <code>Collection</code> object that does this logic for us.</p>
<pre><code class="language-php">use Illuminate\Support\Collection;

Collection::macro('path', function (string $path) {
    return data_get($this, $path);
});
</code></pre>
<p>The <code>Macroable::macro()</code> method accepts 2 arguments. The first is the name of the macro and the second is a <code>Closure</code> or <code>callable</code> value.</p>
<p>We can now call a magic <code>path()</code> method on the <code>$collection</code> and it will return the value found at the path provided.</p>
<pre><code class="language-php">$baz = collect([
    // ...
])
    -&gt;path('foo.bar.baz');
</code></pre>
<p>Behind the scenes the method call is being delegated to the <code>__call()</code> method implemented by the <code>Macroable</code> trait. It will check if the macro exists and invoke the callback if it does.</p>
<p>What is special about the callback is that we can use <code>$this</code> and reference the object we're calling the macro on instead of the <code>$this</code> context where the macro is defined.</p>
<p>Inside of the <code>Closure</code>, <code>$this</code> is actually the <code>Collection</code> object that we created. To help our IDE understand the context a little more, we can add a DocBlock at the top of the <code>Closure</code>.</p>
<pre><code class="language-php">Collection::macro('path', function (string $path) {
    /** @var \Illuminate\Support\Collection $this */
    return data_get($this, $path);
});
</code></pre>
<h2>Intellisense</h2>
<p>Since macros are defined at runtime, your IDE likely won't be able to provide any autocomplete or intellisense. I've found the best way to fix this problem is by creating a &quot;stubs&quot; file that has a carcass definition of your macros.</p>
<p>This file has multiple purposes:</p>
<ol>
<li>It lets your IDE and static analysis tools discover the macros your define.</li>
<li>It serves as a single-source of truth for the macros that you define in your project.</li>
</ol>
<p>I typically create a <code>.stubs.php</code> file in the root of my project. The <code>path()</code> macro might be stubbed out like below.</p>
<pre><code class="language-php">&lt;?php

namespace Illuminate\Support
{
    class Collection
    {
        public function path(string $path): mixed {}
    }
}
</code></pre>
<p>If your tooling is able to scan that file, it should add the <code>Collection::path()</code> definition to its indexes and provide some autocomplete for you.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 27 Jun 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Adding "Suggested Posts" to my Laravel blog]]></title>
                <link>https://ryangjchandler.co.uk/posts/adding-suggested-posts-to-my-laravel-blog</link>
                <description><![CDATA[<p>My blog is very, very simple. It's a Laravel app powered by a set of flat Markdown files which can be <a href="https://github.com/ryangjchandler/orbit">interacted with using Eloquent</a>.</p>
<p>I've noticed that the bounce rate on my blog is pretty poor. I don't write a lot of content these days but I have written quite a few posts in the past. My theory is that I'm not suggesting content to people so they're never actually visiting other pages.</p>
<p>I want to try to improve that since the content I've written in the past can easily get lost amongst the latest posts.</p>
<p>Here's my grand plan:</p>
<ul>
<li>Add a field to store keywords on my blog posts</li>
<li>Write a script to fill in keywords based on category and title</li>
<li>Add a <code>keywords</code> field to Filament</li>
<li>Start recommending blog posts based on matching keywords</li>
</ul>
<h2>Storing keywords</h2>
<p>As I mentioned, my blog uses <a href="https://github.com/ryangjchandler/orbit">Orbit</a> to store content in the form of a Markdown file and interact with those files using Eloquent models.</p>
<p>Adding a new <code>keywords</code> field to the <code>Post</code> model is really simple. We just need to update our model's schema.</p>
<pre><code class="language-php">public static function schema(Blueprint $table)
{
    $table-&gt;string('title');
    $table-&gt;string('slug');
    $table-&gt;text('excerpt')-&gt;nullable();
    $table-&gt;text('content')-&gt;nullable();
    $table-&gt;json('keywords')-&gt;nullable();
    $table-&gt;timestamp('published_at')-&gt;nullable();
    $table-&gt;string('category_slug')-&gt;nullable();
}
</code></pre>
<p>We'll also need a cast since we want this to return a PHP <code>array</code>.</p>
<pre><code class="language-php">protected $casts = [
    'published_at' =&gt; 'datetime',
    'keywords' =&gt; 'json',
];
</code></pre>
<p>Now our <code>Post</code> model is able to store keywords inside of the Markdown content files.</p>
<h2>Filling in missing keywords</h2>
<p>All of the posts on my blog are categorised. They <code>belongTo</code> a single <code>Category</code> model.</p>
<p>I'm going to write a command that loops over each <code>Post</code>, checks the <code>Category</code> it belongs to and fills in the <code>keywords</code> field with some standard values.</p>
<p>The command is only going to be run once, so I'm not going to bother with a dedicated <code>Command</code> class. Instead I'll opt for the simpler approach and write all of the logic inside of the <code>routes/console.php</code> file.</p>
<p>We need to grab all of the posts on the site.</p>
<pre><code class="language-php">Artisan::command('script:fill-missing-keywords', function () {
    $posts = Post::all();

    // ...
});
</code></pre>
<p>The only thing left to do is loop over each of the posts and update the keywords accordingly.</p>
<pre><code class="language-php">Artisan::command('script:fill-missing-keywords', function () {
    $posts = Post::all();

    $posts-&gt;each(function (Post $post) {
        $post-&gt;update([
            'keywords' =&gt; match ($post-&gt;category?-&gt;slug) {
                'alpinejs' =&gt; ['alpine', 'alpinejs', 'frontend', 'javascript', 'js'],
                'css' =&gt; ['css', 'style', 'styling', 'tailwind'],
                'github-actions' =&gt; ['actions', 'ci', 'cd', 'github'],
                'insights' =&gt; ['insights'],
                'javascript' =&gt; ['javascript', 'js', 'alpine', 'alpinejs'],
                'laravel' =&gt; ['php', 'laravel', 'laravelphp', 'blade', 'model', 'eloquent'],
                'livewire' =&gt; ['livewire', 'laravel', 'php', 'reactive', 'ssr', 'wire'],
                'php' =&gt; ['php', 'server', 'laravel', 'programming'],
                'programming-languages' =&gt; ['pl', 'plt', 'programming-language', 'programming'],
                'tailwind-css' =&gt; ['css', 'style', 'tailwind', 'tailwindcss'],
                'tips-tricks' =&gt; ['tips', 'tricks', 'tips-tricks', 'php', 'livewire',],
                'tooling' =&gt; ['tooling', 'tips'],
                default =&gt; [],
            }
        ]);
    });
});
</code></pre>
<p>Each <code>Category</code> has a <code>slug</code> column. Matching against that we can set the value of <code>keywords</code> to some array of strings. This could run a little faster if we eager-load the <code>category</code> relationship but it's a one-time script so I'm not too bothered.</p>
<p>Running this command will update the Markdown files. Progress!</p>
<h2>Setting keywords from Filament</h2>
<p>I normally write my content in Markdown files directly but sometimes I need to fix typos. It's quicker for me to do that through an admin panel so I use <a href="https://filamentphp.com/">Filament</a>.</p>
<p>To update keywords from Filament, we just need to add a new field to the <code>PostResource</code>. I'm going to use a <code>TagsInput</code> field that accepts a list of strings.</p>
<pre><code class="language-php">public static function form(Form $form): Form
{
    return $form
        -&gt;schema([
            Card::make([
                // ...
                TagsInput::make('keywords')
                    -&gt;columnSpan(2)
                    -&gt;nullable(),
                // ...
            ])
                -&gt;columns(2)
        ]);
}
</code></pre>
<!-- Add image here. -->
<h2>Finding related posts</h2>
<p>With all of that in place, we can finally write the method to find related posts. I'm going to do this in a method on the <code>Post</code> model directly.</p>
<p>Before you look at the code, it's worth mentioning that Orbit uses an SQLite database under-the-hood to proxy the flat content files between the filesystem and Eloquent. This is a trick that was first introduced by <a href="https://twitter.com/calebporzio">Caleb Porzio</a> with <a href="https://github.com/calebporzio/sushi">Sushi</a>.</p>
<pre><code class="language-php">public function relatedPosts(): Collection
{
    return static::query()
        -&gt;select('posts.*')
        -&gt;fromRaw('posts, json_each(posts.keywords)')
        -&gt;where($this-&gt;getKeyName(), '!=', $this-&gt;getKey())
        -&gt;whereIn(DB::raw('json_each.value'), $this-&gt;keywords)
        -&gt;distinct()
        -&gt;get();
}
</code></pre>
<p>There's a little bit of SQLite wizardry going on here. If this were a MySQL query you could run a <code>JSON_CONTAINS()</code> check on the <code>keywords</code> column and check if the array of keywords contains any matching values.</p>
<p>Sadly SQLite doesn't have the same level of JSON support as MySQL and Postgres. To work around this, we instead need to use the <code>json_each()</code> function.</p>
<p>The <code>json_each()</code> function will produce a separate row in the query result for each value found in the JSON column. If a row in the <code>posts</code> table contains 7 keywords, that row will be returned 7 times each with the respective keyword. The string from the JSON column will get put into a kind of virtual table for that query called <code>json_each</code> so we can run comparison checks on the <code>json_each.value</code> column.</p>
<p>I couldn't find a method to add the <code>json_each</code> call natively in Laravel so I went with a <code>fromRaw()</code> call that adds in the <code>posts</code> table and the <code>json_each</code> call.</p>
<p>We also want to exclude the current post to make sure we're not suggesting the same post the visitor is currently reading.</p>
<p>Some of you might be questioning the choice to use an Eloquent query here instead of a plain <code>DB</code> query. Using an <code>Eloquent</code> query will ensure that the query results are still transformed into <code>Post</code> model instances.</p>
<h2>Outputting related posts</h2>
<p>The <code>Post::relatedPosts()</code> method can now be used inside of our Blade template to output a couple suggestions at the very end of the blog post.</p>
<pre><code class="language-blade">@php($relatedPosts = $post-&gt;relatedPosts())
@if($relatedPosts-&gt;isNotEmpty())
    &lt;div id=&quot;suggestions&quot; class=&quot;space-y-4&quot;&gt;
        &lt;h4&gt;You might also enjoy...&lt;/h4&gt;

        &lt;div class=&quot;space-y-2&quot;&gt;
            @foreach($relatedPosts-&gt;shuffle()-&gt;take(2) as $post)
                &lt;x-post-card :post=&quot;$post&quot; :excerpt=&quot;false&quot; /&gt;
            @endforeach
        &lt;/div&gt;
    &lt;/div&gt;
@endif
</code></pre>
<p>Pretty simple Blade logic here. If we find some related posts, we loop over them and output the <code>x-post-card</code> Blade component. The excerpt is disabled to save some vertical space.</p>
<p>We also shuffle the posts and take the first 2 results so that we don't end up suggesting the same 2 posts to every visitor.</p>
<h2>Result</h2>
<p>With all of that in place, you should be able to see some post suggestions at the end of this page.</p>
<p>If you want to see all of the code changes, the <a href="https://github.com/ryangjchandler/ryangjchandler.co.uk/pull/183">pull request can be found here</a>.</p>
<p>Probably worth clicking through and reading one of those suggested posts, right?</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 17 Jun 2022 00:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Creating dynamic HTML tooltips with Alpine.js and alpine-tooltip]]></title>
                <link>https://ryangjchandler.co.uk/posts/creating-dynamic-html-tooltips-with-alpine-and-alpine-tooltip</link>
                <description><![CDATA[<p>After integrating Tippy into a few projects with Alpine.js, I decided to write my own plugin to make the integration easier and the API a little nicer (<code>x-tooltip</code> and <code>$tooltip</code>).</p>
<p>The <a href="https://github.com/ryangjchandler/alpine-tooltip">package itself</a> receives hundreds of thousands of hits via the CDN each month and has become quite popular.</p>
<p>Something that is quite common is using a template element in your HTML to provide <a href="https://atomiks.github.io/tippyjs/">Tippy</a> with content. A recent release of my package (v1.2.0) now lets developers provide a raw Tippy configuration object to the <code>x-tooltip</code> directive.</p>
<p>This new integration path makes it simple to use other Alpine directives and <code>&lt;template&gt;</code> tags to generate the content for your tooltip.</p>
<h2>Using <code>&lt;template&gt;</code> tags for content</h2>
<pre><code class="language-html">&lt;div x-data=&quot;{ message: 'Hello, world!' }&quot;&gt;
    &lt;template x-ref=&quot;template&quot;&gt;
        &lt;p x-text=&quot;message&quot;&gt;&lt;/p&gt;
    &lt;/template&gt;

    &lt;button type=&quot;button&quot;&gt;
        Show message!
    &lt;/button&gt;
&lt;/div&gt;
</code></pre>
<p>I want to use the <code>&lt;template&gt;</code> tag here as my tooltip content. Tippy doesn't know about this element, so we need to use a configuration object to inform Tippy of its existence and <code>innerHTML</code>.</p>
<p>This can be done with the <code>x-tooltip</code> directive on <code>&lt;button&gt;</code> the like so:</p>
<pre><code class="language-html">&lt;button x-tooltip=&quot;{
    content: () =&gt; $refs.template.innerHTML,
}&quot;&gt;
    Show message!
&lt;/button&gt;
</code></pre>
<p>The <code>content</code> property on the object is a callback function. This function is invoked by Tippy before each tooltip render and the return value should be a string or an HTML element. We'll use a string since the element itself is a <code>&lt;template&gt;</code> and doesn't actually get rendered by the browser in this scenario.</p>
<p>Tippy will render all HTML as plain text for security reasons. To prevent this, we also need to tell Tippy to allow HTML content using the <code>allowHTML</code> property.</p>
<pre><code class="language-html">&lt;button x-tooltip=&quot;{
    content: () =&gt; $refs.template.innerHTML,
    allowHTML: true,
}&quot;&gt;
    Show message!
&lt;/button&gt;
</code></pre>
<p>Hovering over the button now will present an empty element... not so good. If you inspect the DOM, you'll see that Tippy actually appends an HTML element to the <code>&lt;body&gt;</code> of the document via <code>document.body</code>. This element is what appears when hovering or interacting with the button.</p>
<p>Our Alpine component is only scoped to the original <code>&lt;div&gt;</code> where <code>x-data</code> or <code>x-init</code> is defined. It doesn't operate outside of that element and therefore can't process the tooltip's HTML content.</p>
<p>To solve this, Tippy needs to append the dynamic tooltip element to a different element inside of the Alpine component's scope. This can be achieved using the <code>appendTo</code> property.</p>
<pre><code class="language-html">&lt;button x-tooltip=&quot;{
    content: () =&gt; $refs.template.innerHTML,
    allowHTML: true,
    appendTo: $root,
}&quot;&gt;
    Show message!
&lt;/button&gt;
</code></pre>
<p>Using the magic <code>$root</code> variable, Tippy will append the tooltip's HTML element to the end of our Alpine component instead of the <code>&lt;body&gt;</code>. This means Alpine can process the HTML and bind text, event listeners etc.</p>
<h3>Interactive HTML</h3>
<p>The HTML rendered by Tippy won't be interactive by default. This means that links and other elements in the tooltip will essentially be unreachable by the user.</p>
<p>Tippy provides an <code>interactive</code> property that reverses this and allows interactive HTML elements to be interacted with.</p>
<pre><code class="language-html">&lt;button x-tooltip=&quot;{
    content: () =&gt; $refs.template.innerHTML,
    allowHTML: true,
    appendTo: $root,
    interactive: true
}&quot;&gt;
    Show message!
&lt;/button&gt;
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 23 May 2022 00:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Bookmarklets you should definitely be using]]></title>
                <link>https://ryangjchandler.co.uk/posts/bookmarklets-you-should-definitely-be-using</link>
                <description><![CDATA[<p>Bookmarklets have been around for decades. Most people will reach for applications (web and desktop) to handle certain things, when in reality a bookmarklet can be just as useful.</p>
<p>As developers we spend a lot of time in the browser. Let me show you some of my favourites, things I wouldn't be able to go without.</p>
<blockquote>
<p>The code in this post won't be in the correct format for a bookmarklet since it's not super readable. I'd recommend using a bookmarklet generator like <a href="https://mrcoles.com/bookmarklet/">this one</a> or <a href="https://caiorss.github.io/bookmarklet-maker/">this one</a>.</p>
</blockquote>
<h2>Unique plus-alias emails</h2>
<p>When you're testing applications, you'll probably need to create an account. This bookmarklets will create a unique email address using <code>+</code> aliases and UNIX timestamps.</p>
<pre><code class="language-js">(function () {
    window.navigator.clipboard.writeText(`youremail+${Date.now()}@yourdomain.com`)
})()
</code></pre>
<p>It's an <a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE">IIFE</a> that will copy a unique email address to your clipboard. This is great for testing registration forms and emails.</p>
<h2>Quick color picker</h2>
<p>I find myself converting colors from hex codes to RGB and HSL a lot. Instead of using a dedicated desktop app for this, I can just use the browser's own color picker.</p>
<pre><code class="language-html">&lt;html&gt;
    &lt;title&gt;Color Picker&lt;/title&gt;
    &lt;input type=&quot;color&quot;&gt;
&lt;/html&gt;
</code></pre>
<h2>Disabling client side validation</h2>
<p>Most of the forms I build use server-side validation as well as client-side validation. Testing the server-side validation rules can be a pain when they also have client-side counterparts (required, min, max, etc).</p>
<p>To get around this, I have a bookmarklet that will disable client-side validation on all forms.</p>
<pre><code class="language-js">(function () {
    document.querySelectorAll('form').forEach(form =&gt; form.noValidate = true)
})()
</code></pre>
<p>Simple, but super productive!</p>
<h2>Design mode</h2>
<p>Modern browsers have the something called &quot;design mode&quot;. It turns the current page into an editable document, allowing you to modify text. Perfect for when a client or manager is asking what a piece of copy looks like in a certain position.</p>
<pre><code class="language-js">(function () {
    document.designMode = (document.designMode === 'on' ? 'off' : 'on')
})()
</code></pre>
<p>If you've got some cool bookmarklets that you'd like me to add to this article, let me know on <a href="https://twitter.com/ryangjchandler">Twitter</a>. I'm always looking for new ways to increase / improve my productivity.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 11 May 2022 00:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[2021: A year in review]]></title>
                <link>https://ryangjchandler.co.uk/posts/2021-a-year-in-review</link>
                <description><![CDATA[<h2>Personal</h2>
<p>I wrote about saving for a deposit in last year's review. That deposit was eventually used after securing a mortgage and purchasing our first house. It's been super nice to have our own space with a dedicated office for my work.</p>
<h2>Work</h2>
<p>I'm still a full-time developer at <a href="https://surewise.com">Surewise</a> and I've managed to enhance our tech stack even further this year. We've continued to adopt <a href="https://laravel-livewire.com">Livewire</a> and <a href="https://alpinejs.dev">Alpine.js</a>.</p>
<p>We've also adopted <a href="https://tailwindcss.com">Tailwind</a> in some of our newer projects and systems, finally making the move away from heavily-overwritten Bootstrap.</p>
<p>I've also been hot on PHP upgrades. We started the year on PHP 7.4 and upgraded to PHP 8.0 pretty quickly and we're now aiming for an upgrade to PHP 8.1 in Q1.</p>
<h3>Freelancing</h3>
<p>Last year I started freelancing / contracting for other businesses who were looking for TALL stack help. I continued doing that in 2021 and have completed a plethora of projects.</p>
<p>There has been a huge variety of work coming in and I've enjoyed every second of it.</p>
<h2>Open-source</h2>
<p>Just like last year, I have spent a good chunk of time contributing to open-source projects and releasing some of my own.</p>
<p>I've made <strong>more than 4000 contributions</strong> to repositories of GitHub this year. Here are some of my personal favourites.</p>
<h3>Filament</h3>
<p><a href="https://filamentadmin.com/">Filament</a> is a set of Laravel packages designed for TALL stack development. It provides a table builder, form builder and highly extensible admin-panel package for your Laravel applications.</p>
<p>I joined the project after using it myself on this blog and some other toy projects and sending in multiple contributions. Since then, <a href="https://twitter.com/danjharrin">Dan</a> has worked hard on the 2.x release and I've tried my best to contribute wherever possible.</p>
<p>Using these packages myself has allowed me to see some flaws and opportunities for refinement, which is never a bad thing. Dog-fooding is one of the best ways to do this.</p>
<h3>Alpine Packages</h3>
<p>Alpine 3.x was released in 2021 and this came thing an amazing new plugin API. I took some of my older 2.x packages and upgraded them to support 3.x.</p>
<p>At the time of writing this post, my <a href="https://github.com/ryangjchandler/alpine-clipboard">Alpine Clipboard</a> package receives more than <strong>1 million</strong> hits per month on the CDN and my <a href="https://github.com/ryangjchandler/alpine-tooltip">Alpine Tooltip</a> packages receives more than <strong>150,000 hits</strong> per month.</p>
<p>The Spruce library was archived and no longer receives updates since Alpine provides a first-party global state solution. Despite that, the CDN still recieves almost <strong>100,000 hits</strong> per month.</p>
<h2>Other work</h2>
<p>I've been super interested in programming language theory, design and development in 2021. I've played around with multiple language ideas and have open-sourced a couple on GitHub.</p>
<p>A lot of this work was done using the Rust programming language which I really enjoy using. I even <a href="https://youtube.com/playlist?list=PLX0VJHnEgHeqE06mX4m2rjlOWm_GUWOTI">streamed it a few times on YouTube</a>.</p>
<p>I'd like to continue this journey in 2022 and work on a solid programming language that targets a specific domain (not crypto, dw). Some of the areas that interest me are:</p>
<ul>
<li>Mathematical calculations and data science</li>
<li>Graphical application development</li>
<li>Word processing</li>
</ul>
<p>Who knows? Perhaps I'll have a language by the end of the year that people actually use and find helpful.</p>
<h2>Epilogue</h2>
<p>I want to thank everybody who has supported my work over the last year through Twitter, GitHub and sponsorships. It really does mean a lot.</p>
<p>I set myself some goals last year and can confirm that I completed the following:</p>
<ul>
<li>Convincing <a href="https://twitter.com/taylorotwell">Taylor</a> to follow me on Twitter.</li>
<li>Released at least 3 new open source packages.</li>
<li>Met new friends.</li>
<li>Wrote more blog posts and helped people out.</li>
</ul>
<p>Going forward into 2022, I would like to do the following:</p>
<ul>
<li>Reach 5,000 followers on <a href="https://twitter.com/ryangjchandler">Twitter</a> - currently at 3,000.</li>
<li>Stream on YouTube at least once a month.</li>
<li>Continue writing more blog posts.</li>
<li>Speak at a conference.</li>
</ul>
<p>We'll see that how goes next year.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 30 Dec 2021 13:30:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Baby's first virtual machine]]></title>
                <link>https://ryangjchandler.co.uk/posts/babys-first-virtual-machine</link>
                <description><![CDATA[<p>In this post, I'll be showing you how to build your first stack-based virtual machine with JavaScript.</p>
<p>At the end of the post, we'll be able to provide our virtual machine with a few mathematical instructions and it will be able to run through those instructions and produce an answer.</p>
<p>We'll be using JavaScript to build our virtual machine so that we don't get lost in type-system details. Most people can read and understand JavaScript too, so it's great for teaching new concepts.</p>
<h2>What is a virtual machine?</h2>
<p>Before we look at how to build one, let's briefly talk about what a virtual machine is.</p>
<p>At the highest level, a virtual machine is just a software-implementation of a computer. It loosely simulates the behaviour of a CPU by reading instructions and performing actions based on those instructions. Virtual machines are commonly used by programming languages to implement their interpretation layer. This is where the programming language actually does most of the logical work.</p>
<h3>What is a stack machine?</h3>
<p>There are many types of virtual-machine, so to keep things simple we'll be building one of the simplest.</p>
<p>A stack-based virtual machine uses the <strong>stack</strong> to, more often than not, store short-lived temporary values. You can think of the stack as an array that is constantly being pushed to, as well as popped from.</p>
<p>When you encounter some form of value, you will generally push that value to the stack. When you encounter an instruction, it will likely need some sort of argument to operate or (commonly known as an <strong>operand</strong>). This argument is retrieved from the stack by popping it from the end, removing it from the stack completely.</p>
<h2>Instructions and Operands</h2>
<p>Our virtual machine is going to act a simple calculator. We'll be able to <code>ADD</code>, <code>SUBTRACT</code>, <code>DIVIDE</code>, <code>MULITPLY</code> and <code>PRINT</code> values using a combination of instructions and values.</p>
<p>Let's take a look at a simple <code>ADD</code> instruction. We'll start off by creating a global constant in our program called <code>ADD</code> and use its string equivalent as the value.</p>
<pre><code class="language-js">const ADD = 'ADD';
</code></pre>
<p>Let's also create an array to store our instructions in.</p>
<pre><code class="language-js">const ADD = 'ADD';

const instructions = [
    ADD,
];
</code></pre>
<p>If you think of the <code>+</code> operation in a mathematical equation, you have 2 operands. The equation <code>1 + 2</code> is adding the numbers <code>1</code> and <code>2</code> together, making them the operands in the equation.</p>
<p>Our <code>ADD</code> instruction will behave in the exact same way. We will need to provide 2 numbers for it to function correctly. The simplest way to do this is by adding them to the <code>instructions</code> array <em>before</em> our <code>ADD</code> instruction.</p>
<pre><code class="language-js">const instructions = [
    1, 2, ADD,
];
</code></pre>
<p>We place them before the instruction so that the <code>ADD</code> instruction can <em>pop</em> them off of the stack and then add them together. To show this in action, let's start creating our main evaluation loop as well as our stack.</p>
<p>We'll use a <code>for..of</code> loop so that we can have direct access to the instruction, as opposed to the instruction's index in the array.</p>
<pre><code class="language-js">const stack = [];

for (const instruction of instructions) {
    if (! Number.isNaN(instruction)) {
        stack.push(instruction);
        continue;
    }
}
</code></pre>
<p>We start by handling our numeric values. To check if something is a number, we can use the <code>isNaN()</code> function. If it returns <code>false</code>, it must be a number. In that case, we can push the value onto the stack and move on to the next iteration.</p>
<p>To keep things super simple, let's use a <code>switch</code> statement to handle all of our instructions:</p>
<pre><code class="language-js">for (const instruction of instructions) {
    if (! isNaN(instruction)) {
        stack.push(instruction);
        continue;
    }

    switch (instruction) {
        case ADD:
            let b = stack.pop()
            let a = stack.pop()
            stack.push(a + b)
            break;
        default:
            throw new Error(`Unhandled instruction: ${instruction}`)
    }
}
</code></pre>
<p>When we encounter an <code>ADD</code> instruction, we can pop the 2 operands from the stack. The first value that is popped will be the second (right-hand) operand to the equation.</p>
<p>This can be quite confusing at first, but it's all down to the order that they were pushed in. The first value we pushed was <code>1</code>, the left-hand side of the equation. The second value was <code>2</code>, the right-hand side of the equation. When the first value is popped off of the stack, it'll be the number <code>2</code>.</p>
<p>Once we have both <code>a</code> and <code>b</code>, we can add the 2 numbers together and push the value back on to the stack.</p>
<p>To help with debugging, let's create a new <code>PRINT</code> instruction that will print <code>pop</code> the last value from the stack and run it through <code>console.log()</code>.</p>
<pre><code class="language-js">const ADD = 'ADD';
const PRINT = 'PRINT';

const instructions = [
    1, 2, ADD,
    PRINT,
];

for (const instruction of instructions) {
    if (! isNaN(instruction)) {
        stack.push(instruction);
        continue;
    }

    switch (instruction) {
        case ADD:
            let b = stack.pop()
            let a = stack.pop()
            stack.push(a + b)
            break;
        case PRINT:
            console.log(stack.pop())
            break;
        default:
            throw new Error(`Unhandled instruction: ${instruction}`)
    }
}
</code></pre>
<p>If we run this program now, we can expect the number <code>3</code> to printed to the console.</p>
<h2>Subtraction, Multiplication and Division</h2>
<p>With the <code>ADD</code> and <code>PRINT</code> instructions in place, let's add the logic for <code>SUBTRACT</code>, <code>MULTIPLY</code> and <code>DIVIDE</code>.</p>
<pre><code class="language-js">const ADD = 'ADD';
const SUBTRACT = 'SUBTRACT';
const MULTIPLY = 'MULTIPLY';
const DIVIDE = 'DIVIDE';
const PRINT = 'PRINT';

// ...

for (const instruction of instructions) {
    if (! isNaN(instruction)) {
        stack.push(instruction);
        continue;
    }

    switch (instruction) {
        case ADD:
            let b = stack.pop()
            let a = stack.pop()
            stack.push(a + b)
            break;
        case SUBTRACT:
            let b = stack.pop()
            let a = stack.pop()
            stack.push(a - b)
            break;
        case MULTIPLY:
            let b = stack.pop()
            let a = stack.pop()
            stack.push(a * b)
            break;
        case DIVIDE:
            let b = stack.pop()
            let a = stack.pop()
            stack.push(a / b)
            break;
        case PRINT:
            console.log(stack.pop())
            break;
        default:
            throw new Error(`Unhandled instruction: ${instruction}`)
    }
}
</code></pre>
<p>We now have a nice set of instructions to calculate some simple mathematical equations. Let's update our <code>instructions</code> array and calculate the value of <code>1 + 2 * 3</code>.</p>
<pre><code class="language-js">const instructions = [
    1,
    2, 3, MULTIPLY,
    ADD,
    PRINT,
]
</code></pre>
<p>The order of these instructions might seem a little strange at first, but it's all to do with the precedence of each sub-calculation. If we were to insert some parentheses into the equation, it would really look like <code>1 + (2 * 3)</code> because the multiplication needs to be calculated separately.</p>
<p>Putting that into words we're really calculating the result of <code>1</code> added to the result of <code>2 * 3</code>. Our instruction set is doing the same. We first push the value of <code>1</code> onto the stack. The value of <code>2 * 3</code> is then calculated and pushed back on to the stack.</p>
<p>When the <code>ADD</code> instruction is reached we pop the result of <code>2 * 3</code> from the stack, as well as the value of <code>1</code> and add those together, pushing the result back on to the stack.</p>
<p>With any luck, running this program will print <code>7</code> in the console.</p>
<h3>A small problem</h3>
<p>At the moment we can only print a value at the very end of the program. This is because the <code>PRINT</code> instruction will pop the last value off of the stack permanently, meaning any further instructions might not have a value to pop off.</p>
<p>To fix this, we can update our <code>PRINT</code> case to instead retrieve the last value from the stack and print it.</p>
<pre><code class="language-js">case PRINT:
    console.log(stack[stack.length - 1])
    break;
</code></pre>
<h2>Refactoring</h2>
<p>There's lot of duplicated code in our instruction handling at the moment. All of our mathematical operations are popping 2 values from the stack and pushing back the result of the operation.</p>
<p>To tidy this up, we could create some sort of instruction handler function for each of our instructions. Let's start by creating a <code>handler</code> object that maps the instruction to a callback function.</p>
<pre><code class="language-js">const handler = {
    ADD: (a, b) =&gt; a + b,
    SUBTRACT: (a, b) =&gt; a - b,
    MULTIPLY: (a, b) =&gt; a - b,
    DIVIDE: (a, b) =&gt; a / b,
}
</code></pre>
<p>When we encounter one of our mathematical instructions, we can create a common <code>case</code> block that pops the values and invokes one of these functions.</p>
<pre><code class="language-js">for (const instruction of instructions) {
    if (! isNaN(instruction)) {
        stack.push(instruction);
        continue;
    }

    switch (instruction) {
        case ADD:
        case SUBTRACT:
        case MULTIPLY:
        case DIVIDE:
            let b = stack.pop()
            let a = stack.pop()
            let result = handler[instruction](a, b)

            stack.push(result)
            break;
        case PRINT:
            console.log(stack[stack.length - 1])
            break;
        default:
            throw new Error(`Unhandled instruction: ${instruction}`)
    }
}
</code></pre>
<p>This removes a lot of code duplication from our <code>switch</code> statement and gives us a single place to add new instruction handlers in the future.</p>
<h2>Next steps</h2>
<p>Now that you've created your own stack-based virtual machine, why not try to write a parser that converts a mathematical equation such as <code>1 + 2 / 3 * 4</code> into a set of instructions and runs them through your machine. Doing this will essentially give you a tiny calculator program that can grow further into a domain-specific language or general-purpose programming language.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 25 Oct 2021 15:00:00 +0000</pubDate>
                                    <category>Programming Languages</category>
                            </item>
                    <item>
                <title><![CDATA[Creating an `Option` type in PHP]]></title>
                <link>https://ryangjchandler.co.uk/posts/creating-an-option-type-in-php</link>
                <description><![CDATA[<p>If you've ever worked with the Rust language, you've likely run into <code>Option</code>.</p>
<p>There is no concept of <code>null</code> or <code>nil</code> in Rust, nor is there any concept of optional parameters in function definitions.</p>
<p>This is one of the things that makes Rust's type system so powerful, reliable and, at times, annoying.</p>
<p>The <code>Option</code> type itself is actually just an <code>enum</code> (enumeration) that is defined as:</p>
<pre><code class="language-rust">enum Option&lt;T&gt; {
    Some(T),
    None
}
</code></pre>
<blockquote>
<p>In Rust, enums are able to hold values inside of variants. This is something that <a href="https://wiki.php.net/rfc/tagged_unions">has been thought of</a> in PHP land too.</p>
</blockquote>
<p>Rust provides some global constructors for the <code>Option</code> type too. You don't need to type <code>Option::Some(value)</code> everytime, you can just type <code>Some(value)</code>.</p>
<p>If you were to add an optional parameter to a function, it would look something like this:</p>
<pre><code class="language-rust">fn hello(name: Option&lt;String&gt;) {
    let name = if name.is_some() {
        name.unwrap()
    } else {
        &quot;World!&quot;.to_string()
    }

    println!(&quot;Hello, {}&quot;, name)
}
</code></pre>
<p>Again, the <code>Option</code> enum is generic so you need to provide the type of the wrapped value.</p>
<p>Calling <code>unwrap()</code> on the <code>Option</code> will return the inner value, in this case a <code>String</code>. If the <code>Option</code> is <code>None</code>, then the program panics and fails to run.</p>
<h2>Why is this better?</h2>
<p>The <code>Option</code> type is best used in situations where you <em>sometimes</em> return a value from a function (typically an object).</p>
<p>It's not uncommon to forget about the cases where no value, or <code>null</code>, is returned from the function.</p>
<p>By introducing an <code>Option</code> type you have to explicitly handle the <code>None</code> or <code>null</code> case, otherwise you won't be able to access the wrapped value.</p>
<p>Here's an example in a Laravel application:</p>
<pre><code class="language-php">$name = Auth::user()-&gt;name;
</code></pre>
<p>If the user is logged in this code will work fine. If the user isn't logged in, <code>Auth::user()</code> will return <code>null</code> and the <code>-&gt;name</code> access will error out.</p>
<p>In PHP 8, you could handle this with the <code>?-&gt;</code> (nullsafe) operator but you would still end up with a <code>null</code> value in <code>$name</code>.</p>
<p>If the <code>Auth::user()</code> function used <code>Option</code>:</p>
<pre><code class="language-php">public function user(): Option
{
    return $this-&gt;user ? new Some($this-&gt;user) : new None;
}
</code></pre>
<p>To access the <code>User</code>, you would need to do something like this:</p>
<pre><code class="language-php">$user = Auth::user()-&gt;unwrap();
</code></pre>
<p>If <code>None</code> is returned from the <code>Auth::user()</code> function, the <code>unwrap()</code> method call will fail and throw an <code>Exception</code> because you can't <code>unwrap</code> a <code>None</code> value.</p>
<p>You have to explicitly consider the <code>None</code> scenario when working with <code>Option</code>.</p>
<h2>Creating the type</h2>
<p>We can start by defining an <code>interface</code> for our <code>Option</code> type that the <code>Some</code> and <code>None</code> types will implement.</p>
<blockquote>
<p>I'll be writing PHP 8.0 compatible code. If you haven't upgraded already, you definitely should.</p>
</blockquote>
<pre><code class="language-php">interface Option
{
    public function isSome(): bool;

    public function isNone(): bool;

    public function unwrap(): mixed;
}
</code></pre>
<p>These three functions are the bare essentials. You'll be able to determine if a type is <code>None</code>, <code>Some</code> and retrieve the internal value.</p>
<h3><code>None</code></h3>
<p>With this interface defined, we can go ahead and create our <code>None</code> type.</p>
<pre><code class="language-php">class None implements Option
{
    public function isSome(): bool
    {
        return false;
    }

    public function isNone(): bool
    {
        return true;
    }

    public function unwrap(): mixed
    {
        throw new \RuntimeException('Attempt to call `unwrap()` on `None` value');
    }
}
</code></pre>
<p>The <code>None</code> type is the simplest. The <code>unwrap()</code> method will throw a <code>\RuntimeException</code> as you can't unwrap a <code>None</code> value.</p>
<blockquote>
<p>In PHP 8.1 you could replace the <code>mixed</code> return type with <code>never</code> as it always throws a <code>\RuntimeException</code>.</p>
</blockquote>
<h3><code>Some</code></h3>
<p>The <code>Some</code> type has a little more going on. We need to define a <code>__construct</code> method to actually hold the value and also return that value from <code>unwrap()</code>.</p>
<pre><code class="language-php">class Some implements Option
{
    public function __construct(
        protected mixed $value
    ) {}

    public function isSome(): bool
    {
        return true;
    }

    public function isNone(): bool
    {
        return false;
    }

    public function unwrap(): mixed
    {
        return $this-&gt;value;
    }
}
</code></pre>
<p>With these implemented, we can go ahead and write our first function that uses <code>Option</code>.</p>
<pre><code class="language-php">function sayHello(Option $name) {
    $name = $name-&gt;isNone() ? 'World' : $name-&gt;unwrap();

    echo &quot;Hello, {$name}!&quot;;
}

sayHello(new None);         // Outputs &quot;Hello, World!&quot;
sayHello(new Some('Ryan')); // Outputs &quot;Hello, Ryan!&quot;
</code></pre>
<h3><code>unwrapOr()</code></h3>
<p>When you start using <code>Option</code>, you'll find yourself using <code>?:</code> (ternaries) or <code>if..else</code> statements to set default values.</p>
<p>We can help ourselves out by introducing a new <code>unwrapOr(mixed $or)</code> method.</p>
<p>Let's first add it to our <code>Option</code> interface.</p>
<pre><code class="language-php">interface Option
{
    public function unwrapOr(mixed $or): mixed;
}
</code></pre>
<p>And then implement in our <code>Some</code> and <code>None</code> classes.</p>
<pre><code class="language-php">class Some implements Option
{
    public function unwrapOr(mixed $or): mixed
    {
        return $this-&gt;unwrap();
    }
}
</code></pre>
<p>The <code>Some</code> class should always hold a value, so we will never need to return the <code>$or</code>.</p>
<pre><code class="language-php">class None implements Option
{
    public function unwrapOr(mixed $or): mixed
    {
        return $or;
    }
}
</code></pre>
<p>The <code>None</code> class can never be unwrapped so we will always return the value of <code>$or</code>.</p>
<p>With this method in place, we can remove the ternary from our <code>sayHello()</code> function:</p>
<pre><code class="language-php">function sayHello(Option $name) {
    $name = $name-&gt;unwrapOr('World');

    echo &quot;Hello, {$name}!&quot;;
}
</code></pre>
<h2>Generics</h2>
<p>PHP doesn't support runtime generics. There is no first-party syntax for them either.</p>
<p>We're very fortunate to have static analysis engines though, so we can use DocBlocks to imitate generic types.</p>
<p>Let's start by adding some annotations to your <code>Option</code> interface.</p>
<blockquote>
<p>I'll be using annotations supported by <a href="https://github.com/phpstan/phpstan">PHPStan</a>.</p>
</blockquote>
<pre><code class="language-php">/**
 * @template T
 */
interface Option {
    // ...
}
</code></pre>
<p>This makes the <code>Option</code> type generic on <code>T</code>. To actually make <code>T</code> do something, we'll need to tell the analyser where <code>T</code> comes from.</p>
<p>Let's add some annotations to the <code>Some</code> type.</p>
<pre><code class="language-php">/**
 * @template T
 *
 * @implements \Option&lt;T&gt;
 */
class Some implements Option
{
    // ...
}
</code></pre>
<p>These class-level annotations will tell the analyser that the <code>Some</code> class is also generic and that the type of <code>T</code> in <code>Some</code> should also be used as the generic type of <code>Option</code> which we're implementing.</p>
<p>Since our <code>unwrap()</code> and <code>unwrapOr()</code> method return a <code>mixed</code> type inside of <code>Some</code>, we can't guarantee that any further method calls or property access is valid.</p>
<p>To tackle this we can add more annotations to those methods, as well as the property promotion in our constructor.</p>
<pre><code class="language-php">/**
 * @template T
 *
 * @implements \Option&lt;T&gt;
 */
class Some implements Option
{
    public function __construct(
        /** @var T */
        protected mixed $value
    ) {}

    /**
     * @return T
     */
    public function unwrap(): mixed
    {
        return $this-&gt;value;
    }

    /**
     * @return T
     */
    public function unwrapOr(mixed $or): mixed
    {
        return $this-&gt;unwrap();
    }
}
</code></pre>
<p>Adding the <code>@var</code> annotation to the promoted property, the analyser will figure out that the type of <code>$value</code> should be used as <code>T</code>.</p>
<p>It can then detect any problems with <code>unwrap</code> and <code>unwrapOr</code> calls.</p>
<h2>Possible Refactoring</h2>
<p>I've implemented everything inside of an <code>Option</code> interface and 2 classes that implement that interface.</p>
<p>This means that our <code>Some</code> and <code>None</code> classes have to implement <em>all</em> of the methods that are part of the contract.</p>
<p>It's not the prettiest thing ever, so if you wanted to refactor this you could instead create an <code>abstract class Option</code> that the <code>Some</code> and <code>None</code> classes extend.</p>
<p>You can then implement the methods inside of the <code>abstract</code> class instead and reduce some of the duplication between the two option types.</p>
<h2>PHP 8.1 and beyond</h2>
<p>PHP 8.1 will be introducing first-party <code>enum</code> types. This brings us one tiny step closer to a Rust-like implementation:</p>
<pre><code class="language-php">enum Option {
    case Some;
    case None;
}
</code></pre>
<p>The only differences between the two languages would be that fact that PHP can't hold values inside of enum variants and that they can't be generically typed.</p>
<p>I hope that PHP will get tagged enums in the near future. This <a href="https://wiki.php.net/rfc/tagged_unions">draft RFC has already started</a> the conversation.</p>
<p>With tagged enums, we could have something like this:</p>
<pre><code class="language-php">enum Option {
    case Some(private $value);
    case None;
}
</code></pre>
<p>Add some generics ontop and we have a slightly more verbose but more powerful <code>Option</code> type.</p>
<pre><code class="language-php">enum Option&lt;T&gt; {
    case Some(private T $value);
    case None;
}
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 22 Sep 2021 13:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Declaring expectations against array items in Pest]]></title>
                <link>https://ryangjchandler.co.uk/posts/declaring-expectations-against-array-items-in-pest</link>
                <description><![CDATA[<p><a href="https://pestphp.com/">Pest</a> has an incredible <a href="https://pestphp.com/docs/expectations">Expectations API</a> that you can use when writing your tests.</p>
<p>It provides a fluent builder pattern for declaring expectations and making assertions against your data.</p>
<p>Here's a very simple example:</p>
<pre><code class="language-php">$names = [
    'Ryan',
    'John',
    'Jane',
];

expect($names)
    -&gt;toBeArray()
    -&gt;toHaveCount(3)
    -&gt;toMatchArray([
        'Ryan',
        'John',
        'Jane',
    ]);
</code></pre>
<p>Each of the method calls makes an assertion on the data provided to <code>expect()</code>.</p>
<p>When you're working with objects, you can also use <a href="https://pestphp.com/docs/expectations#higher-order-expectations">higher-order expectations</a> to make assertions against properties and method return values.</p>
<p>One tricky problem that I have faced today is that you can't use the <code>HigherOrderExpectation</code> object as an array.</p>
<p>This prevents you from doing something like this:</p>
<pre><code class="language-php">$object = new class {
    public function getNames()
    {
        return [
            'Ryan',
            'John',
            'Jane',
        ];
    }
};

expect($object)
    -&gt;getNames()[0]
    -&gt;toBe('Ryan');
</code></pre>
<p>When you call <code>getNames()</code>, the <code>HigherOrderExpectation</code> class will proxy that method call to the original object that was passed in and return a new instance of <code>HigherOrderExpectation</code> with the return value of the method inside.</p>
<p>It does this because the method doesn't explicitly exist on the <code>HigherOrderExpecation</code> class or the <code>Expectation</code> class.</p>
<p>It does the same for properties too. The <code>retrieve()</code> method that is used to proxy the property access actually checks whether the base value is an array or not.</p>
<p>If the value is an array, it will take the property name and try to find a value with that key.</p>
<p>Unfortunately PHP doesn't let you use numeric values when accessing properties, so something like <code>$object-&gt;0</code> fails.</p>
<p>What you can do instead is use PHP's <code>{}</code> interpolation syntax to create dynamically access a property. Pest will then attempt to find an array with that key and return an instance of <code>HigherOrderExpectation</code> with that value.</p>
<p>This means we can test individual array items with the Expectation API.</p>
<pre><code class="language-php">expect($object)
    -&gt;getNames()-&gt;{0}
    -&gt;toBe('Ryan');
</code></pre>
<p>This would return the value as index <code>0</code> so that we can perform assertions.</p>
<p>If you had non-numeric array keys, you can use the normal property access syntax as Pest will proxy those to the array.</p>
<pre><code class="language-php">$ages = [
    'Ryan' =&gt; 100,
];

expect($ages)
    -&gt;Ryan-&gt;toBe(100);
</code></pre>
<blockquote>
<p>I do have a work in progress branch that adds support for the <code>[]</code> syntax as it definitely feels more familiar, but in some cases the syntax is a bit strange, e.g. <code>expect($value)[0]-&gt;toBe('Ryan')[1]-&gt;toBe('John')</code></p>
</blockquote>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 17 Sep 2021 16:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[All about match expressions]]></title>
                <link>https://ryangjchandler.co.uk/posts/all-about-match-expressions</link>
                <description><![CDATA[<p>If you've not been keeping up-to-date with the latest PHP releases, you might have missed that PHP 8.0 introduced a new <code>match</code> expression.</p>
<p>PHP isn't the first language to introduce the concept of a <code>match</code> expression. It has existed in programming languages for quite a while, for example Rust, Scala and more recently Python.</p>
<p>Here's what a <code>match</code> expression looks like:</p>
<pre><code class="language-php">match ($subject) {
    [condition] =&gt; [result]
}
</code></pre>
<p>In its current state <code>match</code> is a hyper-optimised <code>switch</code> statement.</p>
<p>You can use it to conditionally evaluate an expression based on a <code>[condition]</code>.</p>
<p>There are a few key differences between <code>match</code> and <code>switch</code> though:</p>
<ol>
<li><code>match</code> uses strict comparisons. This means that an <code>int</code> subject can't match a <code>string</code> condition.</li>
<li><code>match</code> only evaluates one condition at a time, whereas <code>switch</code> evaluates all <code>case</code> conditions before calculating the result.</li>
<li><code>match</code> only allows single-line expressions to be used in the place of <code>[result]</code>, where as <code>switch</code> allows blocks of code to be executed for each <code>case</code>.</li>
</ol>
<p>Let's take a <code>switch</code> statement and convert it to a <code>match</code> expression.</p>
<pre><code class="language-php">switch ($name) {
    case 'Ryan':
        echo 'Hello, Ryan!';
        break;
    case 'John':
        echo 'Hello, John! How are you?';
        break;
    default:
        echo 'Hello!';
}
</code></pre>
<p>Here's the equivalent code written in the form a <code>match</code> expression:</p>
<pre><code class="language-php">echo match ($name) {
    'Ryan' =&gt; 'Hello, Ryan!',
    'John' =&gt; 'Hello, John! How are you?',
    default =&gt; 'Hello!'
};
</code></pre>
<p>The <code>match</code> expression is definitely more concise.</p>
<p>It's also an expression, meaning it returns a value. This is great as we can use it next to the <code>echo</code> statement directly. We don't need to write an <code>echo</code> for each <code>case</code> like we do for a <code>switch</code> statement.</p>
<h2>Multiple conditions, one result</h2>
<p>If we had a <code>switch</code> statement that had multiple <code>case</code>s executing the same block of code, we'd do something like this:</p>
<pre><code class="language-php">switch ($name) {
    case 'Ryan':
    case 'John':
        echo 'Hello, Ryan or John!';
        break;
    default:
        echo 'Hello!';
}
</code></pre>
<p>To achieve the same effect in a <code>match</code> expression, we can separate the <code>[condition]</code> expressions with commas:</p>
<pre><code class="language-php">echo match ($name) {
    'Ryan', 'John' =&gt; 'Hello, Ryan or John!',
    default =&gt; 'Hello!'
};
</code></pre>
<h2>Generalised match statements</h2>
<p>Imagine you have the following code:</p>
<pre><code class="language-php">$age = (int) $request-&gt;input('age');

if ($age &lt; 25) {
    return $this-&gt;lessThanTwentyFive();
} elseif ($age &lt; 50) {
    return $this-&gt;lessThanFifty();
} elseif ($age &lt; 75) {
    return $this-&gt;lessThanSeventyFive();
} else {
    return $this-&gt;olderThanSeventyFive();
}
</code></pre>
<p>Personally I find <code>elseif</code> statements hard to read. They make the code dense and hard to understand at a glance.</p>
<p>Since we're using boolean values inside of the expression, we can actually convert this into a <code>match</code> expression:</p>
<pre><code class="language-php">$age = (int) $request-&gt;input('age');

return match (true) {
    $age &lt; 25 =&gt; $this-&gt;lessThanTwentyFive(),
    $age &lt; 50 =&gt; $this-&gt;lessThanFifty(),
    $age &lt; 75 =&gt; $this-&gt;lessThanSeventyFive(),
    default =&gt; $this-&gt;oldThanSeventyFive(),
}
</code></pre>
<p>Method and functions calls are expressions, so we can use those in the <code>[result]</code> part of the <code>match</code> expression.</p>
<p><code>match</code> also returns a value so we can use it as the expression in a <code>return</code> statement.</p>
<blockquote>
<p>In the future, we could see the <code>(true)</code> part disappear with the <a href="https://wiki.php.net/rfc/short-match">&quot;short match&quot; RFC</a>.</p>
</blockquote>
<h2>Array pattern matching</h2>
<p>Although PHP doesn't support complex pattern matching (<a href="https://wiki.php.net/rfc/pattern-matching">RFC</a>), you can actually do some light pattern matching when using a <code>match</code> expression with an <code>array</code>.</p>
<p>Here's an example of how you might do something based on the values of an array:</p>
<pre><code class="language-php">// Pseudo-data that you might receive from the front-end.
$options = [
    'monthly',
    'credit-card',
];

if ($options[0] === 'monthly' &amp;&amp; $options[1] === 'direct-debit') {
    return $this-&gt;setupDirectDebit();
} else if ($options[0] === 'yearly' &amp;&amp; $options[1] === 'credit-card') {
    return $this-&gt;takeYearlyCardPayment();
} else if ($options[0] === 'monthly' &amp;&amp; $options[1] === 'credit-card' {
    return $this-&gt;setupCardSubscription();
}
</code></pre>
<p>Again, <code>else if</code> statements can be confusing. Maybe there's a better way to write this code using <code>match</code> expressions.</p>
<pre><code class="language-php">// Pseudo-data that you might receive from the front-end.
$options = [
    'monthly',
    'credit-card',
];

return match ($options) {
    ['monthly', 'direct-debit'] =&gt; $this-&gt;setupDirectDebit(),
    ['yearly', 'credit-card']   =&gt; $this-&gt;takeYearlyCardPayment(),
    ['monthly', 'credit-card']  =&gt; $this-&gt;setupCardSubscription(),
};
</code></pre>
<p>We can actually use the <code>match</code> expression to match an <em>exact</em> array pattern. This is super handy and something that is quite common in other languages like Rust where you would match some sort of tuple pattern.</p>
<p>PHP doesn't have tuples, but arrays are close enough.</p>
<h2>Beyond PHP 8.0</h2>
<p>The <code>match</code> expression in its current state is good enough to replace simple <code>switch</code> statements, lookup tables and even some <code>if..else</code> statements.</p>
<p>There are still some things that can be added to the <code>match</code> expression to make it even cooler though.</p>
<h3>Code blocks</h3>
<p><code>match</code> only support single-line expressions at the moment. You can't have multiple lines of code as the result of a <code>match</code> arm.</p>
<p>This was part of the original RFC, but the syntax was hard to get right so it was removed.</p>
<p>I'd love to see this added, perhaps with this syntax:</p>
<pre><code class="language-php">match ($subject) {
    [condition] =&gt; {
        // Write multiple lines of code here.
        
        // Semi-colon is omitted from the last expression and is used as the return value of the block.
        &quot;Hello, world!&quot;
    }
}
</code></pre>
<p>It's understandable why this syntax was difficult to get right. Using <code>return</code> to return a value from the block is a bit odd as that would typically return a value from the function.</p>
<p>Omitting the semi-colon on the last line, creating an implicit return, is also strange as that behaviour doesn't exist anywhere else in the language.</p>
<p>Introducing a new keyword could work, but it would be yet <em>another</em> keyword added to the language. PHP already has a tonne of reserved keywords.</p>
<h3>Complex pattern matching</h3>
<p>Pattern matching has already been discussed in <a href="https://wiki.php.net/rfc/pattern-matching">this draft RFC</a>.</p>
<p>It's a fairly advanced feature and has lots of use-cases which makes getting the RFC right very difficult.</p>
<p>Here's a simple example where we can check if an object matches a pattern based on the property values:</p>
<pre><code class="language-php">class Vector
{
    public function __construct(
        public int|float $x,
        public int|float $y
    ) {}
}

$vector = new Vector(0, 1);

$vector is Vector { x: 0, y: 1 }; // `true` 
</code></pre>
<p>The plan in the RFC is to introduce a new <code>is</code> keyword which would act as an &quot;infix operator&quot; (something that goes between 2 expressions).</p>
<p>The part on the left would be the subject and the right would be the pattern.</p>
<p>In this case, the pattern is checking if <code>$vector</code> is of the type <code>Vector</code> and if the property <code>$x === 0</code> and <code>$y === 1</code>.</p>
<p>If we were to do this without the pattern matching, it'd look like this:</p>
<pre><code class="language-php">$vector instanceof Vector &amp;&amp; $vector-&gt;x === 0 &amp;&amp; $vector-&gt;y === 1;
</code></pre>
<p>It's very word-y. It's very verbose. Pattern matching is good.</p>
<p>Perhaps we only want to check if the <code>$vector</code> object has an <code>$x</code> value of <code>1</code>. We can ignore the rest of the fields in the object using the <code>..</code> token.</p>
<pre><code class="language-php">$vector is Vector { x: 1, .. }; 
</code></pre>
<p>Although this isn't part of the <a href="https://wiki.php.net/rfc/pattern-matching">RFC</a>, it's something that I absolutely love in Rust.</p>
<p>If we took this pattern matching and paired it with a <code>match</code> expression, we'd end up with something like:</p>
<pre><code class="language-php">$vector = new Vector(0, 1);

match ($vector) {
    Vector { x: 0, y: 1 } =&gt; $vector-&gt;moveTo(0, 2),
};
</code></pre>
<p>The pattern moves into the <code>[condition]</code> spot and works exactly the same.</p>
<p>Some languages, like Rust, take this a step further an allow you to &quot;bind&quot; particular parts of a pattern to a variable in the <code>match</code>'s scope.</p>
<p>Here's what that might look like:</p>
<pre><code class="language-php">echo 'Y co-ordinate: ' . match ($this-&gt;getVector()) {
    Vector { x: 0, $y @ y: 1 } =&gt; $y,
};
</code></pre>
<p>Bit of a silly example but it shows the concept. We can bind a specific part of a pattern to a variable using an <code>@</code> token. We can then use the variable <code>$y</code> in the expression.</p>
<h2>Sign off</h2>
<p>There is definitely lots of room for new features when it comes to <code>match</code> expressions. Despite that, I still love them.</p>
<p>I've been replacing <code>switch</code> statements, <code>if..else</code> statements and boring array-powered lookup tables with them since upgrading to PHP 8.0.</p>
<p>If you haven't upgraded to PHP 8.0 yet, just do it. You're missing out on a lot of great stuff and PHP 8.1 is around the corner. Minimise your upgrade path!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 28 Aug 2021 00:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Laravel seeders on steroids]]></title>
                <link>https://ryangjchandler.co.uk/posts/laravel-seeders-on-steroids</link>
                <description><![CDATA[<p>It's very common for Laravel developers to create &quot;seeder&quot; classes that run in their local environment. The normal use-case is to create some dummy data for local development using <code>Factory</code> classes or the <code>DB</code> facade.</p>
<p>Here are some commands that you've probably run before:</p>
<pre><code class="language-bash">php artisan migrate --seed
</code></pre>
<pre><code class="language-bash">php artisan migrate:fresh --seed
</code></pre>
<pre><code class="language-bash">php artisan db:seed
</code></pre>
<p>Recently I learned that seeders can be more than just <code>Factory</code> runners.</p>
<p>Looking at the underlying <code>Seeder</code> class, you'll notice a couple of different properties:</p>
<pre><code class="language-php">namespace Illuminate\Database;

abstract class Seeder
{
    /**
     * The container instance.
     *
     * @var \Illuminate\Container\Container
     */
    protected $container;

    /**
     * The console command instance.
     *
     * @var \Illuminate\Console\Command
     */
    protected $command;

    // More stuff here...
}
</code></pre>
<h2><code>$container</code></h2>
<p>The <code>$container</code> property can be found in lots of classes provided by Laravel. It's the main way to automatically resolve dependencies, register bindings, etc.</p>
<blockquote>
<p>If you want to read more about Laravel's container, visit the <a href="https://laravel.com/docs/container">official documentation</a>.</p>
</blockquote>
<p>When you run a <code>Seeder</code> class via one of the many <code>artisan</code> commands, the <code>$container</code> property will actually be used to call the <code>run()</code> method defined on the class.</p>
<p>This means you can type-hint container-bound dependencies in your <code>run</code> method's signature to help with extra tasks.</p>
<pre><code class="language-php">class ExternalDataSeeder extends Seeder
{
    public function run(ExternalServiceClient $service)
    {
        $rates = $service-&gt;getRates();

        foreach ($rates as $rate) {
            // Do something with the rates here...
        }
    }
}
</code></pre>
<p>The <code>ExternalServiceClient</code> could be any class or object that has been bound to the container inside of a <code>ServiceProvider</code> or provided by a third-party package.</p>
<p>Dependency injection is a perfect way of removing the construction and resolution logic from the <em>body</em> of the <code>run</code> method.</p>
<h2><code>$command</code></h2>
<p>I think <code>$command</code> is my favourite of the two. As the DocBlock suggests, it holds an instance of <code>Illuminate\Console\Command</code>.</p>
<p>When you're running your seeders via <code>artisan</code>, this is likely going to be an instance of whichever command you're currently running.</p>
<p>The hidden power here is that we now have full access to the terminal, so we can show custom messages and provide extra information.</p>
<p>Let's take our <code>$container</code> example and provide some helpful output about what we're actually doing:</p>
<pre><code class="language-php">class ExternalDataSeeder extends Seeder
{
    public function run(ExternalServiceClient $service)
    {
        $rates = $service-&gt;getRates();

        foreach ($rates as $rate) {
            $rate = Rate::create([
                'name' =&gt; $rate['name'],
                'multiplier' =&gt; $rate['multiplier'],
            ]);

            $this-&gt;command-&gt;info(&quot;Created a new rate with name {$rate-&gt;name} and multiplier {$rate-&gt;multiplier}.&quot;);
        }
    }
}
</code></pre>
<p><code>$this-&gt;command-&gt;info()</code> will print some text in a happy green colour to the console, providing the user with information about what the seeder is actually doing.</p>
<p>We can take this one step further and use <code>$this-&gt;command-&gt;ask()</code> to retreive some input from the user. Let's write a <code>MakeUserSeeder</code> class that creates a new <code>User</code>.</p>
<pre><code class="language-php">use App\Models\User;
use Illuminate\Support\Facades\Hash;

class MakeUserSeeder extends Seeder
{
    public function run()
    {
        $name = $this-&gt;command-&gt;ask('Name');
        $email = $this-&gt;command-&gt;ask('Email');
        $password = $this-&gt;command-&gt;secret('Password');

        User::create([
            'name' =&gt; $name,
            'email' =&gt; $email,
            'password' =&gt; Hash::make($password),
        ]);

        $this-&gt;command-&gt;info('User created successfully.');
    }
}
</code></pre>
<p>Running this seeder will ask the user to provide a name, email and password. It will then create that <code>User</code> in the database so that you can quickly login without needing to run a separate command or fill in a registration form.</p>
<p>Let's do one more thing. Let's replace our custom <code>MakeUserSeeder</code> with my package <code>ryangjchandler/laravel-make-user</code>.</p>
<p>We can begin by installing the package:</p>
<pre><code class="language-bash">composer require ryangjchandler/laravel-make-user
</code></pre>
<p>This package provides a convenient <code>make:user</code> command that will ask similar questions to <code>MakeUserSeeder</code>. You can also extend the command to ask for extra data, more specific to your application.</p>
<p>Inside of our <code>MakeUserSeeder</code>, we can replace the custom logic with a single <code>$this-&gt;command-&gt;call()</code> statement:</p>
<pre><code class="language-php">class MakeUserSeeder extends Seeder
{
    public function run()
    {
        $this-&gt;command-&gt;call('make:user');
    }
}
</code></pre>
<p>This will invoke the <code>make:user</code> command inside of the current process, allowing the <code>make:user</code> command to write to the same &quot;output&quot; as the seeder. That means any <code>$this-&gt;info()</code> or <code>$this-&gt;ask()</code> calls made by the <code>make:user</code> command will appear in the terminal, just like they did in the original <code>MakeUserSeeder</code>.</p>
<p>All in all, I think this is pretty cool. With these 2 things, we can give our seeder classes superpowers and greatly reduce the number of commands or setup steps needed to get a local copy of the application running.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 12 Aug 2021 12:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Delete all rows for a Laravel model]]></title>
                <link>https://ryangjchandler.co.uk/posts/delete-all-rows-for-a-laravel-model</link>
                <description><![CDATA[<p>There are 2 way to delete all of the records for a model.</p>
<ol>
<li><code>Model::truncate()</code></li>
</ol>
<p>This is perfect for when you don't need to modify which records are being deleted and just want to delete all of them.</p>
<pre><code class="language-php">Post::truncate();
</code></pre>
<ol start="2">
<li><code>Model::query()-&gt;delete()</code></li>
</ol>
<p>If you wanted to add some constraints onto the deletion, you'd likely want to use this method. The <code>::query()</code> method just returns a new <code>Builder</code> instance, so you can chain you extra methods with, some, intellisense.</p>
<pre><code class="language-php">Post::query()
    -&gt;delete();

Post::query()
    -&gt;where('created_at', '&lt;', now()-&gt;subYear())
    -&gt;delete();
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 20 Jul 2021 10:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[How to watch Alpine.js stores for changes]]></title>
                <link>https://ryangjchandler.co.uk/posts/how-to-watch-alpine-stores-for-changes</link>
                <description><![CDATA[<p>With Alpine 2.x and Spruce, you could define a global store and also a watcher for a particular store property:</p>
<pre><code class="language-js">Spruce.store('counter', {
    count: 0,
})

Spruce.watch('counter.count', () =&gt; {
    // Do something here...
})
</code></pre>
<p>Anytime the <code>counter.count</code> property was updated, the callback would be called.</p>
<p>With the introduction of <code>Alpine.store</code> in Alpine 3.x there is no longer a dedicated watch method for stores, but we can still get the same effect with <code>Alpine.effect</code> (no pun intended):</p>
<pre><code class="language-js">Alpine.store('counter', {
    count: 0,
})

Alpine.effect(() =&gt; {
    const count = Alpine.store('counter').count;

    // Now do something with `count`...
})
</code></pre>
<p>This works because Alpine will keep track of any dependencies / reactive properties we use inside of the callback and invoke it when any of them change.</p>
<p>Keep in mind that Alpine will run this callback function <strong>atleast once</strong>, so make sure you check for your initial state and prevent anything from happening.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 08 Jul 2021 12:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Effects (The magic behind reactivity)]]></title>
                <link>https://ryangjchandler.co.uk/posts/the-magic-behind-reactivity-effects</link>
                <description><![CDATA[<p>In the <a href="/posts/the-magic-behind-reactivity-proxies">previous instalment</a>, we created a <code>reactive</code> function that accepts an object and returns a new <code>Proxy</code> instance.</p>
<p>If you're not sure what a <code>Proxy</code> is or how it works, definitely go back and read that post.</p>
<p>In this post, I'll be creating an <code>effect</code> function that will allow us to react to changes on the <code>Proxy</code> and update the DOM.</p>
<h2>What is an &quot;effect&quot;?</h2>
<p>An effect is a side-effect of a data change. Generally speaking, it's a function that should be run when a particular piece of data changes.</p>
<p>Here's a good example:</p>
<pre><code class="language-html">&lt;p id=&quot;greeting&quot;&gt;Hello, reader!&lt;/p&gt;
</code></pre>
<p>At the moment, this text is completely static. If we use an <code>effect</code> function, we can actually make this dynamic.</p>
<pre><code class="language-js">const greeting = document.querySelector(&quot;#greeting&quot;);

const data = reactive({
    greeting: &quot;Hello, reader!&quot;,
});

effect(() =&gt; {
    greeting.innerText = data.greeting;
});
</code></pre>
<p>We haven't written the <code>effect</code> function yet, so let's start implementing it now.</p>
<pre><code class="language-js">function effect(callback) {
    callback();
}
</code></pre>
<p>This version of <code>effect</code> is the bare minimum. When we register an effect, we want to invoke / call it immediately to update the DOM.</p>
<h2>Running effects when state changes</h2>
<p>If you were to do something like <code>data.greeting = 'Hello, John!'</code>, nothing will happen. Our DOM node won't be updated, which isn't very helpful.</p>
<p>What we can do is store all the <code>effect</code> callbacks in an array and call each one when our <code>Proxy</code> is updated.</p>
<pre><code class="language-js">const effects = [];

function effect(callback) {
    effects.push(callback);

    callback();
}
</code></pre>
<p>Inside of the <code>Proxy.set</code> handler, we can loop through the <code>effects</code> array and call each callback.</p>
<pre><code class="language-js">function reactive(object) {
    // ...

    return new Proxy(object, {
        // ...
        set(target, property, value) {
            target[property] = reactive(value);

            effects.forEach((effect) =&gt; {
                effect();
            });

            return true;
        },
    });
}
</code></pre>
<p>If we were to now run <code>data.greeting = 'Hello, John!'</code>, the DOM node's <code>innerText</code> property will be updated with the value <code>Hello, John!</code>.</p>
<h2>More efficient updates</h2>
<p>The current system works quite well for small bits of reactivity, such as text changes or attribute changes.</p>
<p>If we were to have 50 different effects though, things would get a little bit out of hand and performance would take quite a big hit. That's because each change we make to <code>data</code> will invoke every callbacks inside of <code>effects</code> and if you're doing anything intensive such as AJAX requests, big loops or heavy DOM updates, your page will slow to a snail's pace.</p>
<p>To work around this issue, we can introduce <strong>dependency tracking</strong>. This is really just a fancy phrase for figuring out what data an <code>effect</code> callback is using.</p>
<p>The major benefit of dependency tracking is the fact that we will be able to only invoke / call the functions that were using the data being changed.</p>
<p>The first thing we need to do is update our <code>effect</code> callback slightly:</p>
<pre><code class="language-js">const effects = new Map();
let currentEffect = null;

function effect(callback) {
    currentEffect = callback;

    callback();

    currentEffect = null;
}
</code></pre>
<p>When we register a new <code>effect</code>, we will assign the callback to a <code>currentEffect</code> variable and remove the old <code>effects</code> array. This will allow us to reference the callback inside of our <code>Proxy.get</code> function later on.</p>
<p>We'll also want to store the effects for a particular <code>Proxy</code> somewhere. The best way to do this is with a <code>Map</code> object.</p>
<p>The <code>Map</code> object provides you with a key/value storage, similar to a normal object. The main difference is that you're not limited to string-based keys, you can actually store objects in the key.</p>
<p>This means we can store the <code>target</code> from our Proxy in the key and then an object literal (<code>{}</code>) in the value.</p>
<p>Here's an example:</p>
<pre><code class="language-js">const map = new Map();

const data = {
    user: &quot;Ryan&quot;,
};

map.set(data, {
    user: [() =&gt; {}],
});

map.get(data)[&quot;user&quot;]; // This returns an array containing an anonymous function.
</code></pre>
<p>Let's also make some changes to the <code>Proxy.get</code> method:</p>
<pre><code class="language-js">let effects = new Map;

function reactive(object) {
    //...

    return new Proxy(object, {
        get(target, property) {
            if (currentEffect === null) {
                return target[property];
            }

            if (! effects.has(target)) {
                effects.set(target, {});
            }

            const targetEffects = effects.get(target);

            if (! targetEffects[property]) {
                targetEffects[property] = [];
            }

            targetEffects[property].push(currentEffect)

            return target[property];
        },
        // ...
    });
</code></pre>
<p>Here's a breakdown of what's happening now:</p>
<ol>
<li>Check if <code>currentEffect</code> is not null. If it's <code>null</code>, we want to just return the property without doing any tracking. It will only hold a value when <code>effect()</code> is doing something.</li>
<li>Check whether our <code>Map</code> has any entries for the <code>target</code> object. If it doesn't, we need to insert an empty object into the <code>Map</code> using <code>Map.set()</code>.</li>
<li>We can then pull that object back out using <code>Map.get(target)</code>.</li>
<li>We need to check whether the current <code>property</code> being accessed on the <code>target</code> has an entry inside of the object returned into <code>targetEffects</code>. If it doesn't, we can simply write to the object using <code>[]</code> notation.</li>
<li>Finally we can return the <code>target[property]</code> so that it still behaves like a normal object.</li>
</ol>
<p>All of this combined allows us to track which properties are being used inside of <code>currentEffect</code>. Cool, right?</p>
<h3>Running effects on change</h3>
<p>Now that we know which <code>effect</code> callbacks rely on certain pieces of data, i.e. <code>property</code>, we can run only the required callbacks inside of <code>Proxy.set</code>.</p>
<pre><code class="language-js">let effects = new Map;

function reactive(object) {
    // ...

    return new Proxy(object, {
        // ...
        set(target, property, value) {
            target[property] = reactive(value);

            if (effects.has(target)) {
                const targetEffects = effects.get(target)

                targetEffects[property].forEach(effect =&gt; {
                    effect()
                })
            }

            return true;
        },
    });
}
</code></pre>
<p>Here's a breakdown of the logic:</p>
<ol>
<li>We need to check whether the current <code>target</code> has any <code>effects</code> register. If it doesn't, we don't want to do anything as it will error out.</li>
<li>Then we want to pull all of the <code>targetEffects</code> for that <code>target</code>.</li>
<li>Once we have those effects, we can get the array for the <code>property</code> being updated and loop over it, invoking / calling each item in the array.</li>
</ol>
<h2>Wrapping up</h2>
<p>And that's it! We now have a reactive object and an <code>effect</code> function that is invoked each time a relevant property in our <code>data</code> is updated.</p>
<p>In the next instalment, I'll show you how to create a reactive data object from an HTML attribute, similar to Alpine's <code>x-data</code>.</p>
<p>Until then, thank you for reading and I'll catch you next time!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 18 Jun 2021 17:01:00 +0000</pubDate>
                                    <category>JavaScript</category>
                            </item>
                    <item>
                <title><![CDATA[Proxies (The magic behind reactivity)]]></title>
                <link>https://ryangjchandler.co.uk/posts/the-magic-behind-reactivity-proxies</link>
                <description><![CDATA[<p>In this short series of blog posts, I'm going to be showing you how reactive JavaScript frameworks such as <a href="https://alpinejs.dev">Alpine.js</a> and <a href="https://vuejs.org/">Vue.js</a> work under the hood.</p>
<p>We'll begin by understanding the <code>Proxy</code> object in JavaScript and create our own budget version of <code>Alpine.reactive()</code>.</p>
<h2>What is <code>Proxy</code>?</h2>
<p>The <code>Proxy</code> object was introduced as part of the ES2015 specification. It allows you to intercept the basic operations on an object, for example retrieving a property, setting a property or deleting a property.</p>
<p>You're able to define your own callbacks / handlers for these operations. This is similar to how PHP's <code>__get</code> and <code>__set</code> magic methods work.</p>
<p>You receive the target object, the name of the property being accessed and when setting, the value that's being assigned.</p>
<p>Here's an example:</p>
<pre><code class="language-js">const proxy = new Proxy(
    {
        count: 0,
    },
    {
        get(target, property) {
            return target[property];
        },
        set(target, property, value) {
            target[property] = value;

            return true;
        },
    }
);
</code></pre>
<p>The code above shows a very basic <code>Proxy</code> handler. The behaviour implemented inside of the <code>get</code> and <code>set</code> methods isn't anything special, it's just returning the <code>property</code> from <code>target</code> and setting it to <code>value</code>. It's really just a regular object.</p>
<p>If we wanted to get fancy, we could put a <code>console.log</code> inside of the <code>get()</code> handler.</p>
<pre><code class="language-js">const proxy = new Proxy(
    {
        count: 0,
    },
    {
        get(target, property) {
            console.log(`Trying to access ${property}.`);

            return target[property];
        },
    }
);

proxy.count;
</code></pre>
<p>When the <code>proxy.count</code> expression is evaluated, the <code>console.log</code> will be called and appear in your console.</p>
<p>One thing that confuses people a lot about <code>Proxy</code> is that it <strong>doesn't</strong> change how you interact with the underlying value.</p>
<p>If you wrap an <code>Array</code> in a <code>Proxy</code>, you can still do <code>myWrappedArray.push</code> or <code>myWrappedArray.filter</code>.</p>
<h2>Creating a function</h2>
<p>Now that we know what a <code>Proxy</code> is, let's create a new function:</p>
<pre><code class="language-js">function reactive(object) {
    return new Proxy(object, {
        get(target, property) {
            return target[property];
        },
        set(target, property, value) {
            target[property] = value;

            return true;
        },
    });
}
</code></pre>
<p>One thing that we haven't covered in this function is nested <code>Proxy</code> instances. Imagine the following scenario:</p>
<pre><code class="language-js">const user = reactive({
    name: 'Ryan',
    address: {
        postcode: 'TT1 1TT'
    }
})

// How do we intercept this!?
user.address.postcode = 'TT2 2TT';
</code></pre>
<p>When we update <code>user.address.postcode</code>, the <code>set</code> handler in our <code>Proxy</code> won't be called as the <code>address</code> object inside of <code>user</code> isn't reactive.</p>
<p>Don't worry, this is easy to fix. We can recursively call <code>reactive</code> for each of the properties on our original <code>object</code> when they're <code>typeof</code> is <code>object</code>.</p>
<pre><code class="language-js">function reactive(object) {
    if (object === null || typeof object !== 'object') {
        return object;
    }

    for (const property in object) {
        object[property] = reactive(object[property])
    }

    return new Proxy(object, {
        get(target, property) {
            return target[property];
        },
        set(target, property, value) {
            target[property] = reactive(value);

            return true;
        },
    });
}
</code></pre>
<p>Voila! When the <code>object</code> passed into <code>reactive</code> has any nested objects, they will also be passed through <code>reactive</code> recursively.</p>
<p>When we <code>set</code> the value of a property, we'll also pass the <code>value</code> through <code>reactive</code> to ensure that any objects are wrapped in a <code>Proxy</code> too.</p>
<h2>Wrapping up</h2>
<p>And with that, we've created a semi-functional version of <code>Alpine.reactive()</code>. The only thing that our <code>reactive</code> function doesn't do yet is update or trigger any function calls.</p>
<p>We'll look at creating a basic version of <code>Alpine.effect()</code> in the next instalment.</p>
<p>Until then, thank you for reading and I'll catch you next time!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 18 Jun 2021 17:00:00 +0000</pubDate>
                                    <category>JavaScript</category>
                            </item>
                    <item>
                <title><![CDATA[Alpine 3.x tips and tricks]]></title>
                <link>https://ryangjchandler.co.uk/posts/alpine-3-tips-and-tricks</link>
                <description><![CDATA[<p>At the time of writing this article, Alpine Day has finished and <a href="https://github.com/alpinejs/alpine-next">Alpine 3.x</a> has only been out a few hours. Some of the cool things that came with the new release are:</p>
<ul>
<li><a href="https://alpinejs.dev">An official website</a>!</li>
<li><a href="https://alpinejs.dev/magics/store">First-party global stores</a>.</li>
<li>A new and improved <a href="https://alpinejs.dev/advanced/reactivity">reactivity engine</a>.</li>
<li>Improved <a href="https://alpinejs.dev/advanced/csp">CSP (Content-Security Policy) support</a>.</li>
<li>And much, much more...</li>
</ul>
<p>I've only had my hands on it for a few hours, just like everybody else, but I've already had a big dive through the source code and here are a couple of things I've found.</p>
<h2>1. Automatic <code>init</code> function calls</h2>
<p>The new documentation states that components powered by <code>Alpine.data</code> declarations that contain an <code>init</code> function will automatically have the <code>init</code> function called. This is great and saves you some time since you don't need to hook up the <code>x-init</code> directive.</p>
<p>After reading through the source code, it turns out you can actually add an <code>init</code> function to any data object and Alpine will still call that function automatically.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{
    init() {
        console.log('Here we go!')
    }
}&quot;&gt;&lt;/div&gt;
</code></pre>
<p>When this component is initialized, the <code>init</code> function will be called automatically and the <code>console.log</code> will appear in your DevTools.</p>
<h2>2. Clean up after yourself with <code>destroy</code></h2>
<p>Anybody familiar with PHP will likely know about the <code>__destruct</code> magic method. This method is called when an object is garbage collected, allowing you to clean up or free other resources manually.</p>
<p>Alpine 3.x also introduces a similar pattern for components through the use of <code>destroy</code> method. This method will be called when the component is removed from the DOM,</p>
<p>A good example might be a carousel or image gallery library that modifies the DOM outside of your component, or isn't handled directly by Alpine.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{
    init() {
        carouselLibrary.create();
    },
    destroy() {
        carouselLibrary.delete();
    }
}&quot;&gt;&lt;/div&gt;
</code></pre>
<p>Alpine will call the <code>destroy</code> method, allowing you to clean up after yourself.</p>
<p><strong>This feature hasn't been documented yet. Please use with caution.</strong></p>
<h2>3. Interact with global stores from external JavaScript</h2>
<p>This is something that Spruce supported to, so if you used that with Alpine 2.x you'll be familiar with this one.</p>
<p>Creating a store with <code>Alpine.store</code> allows you to access global state in your components using a <code>$store</code> property. That same <code>Alpine.store</code> method can be used to retrieve a store in your external scripts.</p>
<pre><code class="language-js">Alpine.store('counter', {
    count: 0
})
</code></pre>
<pre><code class="language-js">// In a different file or area.
Alpine.store('counter').count += 1
</code></pre>
<p>Calling <code>Alpine.store</code> with a single argument will return the <code>Proxy</code> instance for that particular store. Awesome, right?</p>
<h2>4. Independent <code>x-init</code> directives</h2>
<p>This one is mentioned <a href="https://alpinejs.dev/directives/init#standalone-x-init">in the documentation</a>, but you can declare <code>x-init</code> on its own, inside or outside of an Alpine component.</p>
<p>This was a question that got asked <em>so</em> much previously -- people were getting frustrated with adding <code>x-init</code> and nothing happening.</p>
<pre><code class="language-html">&lt;div x-data&gt;
    &lt;p x-init=&quot;console.log('I am ready!')&quot;&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;img src=&quot;...&quot; x-init=&quot;doSomeMagicHere()&quot;&gt;
</code></pre>
<p>This is great for elements that don't need any state and just need to call another method or third-party library on initialisation.</p>
<h2>5. Unfurl / unwrap <code>Proxy</code> with <code>Alpine.raw</code></h2>
<p>When debugging an issue in a component, 9 times out of 10 we turn to <code>console.log()</code>. This is fine in most cases. Other times, people get confused by the appearance of a <code>Proxy</code> in their console window.</p>
<p>This is somewhat annoying since expanding the object will give you <code>[[Target]]</code> and <code>[[Handler]]</code> which can be confusing.</p>
<p>To save you some confusion, you can use <code>Alpine.raw</code> inside of your <code>console.log()</code> calls. This method will unfurl / unwrap the <code>Proxy</code> instance created by Alpine and return the underlying value, i.e. the plain object, array, etc.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ user: { name: 'Ryan' } }&quot; x-init=&quot;console.log(user)&quot;&gt;
    &lt;!-- This produces a `Proxy` in the console --&gt;
&lt;/div&gt;

&lt;div x-data=&quot;{ user: { name: 'Ryan' } }&quot; x-init=&quot;console.log(Alpine.raw(user))&quot;&gt;
    &lt;!-- This produces the &quot;real&quot; `user` object in the console --&gt;
&lt;/div&gt;
</code></pre>
<hr />
<p>And that's it from me, at least for now. I'll be working hard over the next couple of weeks trying to find other tips and tricks. In the meantime you can find me on <a href="https://twitter.com/ryangjchandler">Twitter</a> and <a href="https://github.com/ryangjchandler">GitHub</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 11 May 2021 00:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Storing Laravel users on disk in flat-files]]></title>
                <link>https://ryangjchandler.co.uk/posts/storing-laravel-users-on-disk-in-flat-files</link>
                <description><![CDATA[<p><strong>I'm tired of generic SQL databases.</strong> I've become infactuated with flat-file systems where content and data is stored on disk and persisted between environments, whether that be an SQLite database that powers my application or plain Markdown files.</p>
<p>That is one of the main reasons why I built <a href="https://github.com/ryangjchandler/orbit">Orbit</a> - a flat-file &quot;database&quot; driver for Laravel's Eloquent ORM.</p>
<p>The main idea is that all of your content and data is stored inside of a &quot;content&quot; file but can still be used through a normal Eloquent <code>Model</code>, just like it would with a MySQL or Postgres database.</p>
<h2>The <code>User</code> model</h2>
<p>To start using Orbit, you'll need to install the Composer package in your Laravel application.</p>
<pre><code class="language-bash">composer require ryangjchandler/orbit
</code></pre>
<p>Orbit operates and bootstraps a model via the <code>Orbit\Concerns\Orbital</code> trait. This can be added to your <code>Model</code> class like this:</p>
<pre><code class="language-php">use Orbit\Concerns\Orbital;

class User extends Model
{
    use Orbital;
}
</code></pre>
<p>This is all you need to do for the model to be &quot;usable&quot;, but for it to function like a normal <code>User</code>, there are a couple of extra steps.</p>
<h2>The <code>schema</code> method</h2>
<p>Just like a model that's hooked up to a MySQL database, you should define a <code>schema</code>. This is what Orbit will use to determine what content is available in your flat-files and what should be accessible from the model.</p>
<p>It's essentially an &quot;up&quot; migration, written as part of your model's definition:</p>
<pre><code class="language-php">class User extends Model
{
    use Orbital;
  
    public static function schema(Blueprint $table)
    {

    }
}
</code></pre>
<p>Laravel provides a <code>users</code> table migration as standard, so we can take that existing migration and copy it into the <code>schema</code> method:</p>
<pre><code class="language-php">class User extends Model
{
    use Orbital;
  
    public static function schema(Blueprint $table)
    {
        $table-&gt;id();
        $table-&gt;string('name');
        $table-&gt;string('email')-&gt;unique();
        $table-&gt;timestamp('email_verified_at')-&gt;nullable();
        $table-&gt;string('password');
        $table-&gt;rememberToken();
    }
}
</code></pre>
<blockquote>
<p>Orbit will automatically add the <code>created_at</code> and <code>updated_at</code> columns to this schema if your <code>Model</code> class needs timestamps.</p>
</blockquote>
<p>And that's all there is to it. <strong>Really!</strong></p>
<p>If you were to open up a <code>tinker</code> session and type <code>User::create([...])</code>, you would see a new <code>content/users</code> directory in your application, as well as a new <code>1.md</code> file.</p>
<h2>Customising the primary key</h2>
<p>One thing that I like to do with these flat-file models is use a more descriptive &quot;key&quot; as the primary key. In the case of the <code>User</code> model, that's most likely going to be the <code>email</code> since it's always going to be unique.</p>
<p>To do this in Orbit, all you need to do is change the <code>$primaryKey</code> or overwrite the <code>getKeyName</code> method.</p>
<pre><code class="language-php">class User extends Model
{
    use Orbital;
  
    protected $primaryKey = 'email';
  
    public static function schema(Blueprint $table)
    {
        $table-&gt;string('name');
        $table-&gt;string('email')-&gt;unique();
        $table-&gt;timestamp('email_verified_at')-&gt;nullable();
        $table-&gt;string('password');
        $table-&gt;rememberToken();
    }
}
</code></pre>
<p>Now, when you create a new <code>User</code>, the file name will be the same as the <code>email</code> making it really easy to see which users already exist.</p>
<blockquote>
<p>Changing the primary key of a model will affect the foreign and local columns for your relationships. For example, if you use <code>email</code> column as your <code>User</code> model's primary key, Laravel will guess that the foreign column name is <code>user_email</code> on the related model when using <code>belongsTo</code> relation. You can change this by specifying the column names when you define the relationship.</p>
</blockquote>
<h2>Sign off</h2>
<p>If you're interested in Orbit and want to find out more, check out the <a href="https://github.com/ryangjchandler/orbit">GitHub repository</a>.</p>
<p>Thanks for reading this post!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 28 Mar 2021 11:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[How to schedule Artisan commands from your Laravel package]]></title>
                <link>https://ryangjchandler.co.uk/posts/how-to-schedule-artisan-commands-from-your-laravel-package</link>
                <description><![CDATA[<p>Before you can run your command on the scheduler, you need to make sure you've actually registered the command with <code>artisan</code>.</p>
<p>To do this, use the <code>$this-&gt;commands</code> method in your <code>ServiceProvider::boot</code> method.</p>
<pre><code class="language-php">class MyPackageServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this-&gt;commands([
            Commands\MyAwesomeCommand::class,
        ])
    }
}
</code></pre>
<p>By doing this, you can now run your command using <code>php artisan my-awesome-command</code>.</p>
<h2>Scheduling the command</h2>
<p>Now that <code>artisan</code> is aware of your command, you can hook it up to Laravel's <code>Schedule</code> and run it as often as you need.</p>
<p>Begin by calling <code>$this-&gt;app-&gt;afterResolving</code> in your <code>ServiceProvider::boot</code> method, passing through two arguments.</p>
<p>The first argument should be the abstract that is being resolved. In this case, that will be <code>Illuminate\Console\Scheduling\Schedule</code>. The second argument should be a <code>Closure</code> that accepts the object in its parameter list.</p>
<pre><code class="language-php">use Illuminate\Console\Scheduling\Schedule;

class MyPackageServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this-&gt;commands([
            Commands\MyAwesomeCommand::class,
        ])
		  
        $this-&gt;app-&gt;afterResolving(Schedule::class, function (Schedule $schedule) {
            $schedule-&gt;command(Commands\MyAwesomeCommand::class)-&gt;everyMinute();
        });
    }
}
</code></pre>
<p>Now when you run <code>php artisan schedule:run</code>, the <code>Closure</code> will be executed and <code>MyAwesomeCommand</code> will be added to the scheduler, running once every minute.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 21 Mar 2021 17:45:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Validating Laravel console input]]></title>
                <link>https://ryangjchandler.co.uk/posts/validating-laravel-console-input</link>
                <description><![CDATA[<p>Let's start off by creating a new console command. Run the following command in your terminal:</p>
<pre><code class="language-bash">php artisan make:command MakeUserCommand
</code></pre>
<p>This will create a new file in <code>app/Console/Commands</code> called <code>MakeUserCommand.php</code> with all of the normal command boilerplate. I've removed some of the cruft below for demonstration purposes.</p>
<pre><code class="language-php">&lt;?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class MakeUserCommand extends Command
{
    protected $signature = 'command:name';

    protected $description = 'Command description';

    public function handle()
    {
        return 0;
    }
}
</code></pre>
<h2>Retrieving user input</h2>
<p>Instead of asking for input up front when the user runs the command, I'll instead be using the <code>Command::ask()</code> method to get input during the command's run time.</p>
<p>Here's how you might get the name of the new user.</p>
<pre><code class="language-php">public function handle()
{
    $name = $this-&gt;ask('Name:');

    return 0;
}
</code></pre>
<p>When the command runs, the user will be shown the text provided as the method's first argument.</p>
<p>If you wanted to validate this input, all you need to do is pass the data through to a new <code>Validator</code> and handle any errors. Let's begin by creating a new <code>Validator</code> with the correct data and rules.</p>
<pre><code class="language-php">use Illuminate\Support\Facades\Validator;

public function handle()
{
    $name = $this-&gt;ask('Name:');
    
    $validator = Validator::make([
        'name' =&gt; $name,
    ], [
        'name' =&gt; ['required', 'string']    
    ]);

    return 0;
}
</code></pre>
<p>Now that the validator has been created, calling the <code>$validator-&gt;fails()</code> method will run the data against the rules provided and return a <code>bool</code>.</p>
<pre><code class="language-php">public function handle()
{
    $name = $this-&gt;ask('Name:');
    
    $validator = Validator::make([
        'name' =&gt; $name,
    ], [
        'name' =&gt; ['required', 'string']    
    ]);
    
    if ($validator-&gt;fails()) {
        // Do something here...
    }

    return 0;
}
</code></pre>
<p>Now that we know if the validation has failed or not, we can look into the errors and output them to the user.</p>
<pre><code class="language-php">public function handle()
{
    $name = $this-&gt;ask('Name:');
    
    $validator = Validator::make([
        'name' =&gt; $name,
    ], [
        'name' =&gt; ['required', 'string']    
    ]);
    
    if ($validator-&gt;fails()) {
        foreach ($validator-&gt;errors()-&gt;all() as $error) {
            $this-&gt;error($error);
        }
        
        return 1;
    }

    return 0;
}
</code></pre>
<p>And that's all there is to it! If somebody tries to enter an invalid name, the validation will fail and the errors will be output in the user's console.</p>
<p>If you went ahead and did this for the <code>email</code> too, you can be confident that the data being provided is valid.</p>
<h2>Improving the <code>ask</code> method</h2>
<p>The only problem with the basic approach I've shown is that the process exits if there is an error. If you've only got one piece of data being validated, this might be okay.</p>
<p>Imagine you've battled with the validation for the name and <em>finally</em> reach the <code>email</code> stage. If you fail the validation here, you need to go back to the beginning, put in your <code>name</code> again and then try the <code>email</code> again too.</p>
<p>One way we can tackle this is with recursion... <strong>dun dun dun</strong>!</p>
<h3>A new method</h3>
<p>Let's start by pulling all of the validation logic into a new helper method on the class.</p>
<pre><code class="language-php">public function askWithValidation(
    string $message, array $rules = [], string $name = 'value'
) {

}
</code></pre>
<p>This new method will handle all of the validation, as well as the error displaying. Start by asking the question and instantiating a validator, just like before</p>
<pre><code class="language-php">public function askWithValidation(
    string $message, array $rules = [], string $name = 'value'
) {
    $answer = $this-&gt;ask($message);
    
    $validator = Validator::make([
        $name =&gt; $answer,
    ], [
        $name =&gt; $rules,
    ]);
}
</code></pre>
<blockquote>
<p>This method is going to be re-usable, so instead of hardcoding the key in each array, we'll let the developer pass in a custom <code>$name</code> (defaulted to <code>value</code>).</p>
</blockquote>
<p>Instead of calling <code>$validator-&gt;fails()</code>, we can actually use the inverse operation, <code>$validator-&gt;passes()</code> and return early if that returns <code>true</code>.</p>
<pre><code class="language-php">public function askWithValidation(
    string $message, array $rules = [], string $name = 'value'
) {
    $answer = $this-&gt;ask($message);
    
    $validator = Validator::make([
        $name =&gt; $answer,
    ], [
        $name =&gt; $rules,
    ]);
    
    if ($validator-&gt;passes()) {
        return $answer;
    }
}
</code></pre>
<p>Early returns are just <em>cleaner</em>, right?</p>
<p>If the condition fails, we can go through and check for any errors and display them to the user.</p>
<pre><code class="language-php">public function askWithValidation(
    string $message, array $rules = [], string $name = 'value'
) {
    $answer = $this-&gt;ask($message);
    
    $validator = Validator::make([
        $name =&gt; $answer,
    ], [
        $name =&gt; $rules,
    ]);
    
    if ($validator-&gt;passes()) {
        return $answer;
    }
    
    foreach ($validator-&gt;errors()-&gt;all() as $error) {
        $this-&gt;error($error);
    }
}
</code></pre>
<p>Now for the recursion. If the validation fails and errors are shown to the user, instead of returning and exiting the process, we can instead <code>return $this-&gt;askWithValidation</code> so that the user is asked the same question again.</p>
<pre><code class="language-php">public function askWithValidation(
    string $message, array $rules = [], string $name = 'value'
) {
    $answer = $this-&gt;ask($message);
    
    $validator = Validator::make([
        $name =&gt; $answer,
    ], [
        $name =&gt; $rules,
    ]);
    
    if ($validator-&gt;passes()) {
        return $answer;
    }
    
    foreach ($validator-&gt;errors()-&gt;all() as $error) {
        $this-&gt;error($error);
    }
    
    return $this-&gt;askWithValidation($message, $rules, $name);
}
</code></pre>
<p>And there you have it! Validated user input inside of your console commands.</p>
<p>I've create a little Gist with a <code>trait</code> that you can pull into any of your console commands <a href="https://gist.github.com/ryangjchandler/1c579774cc2c2c5fda421f3374e4a01c">here</a>.</p>
<h2>Sign off</h2>
<p>Used something similar in your application or package? Let me know on <a href="https://twitter.com/ryangjchandler">Twitter</a>.</p>
<p>Thanks for reading!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 02 Mar 2021 18:30:00 +0000</pubDate>
                                    <category>Livewire</category>
                            </item>
                    <item>
                <title><![CDATA[Flashing banner messages in your Laravel Jetstream and Livewire applications]]></title>
                <link>https://ryangjchandler.co.uk/posts/flashing-banner-messages-in-your-laravel-jetstream-and-livewire-applications</link>
                <description><![CDATA[<blockquote>
<p>This article assumes you've already got a <a href="https://jetstream.laravel.com/">Laravel Jetstream</a> application setup and that you are using the <a href="https://laravel-livewire.com">Livewire</a> stack. If you haven't, read the official documentation on <a href="https://jetstream.laravel.com/2.x/installation.html">how to get started</a>.</p>
</blockquote>
<h2>The <code>&lt;x-jet-banner&gt;</code> component</h2>
<p>Jetstream comes jam-packed with lots of goodies. One of those goodies is an <code>&lt;x-jet-banner&gt;</code> component. If you're using the default <code>layouts.app</code> layout that comes with Jetstream, you might have already seen this. It can be found at the very start of the <code>&lt;body&gt;</code> tag:</p>
<pre><code class="language-html">&lt;body class=&quot;font-sans antialiased&quot;&gt;
    &lt;x-jet-banner /&gt;
</code></pre>
<p>If you're using a different layout file, go ahead and include this Blade component somewhere in your markup.</p>
<p>A brief look at the component itself shows that it's powered by Alpine and support 2 different styles out of the box. A <strong>success</strong> style, as well as an <strong>error/danger</strong> style.</p>
<p>This is perfect for 99% of applications since you either want to say something is good or bad.</p>
<p>You might also notice that there is an <code>@props</code> declaration at the top of the component file:</p>
<pre><code class="language-blade">@props(['style' =&gt; session('flash.bannerStyle', 'success'), 'message' =&gt; session('flash.banner')])
</code></pre>
<p>This is where the component gets all of the information for what type of banner should be shown as well as the message.</p>
<h2>Flashing a message</h2>
<p>Since we know the component is looking for the message and style in the session, all we need to do is flash these pieces of information to the session.</p>
<p>In a Livewire component, you might use the <code>session()</code> helper or go through the <code>request()</code> helper instead.</p>
<pre><code class="language-php">public function banner(string $message, string $style = 'success')
{
    request()-&gt;session()-&gt;flash('flash.banner', $message);
    request()-&gt;session()-&gt;flash('flash.bannerStyle', $style);
}
</code></pre>
<p>Add this method to your component and use it yourself!</p>
<pre><code class="language-php">public function save()
{
    // Some save logic goes here, I guess.
  
    $this-&gt;banner('Successfully saved!');
}
</code></pre>
<h2>A reusable trait</h2>
<p>If you want to re-use this throughout multiple components, you might wish to extract the method into a <code>trait</code> that can be used on your components.</p>
<p>Here's the one I use.</p>
<pre><code class="language-php">namespace App\Support\Concerns;

trait InteractsWithBanner
{
    public function banner(string $message, string $style = 'success')
    {
        request()-&gt;session()-&gt;flash('flash.banner', $message);
        request()-&gt;session()-&gt;flash('flash.bannerStyle', $style);
    }
}
</code></pre>
<blockquote>
<p>For these sort of traits, I don't put them inside of the <code>App/Http/Livewire</code> folder because they're not reliant on Livewire specific methods. I could add this to anything in my application and it would still do the same thing.</p>
</blockquote>
<p>Now you can use this trait in your Livewire component instead:</p>
<pre><code class="language-php">use App\Support\Concerns\InteractsWithBanner;

class SaveForm extends Component
{
    use InteractsWithBanner;
}
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 15 Feb 2021 14:35:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[How to customise the logo in Your Laravel Jetstream application]]></title>
                <link>https://ryangjchandler.co.uk/posts/how-to-customise-the-logo-in-your-laravel-jetstream-application</link>
                <description><![CDATA[<blockquote>
<p>This article assumes you've already got a <a href="https://jetstream.laravel.com/">Laravel Jetstream</a> application setup. If you haven't, read the official documentation on <a href="https://jetstream.laravel.com/2.x/installation.html">how to get started</a>.</p>
</blockquote>
<h2>Publishing Jetstream's views</h2>
<p>Although Jetstream publishes quite a few things into your application, it doesn't publish views by default. The main reason for this is it's much easier to rollout bug fixes or new features if the views are registered inside of the package.</p>
<p>You can publish them yourself however by running the following command:</p>
<pre><code class="language-bash">php artisan vendor:publish --tag=jetstream-views
</code></pre>
<p>This will publish all of Jetstream's views into <code>resources/views/vendor/jetstream</code>.</p>
<h2>Changing the logo</h2>
<p>The steps needed here depend on which stack you have chosen.</p>
<h3>Livewire</h3>
<p>To use a custom logo, you'll need to customise three files:</p>
<ol>
<li><code>resources/views/vendor/jetstream/components/application-logo.blade.php</code></li>
<li><code>resources/views/vendor/jetstream/components/application-mark.blade.php</code></li>
<li><code>resources/views/vendor/jetstream/components/authentication-card-logo.blade.php</code></li>
</ol>
<p>Each of these files will contain an SVG. Replace this markup with your own logo (another SVG or even an <code>&lt;img&gt;</code> tag).</p>
<blockquote>
<p>If you use an SVG, be sure to add the <code>{{ $attributes }}</code> on to the <code>&lt;svg&gt;</code> tag so that any attributes passed through to the component are still rendered.</p>
</blockquote>
<h3>Inertia</h3>
<p>You'll need to customise three files for Inertia too:</p>
<ol>
<li><code>resources/js/Jetstream/ApplicationLogo.vue</code></li>
<li><code>resources/js/Jetstream/ApplicationMark.vue</code></li>
<li><code>resources/js/Jetstream/AuthenticationCardLogo.vue</code></li>
</ol>
<p>Much like the Livewire stack, just replace the SVG markup with your own SVG or an <code>&lt;img&gt;</code> tag.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 14 Feb 2021 20:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[How Puny works under the hood]]></title>
                <link>https://ryangjchandler.co.uk/posts/how-puny-works-under-the-hood-the-basics</link>
                <description><![CDATA[<h2>Introduction</h2>
<p>For those of you who don't know, or haven't heard about it, <a href="https://github.com/ryangjchandler/puny">Puny</a> is my very own unit testing library.</p>
<p>Unlike PHPUnit et al, it's designed with minimalism as its main goal. There are only a handful (literally) of standard functions provided by Puny and it really makes you think differently about how you test your applications or packages.</p>
<p>The best way to showcase Puny is by writing a simple unit test for a <code>StringFormatter</code> class.</p>
<pre><code class="language-php">class StringFormatter
{
    public static function upper(string $input)
    {
        return strtoupper($input);
    }
}
</code></pre>
<p>All this method does is wrap the <code>strtoupper()</code> function, but it's a good way of showcasing the testing utilities.</p>
<p>Normally my test files can be found in a <code>tests</code> directory at the root of my project. By default, Puny will try to look for this folder.</p>
<p>Since we're unit testing, it's also common practice to test each component or concept inside of its own file, so I'll create a new file called <code>tests/StringFormatter.php</code>.</p>
<p>Puny provides a <code>Puny\test</code> function that can be used to register a new test.</p>
<pre><code class="language-php">use function Puny\test;

test('it can convert a string to uppercase', function () {

});
</code></pre>
<p>The <code>Puny\test</code> function accepts <strong>two arguments</strong>, the first is the name of the test itself (a description of what you will be testing) and the second is a <code>callable</code> / <code>Closure</code> that actually performs the test's logic.</p>
<p>In this case, we'll be calling <code>StringFormatter::upper()</code> and checking that the return value is suitable.</p>
<pre><code class="language-php">use function Puny\{test, ok};

test('it can convert a string to uppercase', function () {
    ok(StringFormatter::upper('hello') === 'HELLO', 'it converts correctly');
});
</code></pre>
<p>Here I'm using the <code>Puny\ok</code> function to make sure that something is, you guessed it, &quot;ok&quot;. All it really does is check that the first argument is <code>true</code> or <code>false</code>.</p>
<p>If it's <code>true</code> it doesn't do anything at all. If it's <code>false</code>, it will print out an error in the console.</p>
<p>The second argument is a sub-description of the specific assertion being made. This will be used in the error output so that you can quickly find the right failing assertion.</p>
<h3>A better equality helper</h3>
<p>Instead of writing out a <code>bool</code> condition for the <code>Puny\ok</code> helper, you could instead use the <code>Puny\eq</code> helper function. This is just a shorthand for comparing two operands.</p>
<pre><code class="language-php">use function Puny\{test, eq};

test('it can convert a string to uppercase', function () {
    eq(StringFormatter::upper('hello'), 'HELLO', 'it converts correctly');
});
</code></pre>
<p>It's almost identical. You just don't need to worry about writing the <code>===</code> (or <code>==</code> if you're a menace) yourself.</p>
<blockquote>
<p>It's worth noting that the <code>Puny\eq</code> helper will always make <strong>strict comparisons</strong>. If this isn't fit for your use case, just use <code>Puny\ok</code>.</p>
</blockquote>
<h2>How it all works</h2>
<p>It all starts with the Puny CLI. This is a file installed with the Composer package that you can use to actually run your tests. It's only responsible for invoking the <code>Puny::run()</code> and setting the correct tests folder method.</p>
<p>As I mentioned previously, Puny will default to using a <code>tests</code> folder in your current working directory (according to <code>getcwd()</code>). This is a great default and makes running the command easier since you don't need to pass in any options or arguments.</p>
<blockquote>
<p>You can specify a custom folder by passing in an argument to the command - <code>puny ./tests-folder</code>.</p>
</blockquote>
<h3>Bootstrapping</h3>
<p>Puny does include some niceties for running some logic before your entire test suite. If it encounters a <code>bootstrap.php</code> file in the root of your <code>tests</code> folder, it will include that file.</p>
<p>This means you can setup singleton classes, bind things to a container or anything else that you might need to use throughout your test suite.</p>
<h3>Discovering tests</h3>
<p>Once Puny knows where the tests are located, it walks through that directory recursively and will include any PHP files it finds. The interesting thing here is that the tests themselves (registered using <code>Puny\test</code>) aren't actually being run quite yet.</p>
<p>Calling the <code>Puny\test</code> function will actually call an internal <code>Puny::register</code> method. This method places the test inside of a single array on the main <code>Puny\Puny</code> instance. This is possible because of how PHP evaluates an entire file when it is imported using <code>include</code> or <code>require</code>.</p>
<p>This happens for each test file and eventually, once all folders have been walked and all files have been included, Puny is left with an array of test names and callbacks.</p>
<blockquote>
<p>By building up this array, it implicitly forces test names to be unique. If two different files both have a test with the same name, only the last test file to be included will <em>actually</em> be run because it overwrites the earlier test.</p>
</blockquote>
<h3>Running tests</h3>
<p>Now that there is a collection of tests to run, Puny will loop over this array and invoke each <code>callable</code> / <code>Closure</code>.</p>
<p>Each callback is invoked inside of a <code>try / catch</code> block. This means that any exceptions thrown by the test will be caught by Puny and can therefore be handled in a special way.</p>
<p>This is exactly how the <code>Puny\ok</code>, <code>Puny\eq</code> and <code>Puny\skip</code> function work. I'll use <code>Puny\ok</code> as an example:</p>
<pre><code class="language-php">function ok(bool $check, string $id) {
    if (! $check) {
        throw new NotOkException($id);
    }

    return true;
}
</code></pre>
<p>This is the code for the <code>Puny\ok</code> helper. All it does is check if the <code>$check</code> is <code>false</code> (falsy) and throws an exception if it is.
Puny can then register a catch block for this exception, <code>NotOkException</code> and handle it accordingly.</p>
<pre><code class="language-php">try {
    $callback();
} catch (NotOkException $e) {
    Console::error(&quot;Failed: {$e-&gt;getMessage()}&quot;);
  
    $this-&gt;failed++;
}
</code></pre>
<p>The exception is being handled so it will never be reported to the user in the console. Instead Puny uses its own output to notify the user of a failure and also increase a counter for the number of failed tests.</p>
<p>The benefit to this approach is that the rest of the test suite can still be run whilst notifying the user of any failures.</p>
<p>The <code>Puny\eq</code> function uses the <code>Puny\ok</code> function internally, so there's no special conditions needed for that.</p>
<p>For the <code>Puny\skip</code> function to work, all we need to add is another <code>catch</code> block for a different exception:</p>
<pre><code class="language-php">try {
    $callback();
} catch (NotOkException $e) {
    Console::error(&quot;Failed: {$e-&gt;getMessage()}&quot;);
  
    $this-&gt;failed++;
} catch (SkippedException $e) {
    Console::warning(&quot;Skipped: {$name}&quot;);
  
    $this-&gt;skipped++;
  
  	continue;
}
</code></pre>
<p>The <code>Puny\skip</code> function can then throw a new <code>SkippedException</code> when it's called.</p>
<pre><code class="language-php">function skip() {
    throw new SkippedException;
}
</code></pre>
<p>Calling the <code>Puny\skip</code> function will also report back to the user in the console and <code>continue</code> the <code>foreach</code> loop, moving on to the next test.</p>
<h2>Conclusion</h2>
<p>And that's all there is to it. Kind of, anyway. I've gone over the basic inner workings of Puny in this article but I'll be writing a follow-up in a couple of weeks that goes over how the <code>Puny\spy</code> helper function works.</p>
<p>If you are interested in giving Puny a try, head over to the <a href="https://github.com/ryangjchandler/puny">GitHub repository</a> for more information.</p>
<p>If you've already used Puny, I'd love to know so message me on <a href="https://twitter.com/ryangjchandler">Twitter</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 05 Feb 2021 12:00:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Deploy an AWS Lambda function from the terminal]]></title>
                <link>https://ryangjchandler.co.uk/posts/deploy-an-aws-lambda-function-from-the-terminal</link>
                <description><![CDATA[<p>My last article gave a quick run-down on <a href="https://ryangjchandler.co.uk/articles/execute-an-aws-lambda-function-from-the-terminal">how you can invoke a Lambda function from your terminal</a>. I've had a few people message me asking how I deploy / upload my Lambda functions to AWS.</p>
<p>Here is how I do it.</p>
<h2>Zipping up your code</h2>
<p>When you upload your Lambda function, you'll want to provide a ZIP file that contains all of the necessary code. I mostly write Node functions these days, so my ZIP files generally contain a <code>node_modules</code> folder, an <code>index.js</code> file and a <code>package.json</code> file too so I can quickly check what dependencies I'm using from the Lambda UI.</p>
<p>On UNIX machines, you can use the <code>zip</code> command to generate a ZIP file. As an example, you might run something like this:</p>
<pre><code class="language-bash">zip -r function.zip .
</code></pre>
<p>This command will create a new <code>function.zip</code> file, compressing the contents of the current directory (or <code>.</code>).</p>
<p>If you need to exclude some files, you can use the <code>-x</code> option. This is handy if you have a generic <code>input.json</code> or <code>output.json</code> file, as described in my <a href="https://ryangjchandler.co.uk/articles/execute-an-aws-lambda-function-from-the-terminal">other article</a>.</p>
<pre><code class="language-bash">zip -r function.zip . -x output.json input.json
</code></pre>
<h2>Deploying to AWS</h2>
<p>Now that we've got a ZIP file with our Lambda function's dependencies and handler, we can finally deploy to AWS. AWS have, surprisingly, made this very simple using the <a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html">AWS CLI</a>.</p>
<pre><code class="language-bash">aws lambda update-function-code --function-name NameOfFunctionHere
</code></pre>
<p>We haven't told the AWS CLI what to deploy though. In our case it will be a ZIP file, so let's use the <code>--zip-file</code> option and specify the correct file.</p>
<pre><code class="language-bash">aws lambda update-function-code --function-name NameOfFunctionHere --zip-file fileb://function.zip
</code></pre>
<p>The <code>fileb://</code> protocol is used because we're uploading binary data.</p>
<h2>Condensing this down</h2>
<p>You might have already guessed it, but I don't actually type out this entire command each time. I like putting these commands inside of NPM &quot;scripts&quot; so that I can quickly run them with <code>npm run</code> or <code>yarn</code>.</p>
<pre><code class="language-json">{
    &quot;scripts&quot;: {
        &quot;zip&quot;: &quot;zip -r function.zip . -x output.json input.json&quot;,
        &quot;deploy&quot;: &quot;npm run zip &amp;&amp; aws lambda update-function-code --function-name NameOfFunctionHere --zip-file fileb://function.zip&quot;
    }
}
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 02 Feb 2021 11:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Execute an AWS Lambda function from the terminal]]></title>
                <link>https://ryangjchandler.co.uk/posts/execute-an-aws-lambda-function-from-the-terminal</link>
                <description><![CDATA[<h2>Getting started</h2>
<p>Before you go any further, you want to make sure you've got the AWS CLI installed. If you haven't already got it installed, you can follow the <a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html">official instructions here</a>.</p>
<h2>Generating a payload</h2>
<p>Unfortunately, the AWS CLI can't accept the raw contents of a file as the payload when invoking a Lambda function. Instead, you need to generate a base 64 encoded version of the file.</p>
<p>On Unix systems, this can be done using the <code>base64</code> command. I typically store my generic payload inside of a <code>payload-raw.json</code> file and then output the base 64 encoded version to <code>payload.json</code>.</p>
<pre><code class="language-bash">base64 payload-raw.json
</code></pre>
<p>This command will encode the raw JSON into base 64. To output the result of this command, we can just redirect <code>stdout</code> into a file.</p>
<pre><code class="language-bash">base64 payload-raw.json &gt; payload.json
</code></pre>
<h2>Invoke the Lambda</h2>
<p>You can invoke your Lambda function using the <code>aws lambda</code> command. This command requires a few options so that it knows which function to execute.</p>
<pre><code class="language-bash">aws lambda \
--function-name NameOfFunctionHere
</code></pre>
<p>If we want to send through our base 64 encoded payload, we can use the <code>--payload</code> option and specify the file that needs to be used.</p>
<pre><code class="language-bash">aws lambda \
--function-name NameOfFunctionHere
--payload file://payload.json
</code></pre>
<p>You need to prefix the file with <code>file://</code> protocol as the AWS CLI also supports sending payloads using <code>http://</code> and <code>https://</code>.</p>
<p>If you want to save the output of the execution to a file, you can specify the output file at the end of the command.</p>
<pre><code class="language-bash">aws lambda \
--function-name NameOfFunctionHere
--payload file://payload.json
output.json
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 28 Jan 2021 20:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[3 simple Tailwind CSS tips and tricks]]></title>
                <link>https://ryangjchandler.co.uk/posts/3-simple-tailwind-css-tips-and-tricks</link>
                <description><![CDATA[<h2>1. Always know the current breakpoint</h2>
<p>Finding it hard to remember what breakpoint you're currently viewing your screen at? Struggle no more!</p>
<p>Install the <code>tailwindcss-debug-screens</code> plugin and you'll be provided with a small visual helper in the bottom-left of your site.</p>
<p>Run this command in your project directory:</p>
<pre><code class="language-bash">npm install tailwindcss-debug-screens --save-dev
</code></pre>
<p>Then register the plugin in your Tailwind configuration file:</p>
<pre><code class="language-js">module.exports = {
    //...
    plugins: [
        require('tailwindcss-debug-screens'),
    ]
}
</code></pre>
<p>And finally add the new <code>debug-screens</code> class to your <code>&lt;body&gt;</code> tag:</p>
<pre><code class="language-html">&lt;body class=&quot;debug-screens&quot;&gt;
</code></pre>
<blockquote>
<p>You should ensure that this class is only added to the <code>&lt;body&gt;</code> in development. Wrap the class inside of a conditional or exclude the plugin at part of your build process.</p>
</blockquote>
<h2>2. Create a visual breakpoint separator</h2>
<p>This is definitely one that you can start implementing in your project. Have you ever seen any class lists like this?</p>
<pre><code class="language-html">&lt;h1 class=&quot;text-xl text-gray-500 focus:text-gray-800 hover:text-gray-800 mb-1 sm:text-2xl sm:mb-2 md:text-3xl md:mb-4 xl:text-5xl&quot;&gt;
</code></pre>
<p>These can get rather large, rather quickly. As they get larger and more breakpoint-specific classes come into play, it can get harder to see each breakpoints styles.</p>
<p>One trick that I like to use is inserting a style-less / marker class between each breakpoints section.</p>
<pre><code class="language-html">&lt;h1 class=&quot;text-xl text-gray-500 focus:text-gray-800 hover:text-gray-800 mb-1 | sm:text-2xl sm:mb-2 | md:text-3xl md:mb-4 | xl:text-5xl&quot;&gt;
</code></pre>
<p>In this case, I'm using a single <code>|</code> as the marker for a new breakpoint. It gives each section some breathing room but also provides a visual indicator for where a new screen definition starts.</p>
<blockquote>
<p>You could use any valid CSS class here instead, but a <code>|</code> is very common for separating things in many contexts.</p>
</blockquote>
<h2>3. Give your text editor / IDE some Tailwind love</h2>
<p>There are plenty of great extensions out there for improving your Tailwind development experience. Here are some of my favourites and ones I would highly recommend to any Tailwind developer.</p>
<h3><a href="https://tailwindcss.com/docs/intellisense">Tailwind CSS Intellisense for VS Code</a></h3>
<p>This is an official extension for Visual Studio Code and comes with some really, <em>really</em> neat features.</p>
<ul>
<li>Autocompletion for class names and CSS functions.</li>
<li>Linting of your classes and CSS files.</li>
<li>Syntax highlighting of custom Tailwind directives.</li>
<li>Hover previews that show entire CSS definitions for CSS classes.</li>
</ul>
<p>I think it's great when a project develops a first-party extension for their own tool. It adds a certain degree of reliability and trust.</p>
<h3><a href="https://marketplace.visualstudio.com/items?itemName=heybourn.headwind">Headwind</a></h3>
<p>Headwind is a Tailwind class sorter extension for Visual Studio Code. The documentation states that <em>&quot;It enforces consistent ordering of classes by parsing your code and reprinting class tags to follow a given order&quot;</em>.</p>
<p>I've been using this one for quite a while now and once you get used to the order, it can make finding a class in a long list much easier.</p>
<blockquote>
<p>If you're a PhpStorm user, you can get a <a href="https://plugins.jetbrains.com/plugin/13376-tailwind-formatter">Headwind port plugin here</a>.</p>
</blockquote>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 24 Jan 2021 17:00:00 +0000</pubDate>
                                    <category>Tailwind CSS</category>
                            </item>
                    <item>
                <title><![CDATA[3 simple Alpine.js tips and tricks]]></title>
                <link>https://ryangjchandler.co.uk/posts/5-simple-alpinejs-tips-and-tricks</link>
                <description><![CDATA[<blockquote>
<p>This article has been written based on functionality in Alpine.js v2.x - when a new major version is released or any of these tips are no longer applicable, I'll be sure to update it.</p>
</blockquote>
<h2>1. Keep your components small</h2>
<p>When Alpine encounters a new component or some of your state changes, it walks the DOM tree of that component. This means that if you have a larger component, you might notice an impact on performance because there is more DOM to walk.</p>
<p>This is why it's always a good idea to keep your markup small and avoid putting <code>x-data</code> attributes on the <code>&lt;body&gt;</code>, especially when you've got a big page.</p>
<p>You'll probably notice a performance impact on <em>huge</em> components, but it's always good to keep in mind because each small performance impact adds up to a larger one.</p>
<h2>2. Extract helpers into mixins</h2>
<p>Since Alpine.js uses a regular JavaScript object, we can take advantage of the &quot;spread&quot; operator. This means we can compose an object using the return value of multiple functions or separate object literals.</p>
<p>Here's an example:</p>
<pre><code class="language-html">&lt;form x-data=&quot;{ ...validationHelpers(), name: '' }&quot; @submit.prevent=&quot;validate({ name: 'required' })&quot;&gt;
    &lt;input x-model=&quot;name&quot; name=&quot;name&quot; id=&quot;name&quot;&gt;
&lt;/form&gt;
</code></pre>
<p>Here is what the <code>validationHelpers</code> function might look like:</p>
<pre><code class="language-js">function validationHelpers() {
    return {
        validate(rules) {
            Object.entries(rules).forEach(([field, rules]) =&gt; { ... });
        }
    }
}
</code></pre>
<p>The <code>...</code> operator will take the entries from the object returned by <code>validationHelpers</code> and add them to our data object. This lets us use them directly in our component whilst keeping the logic separated from the component's own.</p>
<p>The validation example is definitely a good use-case for this sort of thing. You might also use it for transition helpers, class name generators and a plethora of other things.</p>
<h2>3. Alpine.js DevTools</h2>
<p>If you didn't already know, there is a third-party Chrome and Firefox extension that provides some handy DevTools for Alpine. You can see all of the components on the page, inspect the data for each one and even modify it in real-time.</p>
<p>Soon you'll also be able to watch for any Alpine related errors, track events being dispatched by components and more.</p>
<p>If you don't already have it installed, follow the <a href="https://github.com/alpine-collective/alpinejs-devtools">instructions in the repository</a>!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 18 Jan 2021 12:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[5 simple Laravel tips and tricks]]></title>
                <link>https://ryangjchandler.co.uk/posts/5-simple-laravel-tips-and-tricks</link>
                <description><![CDATA[<h2>1. Chained <code>dd</code> and <code>dump</code></h2>
<p>Have you ever written a block of code like this?</p>
<pre><code class="language-php">$users = User::all();

dd($users);
</code></pre>
<p>It's not awful, but it is annoying that you <em>need</em> to assign the result of <code>User::all()</code> (an instance of <code>Collection</code>) to a variable just to dump and die. Turns out, you don't actually <em>need</em> to. Instead, you can use the <code>dd</code> or <code>dump</code> method on the <code>Collection</code> class instead and turn this into a one-liner.</p>
<pre><code class="language-php">User::all()-&gt;dd();
</code></pre>
<h2>2. <code>Auth::id()</code></h2>
<p>I wrote a tweet about this one a little while ago and it seemed like a lot of people didn't know about it.</p>
<blockquote>
<p>🔥 I still see so many people retrieving the current user's ID as shown at the top of the image. Take a shortcut and use the <code>Auth::id()</code> method instead! <a href="https://t.co/P7eB1PJrt2">https://t.co/P7eB1PJrt2</a></p>
<p><a href="https://twitter.com/ryangjchandler/status/1286316647385636864/photo/1"><img src="https://pbs.twimg.com/media/EdnqD4AXoAIcrx3.png?name=thumb" alt="" /></a></p>
<p>— Ryan Chandler (<a href="https://twitter.com/ryangjchandler">@ryangjchandler</a>) <a href="https://twitter.com/ryangjchandler/status/1286316647385636864">Jul 23, 2020</a></p>
</blockquote>
<p>I think my favourite thing about using this method is that you don't need to worry about accessing the <code>id</code> property on a <code>null</code> object, you can just use <code>Auth::id()</code> and it will return <code>null</code> when the user is logged out.</p>
<h2>3. Default Relationship Models</h2>
<p>Laravel provides a handy <code>withDefault()</code> method on the <code>belongsTo</code> relationship that will return a model object even when the relationship doesn't actually exist.</p>
<pre><code class="language-php">class Post extends Model
{
    public function user()
    {
        return $this-&gt;belongsTo(User::class)-&gt;withDefault();
    }
}
</code></pre>
<p>Now, if we try to access the <code>$post-&gt;user</code> relationship, we'll still get a <code>User</code> object even when it does exist in the database. This is known as the &quot;null object&quot; pattern and helps eliminate some of those <code>if ($post-&gt;user)</code> conditional statements.</p>
<p>There's a few different things you can do with <code>withDefault()</code>, you can read more about it <a href="https://laravel.com/docs/8.x/eloquent-relationships#default-models">here in the documentation</a>.</p>
<h2>4. Custom Blade Directives</h2>
<p>I don't use custom Blade directives all too often, but when I do it definitely makes my views look nicer. One example of a Blade directive that I use across multiple projects is <code>@nl2br</code></p>
<pre><code class="language-blade">&lt;h3&gt;Notes&lt;/h3&gt;

@foreach($notes as $note)
    &lt;p&gt;@nl2br($note-&gt;content)&lt;/p&gt;
@endforeach
</code></pre>
<p>Creating your own Blade directive really isn't difficult. Here's what the <code>@nl2br</code> one looks like:</p>
<pre><code class="language-php">Blade::directive('nl2br', function ($expression) {
    return &quot;&lt;?php echo nl2br(e({$expression})) ?&gt;&quot;;
});
</code></pre>
<p>Under the hood, Blade transforms a Blade directive into a PHP string (or expression). In this case, we're writing the PHP code necessary to print out the result of <code>nl2br</code>.</p>
<p>The callback function accepts an <code>$expression</code> argument. This is what was passed to the directive as arguments. In the example above, that would be <code>$note-&gt;content</code> as a string.</p>
<p>That confuses people quite a bit, because they expect <code>$expression</code> to be the return value of <code>$note-&gt;content</code>, when in fact is it a literal string with the contents <code>$note-&gt;content</code>:</p>
<pre><code class="language-php">$expression = '$note-&gt;content';
</code></pre>
<h2>5. Better Intellisense</h2>
<p>This isn't something related to your code directly, but it can definitely make it faster to write.</p>
<h3>PhpStorm</h3>
<p>If you're one of the PhpStorm crowd, you've probably already got the Laravel extension installed. If you're looking for something a little more powerful, and premium, you should definitely check out <a href="https://plugins.jetbrains.com/plugin/13441-laravel-idea">LaravelIdea</a>.</p>
<p>This extension provides auto-complete for basically everything cool and awesome in Laravel. View names, config names, Blade component tags and more.</p>
<h3>Visual Studio Code</h3>
<p>I've been using <a href="https://marketplace.visualstudio.com/items?itemName=amiralizadeh9480.laravel-extra-intellisense">Laravel Extra Intellisense</a> for a little while now and it has definitely given me a speed boost when it comes to getting the right view, configuration value or route name.</p>
<p>It's free, pretty powerful and feels just like any other intellisense plugin.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 17 Jan 2021 12:00:00 +0000</pubDate>
                                    <category>Tips &amp; Tricks</category>
                            </item>
                    <item>
                <title><![CDATA[Highlight Laravel Blade templates with Highlight.php]]></title>
                <link>https://ryangjchandler.co.uk/posts/highlight-laravel-blade-templates-with-highlightphp</link>
                <description><![CDATA[<p>Before we begin, this blog posts assumes you already have <a href="https://github.com/scrivo/highlight.php">Highlight.php</a> setup in your application. If you don't already have it setup, consult the <a href="https://github.com/scrivo/highlight.php">official documentation</a> or look into alternatives such as <a href="https://github.com/spatie/commonmark-highlighter"><code>commonmark-highlighter</code></a> that use this library under the hood.</p>
<h2>The syntax</h2>
<p>Highlight.php uses JSON files for syntax definitions, where as Highlight.js uses JavaScript files. This is just down to the fact that one is written in PHP where JavaScript evaluation is basically impossible and the other is a JavaScript library, so JavaScript can be used for configuration.</p>
<p>Here is the JSON file for the Blade syntax definition:</p>
<pre><code class="language-json">{
    &quot;case_insensitive&quot;: true,
    &quot;subLanguage&quot;: &quot;xml&quot;,
    &quot;contains&quot;: [
        {
            &quot;className&quot;: &quot;comment&quot;,
            &quot;begin&quot;: &quot;\\{\\{--&quot;,
            &quot;end&quot;: &quot;--\\}\\}&quot;
        },
        {
            &quot;className&quot;: &quot;template-variable&quot;,
            &quot;begin&quot;: &quot;\\{\\{&quot;,
            &quot;starts&quot;: {
                &quot;end&quot;: &quot;\\}\\}&quot;,
                &quot;returnEnd&quot;: true,
                &quot;subLanguage&quot;: &quot;php&quot;
            }
        },
        {
            &quot;className&quot;: &quot;template-variable&quot;,
            &quot;begin&quot;: &quot;\\}\\}&quot;
        },
        {
            &quot;className&quot;: &quot;template-variable&quot;,
            &quot;begin&quot;: &quot;\\{!!&quot;,
            &quot;starts&quot;: {
                &quot;end&quot;: &quot;!!\\}&quot;,
                &quot;returnEnd&quot;: true,
                &quot;subLanguage&quot;: &quot;php&quot;
            }
        },
        {
            &quot;className&quot;: &quot;template-variable&quot;,
            &quot;begin&quot;: &quot;!!\\}&quot;
        },
        {
            &quot;className&quot;: &quot;template-tag&quot;,
            &quot;begin&quot;: &quot;@php&quot;,
            &quot;starts&quot;: {
                &quot;end&quot;: &quot;@endphp&quot;,
                &quot;returnEnd&quot;: true,
                &quot;subLanguage&quot;: &quot;php&quot;
            },
            &quot;relevance&quot;: 10
        },
        {
            &quot;begin&quot;: &quot;@[\\w]+&quot;,
            &quot;end&quot;: &quot;[\\W]&quot;,
            &quot;excludeEnd&quot;: true,
            &quot;className&quot;: &quot;template-tag&quot;
        }
    ]
}
</code></pre>
<p>At a very basic level, this JSON files uses RegEx patterns to describe starting and ending delimiters. Those patterns are used to match your code blocks against a particular type of token and then add a class to the wrapping HTML element.</p>
<p>As an example, the very first items inside of the <code>contains</code> key is an object that stores information about comments. The <code>className</code> describes which <code>hljs-</code> class will be added to that text node. In this case a <code>hljs-comment</code> class will be added when <code>{{--</code> is encountered.</p>
<p>When that first pattern is matched, it will continue to match the text until the <code>end</code> pattern matches. As a result, our Blade comments are rendered as:</p>
<pre><code class="language-blade">{{-- This is a comment. --}}
</code></pre>
<p>Any objects that have a <code>starts</code> key indicate that matching the <code>begin</code> pattern should start a new sublanguage block. This is what lets you highlight text inside of <code>{{ }}</code> as PHP, instead of a plain-text string.</p>
<p>The same applies to the <code>@php</code> and <code>@endphp</code> blocks. Everything that is found within those 2 directives will be highlighted as PHP.</p>
<pre><code class="language-blade">{{ \Example::method() }}

@php
$example = 2 + 2;

echo $example;
@endphp
</code></pre>
<p>The <code>@php</code> and <code>@endphp</code> rules also have a <code>relevance</code> key. The higher that value of this key, the more likely it is to be used to automatically match the current syntax.</p>
<p>If you don't specify which language you are currently rendering and your code contains an <code>@php</code> directive, Highlight.php will use this relevance and assume you're trying to render Blade.</p>
<h3>Storing our syntax</h3>
<p>This is all down to personal preference, but I like to keep my <code>blade.json</code> file in a <code>resources/syntax</code> folder in my Laravel applications. You can of course place this anywhere you like, just be sure to change any references to it later on.</p>
<h2>Registering the syntax</h2>
<p>Once you have created the <code>blade.json</code> file, we need to tell Highlight.php to use this new syntax definition. This is really simple and only requires a single line of code:</p>
<pre><code class="language-php">\Highlight\Highlighter::registerLanguage('blade', resource_path('syntax/blade.json'), true);
</code></pre>
<p>The first argument is the identifier for the language. In this case, I'll use <code>blade</code>.</p>
<p>The second argument is where your <code>blade.json</code> file is stored. I've stored mine in <code>resources/syntax/blade.json</code> so I'm using the <code>resource_path()</code> helper to get the correct path.</p>
<p>The third argument is optional, but it will forcefully overwrite any existing <code>blade</code> definitions. At the time of writing, Highlight.php doesn't have its own (obviously, that's why you're here) so I'm going to say <code>true</code> so that nothing unexpectedly breaks in the future.</p>
<blockquote>
<p>Ensure that you execute this code <strong>before</strong> attempting to highlight anything. In a Laravel application, you could put it inside of a <code>ServiceProvider</code>.</p>
</blockquote>
<h2>Using the custom syntax</h2>
<p>Once that's all done, you will be able to use <code>blade</code> code in your blocks. Here's an example:</p>
<pre><code class="language-blade">&lt;h1&gt;
    @auth
        Hello, {{ $user-&gt;name }}!
    @else
        Hello!
    @endauth
&lt;/h1&gt;

&lt;livewire:user-profile user=&quot;{{ $user-&gt;name }}&quot; /&gt;
</code></pre>
<h2>Planned improvements</h2>
<p>As I mentioned before, code inside of <code>{{ }}</code> will try to be highlighted using the PHP syntax definitions. This is great, but when you try to right code inside of directives that expect expressions, it isn't highlighted correctly:</p>
<pre><code class="language-blade">@if(2 + 2 === 5)
    {{ 5 }}
@endif
</code></pre>
<p>This is a limitation of Highlight.js and, in turn, Highlight.php. Since the tokeniser relies on a beginning and ending pattern, it's quite hard to match all content between a pair of matching parentheses.</p>
<p>There might be a way to solve this, but my RegEx skills are nowhere near good enough. If you've got any ideas, I'd love to know on <a href="https://twitter.com">Twitter</a>.</p>
<p>Another thing that I'd like to add in PHP highlighting inside of <code>&lt;x:</code> or <code>&lt;livewire:</code> attribute bindings. Since the syntax definition extends from XML, the attributes themselves can be highlighted but the content of those attributes is just rendered as a string.</p>
<p>This one is a bit easier to solve than the directive expressions, so I'll play around with the RegEx and update this article accordingly.</p>
<p>If you want a separate reference, I've put the slimmed down instructions into a <a href="https://gist.github.com/ryangjchandler/f939b4105cf665e564df638d93e8c7d7">GitHub Gist here</a>.</p>
<p>Got any ideas or improvements? Comment on the Gist above and I'll reply as best as I can.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 08 Jan 2021 12:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Setup MailHog with Laravel Valet]]></title>
                <link>https://ryangjchandler.co.uk/posts/setup-mailhog-with-laravel-valet</link>
                <description><![CDATA[<p>Before we begin, you need to have <strong><a href="https://brew.sh/">Homebrew</a></strong> installed. If you don't, visit <a href="https://brew.sh/">https://brew.sh/</a> for instructions on how to get it installed.</p>
<p>If you're <em>not</em> using Laravel Valet, you can skip the last section of this tutorial and use the <code>localhost</code> / <code>127.0.0.1</code> domain instead.</p>
<h2>Installing MailHog</h2>
<p>To install MailHog, run the follow commands in your terminal:</p>
<pre><code class="language-bash">brew install mailhog
</code></pre>
<p>This command will install MailHog on your system, but won't enable the service.</p>
<p>To enable the service, run the command below:</p>
<pre><code class="language-bash">brew services start mailhog
</code></pre>
<p>This will instruct Homebrew to setup a background service so that MailHog is always running on your machine. You won't need to manually start anything, as long as Homebrew is running.</p>
<p>Now, you can visit 127.0.0.1:8025 in a browser and you should be greeted with the MailHog application:</p>
<p><img src="https://github.com/mailhog/MailHog/raw/master/docs/MailHog.png" alt="MailHog image" /></p>
<h2>Configuring your Laravel application</h2>
<p>To get MailHog working with your Laravel application, update the following keys in your <code>.env</code> file:</p>
<pre><code class="language-bash">MAIL_DRIVER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
</code></pre>
<p>The reason the ports are different to the MailHog UI is that the SMTP server is running on port 1025, where as the HTTP server is running on 8025.</p>
<p>If you send an email from your Laravel application now, you will see it pop up in the MailHog interface. You can use the code snippet below inside of Laravel Tinker to test:</p>
<pre><code class="language-php">Mail::raw('MailHog', fn ($message) =&gt; $message-&gt;to('john@example.com')-&gt;from('laravel@example.com'));
</code></pre>
<h2>Setting up a <code>.test</code> domain</h2>
<p><a href="https://laravel.com/docs/8.x/valet">Laravel Valet</a> makes this process super easy. All you need to do is run the following command in your terminal:</p>
<pre><code class="language-bash">valet proxy mailhog.test http://127.0.0.1:8025
</code></pre>
<p>This command will create an Nginx configuration file for the domain <code>mailhog.test</code>, proxying all requests to that domain through to the MailHog HTTP server.</p>
<p>It will also setup an SSL certificate, just like <code>valet secure</code> does for your normal Laravel sites.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 07 Jan 2021 12:00:00 +0000</pubDate>
                                    <category>Tooling</category>
                            </item>
                    <item>
                <title><![CDATA[2020: A year in review]]></title>
                <link>https://ryangjchandler.co.uk/posts/2020-a-year-in-review</link>
                <description><![CDATA[<p><strong>Damn</strong>. 2020. What a (good, bad) year.</p>
<p>This is my first time writing one of these &quot;year in review&quot; blog posts but I'd like to make this an annual tradition. It gives me an opportunity to reflect on the positives from this year and also look into next year, 2021.</p>
<h2>Prologue</h2>
<p>Before I get started, I want to acknowledge the fact that there are lots of people who have had it rough this year. Nobody could have predicted this year to turn out the way it did.</p>
<p>Some might have guessed that certain things would happen but definitely not to <em>this</em> extent.</p>
<p>I also want to acknowledge that I am <em>very</em> lucky and fortunate to be in a good position mentally, financially and health wise.</p>
<h2>Personal</h2>
<p>I don't want to go too deep into my personal life. You're probably not interested in it.</p>
<p>Not much has changed for me in the last year outside of the development world. I think the biggest milestone was <strong>saving for a deposit on a house</strong>.</p>
<p>This was one positive thing to come from COVID. Being stuck at home had a side effect of spending less money on food, travel and holidays since my partner and I couldn't do any of that. This leftover money ended up in savings and in the last couple of months has added up and allowed us to start looking at properties with the hopes of buying and moving out in the New Year.</p>
<h2>Work</h2>
<h3>New job</h3>
<p>I started a new job in January at an insurance company, <a href="https://surewise.com">Surewise</a>. I joined a small team of Laravel developers who all have a shared goal of making online insurance smarter and simpler for as many people as possible.</p>
<p>The job is great and I've been able to innovate our technology stack over this last year. We've implemented many new tools and packages, here's a list of just a few:</p>
<ul>
<li><a href="https://laravel-livewire.com">Livewire</a></li>
<li><a href="https://github.com/alpinejs/alpine">Alpine.js</a></li>
<li>CI/CD</li>
</ul>
<h3>Freelancing</h3>
<p>I'm very happy to say that this year was <strong>the</strong> year that I started (seriously) freelancing. This was the second positive thing to come from COVID, since I was at home I had some more time on my hands and I wanted to help others with their projects.</p>
<p>All of the freelance work was done in the evenings after work or at the weekends, but that really didn't bother me. I was helping others (people and companies) with their projects and really trying to help out companies who were invested in the <a href="https://tallstack.dev/">TALL stack</a>.</p>
<h2>Open-source</h2>
<p>I've been interested in open-source work for a few years now but this last year, it has been a real focus of mine.</p>
<h3>My introduction to big open-source (Alpine.js)</h3>
<p>It all started at the beginning of the year with the new <a href="https://github.com/alpinejs/alpine">Alpine</a> (originally named Project X) project by <a href="https://twitter.com/calebporzio">Caleb Porzio</a>. I was using the project myself and was very active on the repository. I'd comment on issues, try to help people out. I was also opening PRs to the project, trying to fix things, introduce new features and improve the developer experience along the way.</p>
<p>This was my first real taste of what it was like to contribute to an open-source project and Caleb made the whole experience <strong>beautiful</strong>.</p>
<p>As a developer who had come from the world of Vue, I felt like Alpine was missing something. There were also a few other people who felt the same way. That &quot;thing&quot; was a way of sharing state between components, a.k.a global state management.</p>
<p>After a few iterations and releases of an early (and ugly) prototype, <a href="https://github.com/ryangjchandler/spruce">Spruce</a> was born. Spruce was my solution to that &quot;missing something&quot;. It was designed to be minimalistic, just like Alpine. It felt natural to use through the <code>$store</code> variable that it provided.</p>
<p>I personally believe that Spruce has filled that void and the numbers do add up. On average, the CDN has had over 75,000 hits per month so either somebody is using it on a really big site, or a lot of people are using it on smaller sites.</p>
<p>Either way, it solved the problem for me. That's all that matters, right?</p>
<p>As well as Spruce, I've gone on to create and contribute to other Alpine.js related projects such as the <a href="https://github.com/alpine-collective/alpinejs-devtools">DevTools</a>, <a href="https://github.com/alpine-collective/alpine-magic-helpers">Magic Helpers</a> and the <a href="https://github.com/alpine-collective/awesome">Awesome list</a>.</p>
<h3>The TALL stack</h3>
<p>Alongside Alpine, Caleb released a new tool called Livewire. Together they're extremely powerful and add Tailwind to the mix, you're going to be having a party.</p>
<p>As people started to pick up these new tools an acronym emerged, TALL:</p>
<ul>
<li><strong>T</strong>ailwind</li>
<li><strong>A</strong>lpine.js</li>
<li><strong>L</strong>ivewire</li>
<li><strong>L</strong>aravel</li>
</ul>
<p>The Laravel framework has had this concept of &quot;presets&quot; for a little while but there wasn't a real one for the TALL stack.</p>
<p>So I teamed up with <a href="https://twitter.com/LiamHammett">Liam Hammett</a> and <a href="https://twitter.com/danjharrin">Dan Harrin</a> to build one. We wanted to build <strong><a href="https://github.com/laravel-frontend-presets/tall">the best third-party preset</a></strong> preset Laravel.</p>
<p>We went above and beyond really. It came out of the box with tests, customisable components, pretty Tailwind components and more.</p>
<p>At the time of writing this article, our preset has had over 33,000 downloads. That is an insane amount of downloads and we're all really happy with how it turned out, as well as how helpful it has been.</p>
<h3>GitHub Sponsors</h3>
<p>GitHub introduced a new Sponsors program this year. I was accepted into it and wrote a <a href="https://github.com/sponsors/ryangjchandler">small profile</a>.</p>
<p>I was initially inspired by Caleb's success with <a href="https://calebporzio.com/sponsorware">sponsorware</a>, but I never really pushed that concept. Instead, I opted for the &quot;if you use my packages and benefit from them in some way, you can give me $1 or more per month to show that you support my work&quot;.</p>
<p>At the time of writing this article, I have <strong>25 sponsors</strong> and I couldn't be more grateful. You know who you are.</p>
<p>The support that these guys give me, financially, allows me to spend more time on my open-source work. It really does mean <strong>a lot</strong>.</p>
<h3>Overview</h3>
<p>Here are some real numbers for you:</p>
<ul>
<li><strong>Total number of contributions: &gt; 2,000</strong></li>
<li><strong>Total number of discussions answered: &gt; 25</strong></li>
<li><strong>Total number of pull request by me: &gt; 150</strong></li>
<li><strong>Total number of issues by me: &gt; 200</strong></li>
</ul>
<p>Considering I do all of that on the side of my full-time <em>and</em> freelance work, those numbers aren't too shabby.</p>
<h2>Writing and Speaking</h2>
<p>I got really serious about blogging this year. I've written <strong>30 blog posts</strong> (not including this one) on topics that interest me but also help other people out.</p>
<p>One of my posts even reached <a href="https://news.ycombinator.com/item?id=24647722">Hacker News</a> and the abuse wasn't too bad!</p>
<p>I won't go into numbers, but here are 4 of my most popular posts from the last year:</p>
<ul>
<li><a href="https://ryangjchandler.co.uk/articles/running-github-actions-for-certain-commit-messages">Running GitHub Actions for Certain Commit Messages</a></li>
<li><a href="https://ryangjchandler.co.uk/articles/unconventional-laravel-custom-pipeline-classes">Unconventional Laravel: Custom Pipeline Classes</a></li>
<li><a href="https://ryangjchandler.co.uk/articles/writing-reusable-alpine-components">Writing Reusable Alpine Components</a></li>
<li><a href="https://ryangjchandler.co.uk/articles/unconventional-laravel-responable-classes">Unconventional Laravel: Responsable classes</a></li>
</ul>
<p>I also did my first meetup talks this year. My favourite one of them all was the <a href="https://meetup.laravel.com/">Laravel Worldwide Meetup</a> where I demonstrated how to setup a simple CI/CD pipeline for your Laravel application with GitHub Actions.</p>
<p>You can watch that talk <a href="https://www.youtube.com/watch?v=1kPu2eQjkGk">on YouTube</a>.</p>
<h2>New friends</h2>
<p>Through all of my new ventures this year, I've been able to meet some really great people. I want to thank you all for reaching out to me for help with something, helping me with something and most of all, being awesome.</p>
<p>I want to thank <a href="https://twitter.com/LiamHammett">Liam</a>, <a href="https://twitter.com/danjharrin">Dan</a>, <a href="https://twitter.com/calebporzio">Caleb</a>, <a href="https://twitter.com/carre_sam">Sam</a>, <a href="https://twitter.com/samuelstancl">Samuel</a>, <a href="https://twitter.com/LarsKlopstra">Lars</a>, <a href="https://twitter.com/hugo__df">Hugo</a>, <a href="https://twitter.com/kevinbatdorf">Kevin</a>, <a href="https://twitter.com/simo_tod">Simone</a>, <a href="https://twitter.com/damcclean">Duncan</a>. This feels like I'm accepting a Grammy so I've definitely missed some people off that list but if we talk, you know who you are.</p>
<p>You've all had a huge impact on my developer life this year and it wouldn't have been the same without you.</p>
<p>(I'll stop with the soppy stuff now).</p>
<h2>Epilogue</h2>
<p>This year has been full of thrills. For some, it has been full of lows but I really want to believe that 2021 will be a better year for all of us, all across the globe.</p>
<p>As I look forward into 2021, I want to set a few goals for myself:</p>
<ol>
<li>Write more blog posts and help people out.</li>
<li>Speak at a conference.</li>
<li>Release at least 3 new open-source packages.</li>
<li>Finish and release <a href="https://actions-for-php.com">GitHub Actions for PHP Developers</a>.</li>
<li>Livestream on a regular basis.</li>
<li>Meet new friends.</li>
<li>Somehow convince <a href="https://twitter.com/taylorotwell">Taylor</a> to follow me.</li>
</ol>
<p>There we go. We'll see how well that went next year.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 23 Dec 2020 15:30:00 +0000</pubDate>
                                    <category>Insights</category>
                            </item>
                    <item>
                <title><![CDATA[Autolinking and Strikethrough (Parsing Markdown with PHP)]]></title>
                <link>https://ryangjchandler.co.uk/posts/parsing-markdown-with-php-autolinking-and-strikethrough</link>
                <description><![CDATA[<p>When you want to use links in your Markdown, you would normally use the following syntax:</p>
<pre><code class="language-markdown">[Text for the link](https://example.com)
</code></pre>
<p>Sometimes you don't need text for the link. Instead you want the URL itself to be clickable, so you end up doing something like this:</p>
<pre><code class="language-markdown">[https://example.com](https://example.com)
</code></pre>
<p>Some editors and Markdown parsers, such as GitHub's one, are smart and will automatically makes URLs clickable in your text. This is known as &quot;autolinking&quot;.</p>
<p>The same thing can be achieved with the CommonMark parser that we have been using in this series.</p>
<h2>Setting up the environment</h2>
<p>Before we can get autolinking, we need to first change how our parser is being setup. Previously, I showed you how to parse Markdown like this:</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;

$converter = new CommonMarkConverter;

$html = $converter-&gt;convertToHtml('# Hello World');
</code></pre>
<p>The <code>league/commonmark</code> package also provides a nice extensible API available through, what they call, <a href="https://commonmark.thephpleague.com/1.5/customization/environment/">custom environments</a>.</p>
<p>To create a custom environment, you need to create a new instance of the <code>League\CommonMark\Environment</code> class. Instead of instantiating it via the <code>new</code> keyword, you instead need to use a &quot;named constructor&quot;.</p>
<blockquote>
<p>A named constructor is a static method on the class that is responsible for instantiating that class in a particular fashion.</p>
</blockquote>
<p>The named constructor ensures that all of the default renderers and parsers are setup on the converter object so that you don't have to do it yourself.</p>
<p>Here's how it's done:</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment;

$environment = Environment::createCommonMarkEnvironment();

$converter = new CommonMarkConverter;

$html = $converter-&gt;convertToHtml('# Hello World');
</code></pre>
<p>Now that the environment has been created, it needs to be provided to the <code>CommonMarkConverter</code> object.</p>
<p>As you saw in the last instalment, the first argument to the constructor is an array of options. The environment needs to be passed through as the second argument, like so:</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment;

$environment = Environment::createCommonMarkEnvironment();

$converter = new CommonMarkConverter([], $environment);

$html = $converter-&gt;convertToHtml('# Hello World');
</code></pre>
<h2>Adding the autolink extension</h2>
<p>With the environment setup, the extension can be added using the <code>Environment::addExtension()</code> method.</p>
<p>Each extension is declared as a separate class. In this case, the autolinking extension is declared under the <code>League\CommonMark\Extension\Autolink\AutolinkExtension</code> class.</p>
<p>The <code>Environment::addExtension()</code> method will expect a new instance of the extension:</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;

$environment = Environment::createCommonMarkEnvironment();

$environment-&gt;addExtension(new AutolinkExtension);

$converter = new CommonMarkConverter([], $environment);

$html = $converter-&gt;convertToHtml('This is an awesome website, check out https://ryangjchandler.co.uk now!');
</code></pre>
<p>With all of this setup, you can use URLs as links in your Markdown. Running the following Markdown through the converter:</p>
<pre><code class="language-markdown">This is an awesome website, check out https://ryangjchandler.co.uk now!
</code></pre>
<p>Will result in the following HTML:</p>
<pre><code class="language-html">This is an awesome website, check out &lt;a href=&quot;https://ryangjchandler.co.uk&quot;&gt;https://ryangjchandler.co.uk&lt;/a&gt; now!
</code></pre>
<h2>Striking through text</h2>
<p>Although I can't think of many places where I ever need to strikethrough text, it <em>can</em> be useful sometimes. A good use case could be in a GitHub issue where you want to strikethrough something you have said previously and update it.</p>
<p>Out of the box, that isn't supported. The syntax for striking through also changes between specifications, but in this case, it's going to be something like this:</p>
<pre><code class="language-markdown">The next piece of text should be ~~striked~~ out.
</code></pre>
<p>To add support for this, you need to add another extension to the environment.</p>
<p>The extension needed is the <code>League\CommonMark\Extension\Strikethrough\StrikethroughExtension</code> extension.</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment;
use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;

$environment = Environment::createCommonMarkEnvironment();

$environment-&gt;addExtension(new StrikethroughExtension);

$converter = new CommonMarkConverter([], $environment);

$html = $converter-&gt;convertToHtml('The next piece of text should be ~~striked~~ out.');
</code></pre>
<h2>Sign off</h2>
<p>Thanks for reading this article. In the next instalment, I'll be showing you how you can use tables in your Markdown.</p>
<p>Thanks for reading! 👋</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 09 Nov 2020 17:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Getting started (Parsing Markdown with PHP)]]></title>
                <link>https://ryangjchandler.co.uk/posts/parsing-markdown-with-php-getting-started</link>
                <description><![CDATA[<p>I'm a huge fan of Markdown. I use it, literally, everywhere I can. The article that you're reading right now was written in Markdown. If I'm ever making notes, I'm using an application that supports Markdown.</p>
<p>Personally, I find it to be the most consistent way of writing. Yes, there are lots of different flavours but they all have the same base.</p>
<p>Here's an example of some Markdown:</p>
<pre><code class="language-markdown"># Let's get started with a heading.

This is some **bold** text.

These are _italics_.

Here is a small bit of `code`
</code></pre>
<p>Markdown was inspired by text-to-HTML filters. They're tools designed to take some non-HTML text and transform them into good ol' hypertext.</p>
<p>I won't go over the basics of Markdown in this series. The best place to read about that is on the <a href="https://daringfireball.net/projects/markdown/">author's website (John Gruber).</a></p>
<p>This series will be using tools to transform Markdown that follows the <a href="https://commonmark.org/">CommonMark</a> specification into HTML.</p>
<h2>Getting started</h2>
<p>First thing that you need to do to start using Markdown in a PHP application is, you guessed it, install a Composer package.</p>
<p>Since I'm going to be using the CommonMark specification, we need to use a tool that supports that spec.</p>
<p>Luckily the wonderful people over at The PHP League have developed a package for that, <code>league/commonmark</code></p>
<p>Run the following command to get it installed:</p>
<pre><code class="language-bash">composer require league/commonmark
</code></pre>
<h2>Parsing your first Markdown</h2>
<p>Now that the package is installed, you can start using it straight away.</p>
<p>First, create a new instance of the <code>League\CommonMark\CommonMarkConverter</code> class.</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;

$converter = new CommonMarkConverter;
</code></pre>
<p>Next, call the <code>convertToHtml()</code> method on the object and pass through a string of Markdown.</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;

$converter = new CommonMarkConverter;

$html = $converter-&gt;convertToHtml('# Hello World');
</code></pre>
<p>The <code>$html</code> variable will now hold the HTML equivalent of the Markdown provided, in this case it will be <code>&lt;h1&gt;Hello World&lt;/h1&gt;</code>.</p>
<h2>Sanitising the Markdown</h2>
<p>Since Markdown is converted to HTML, it makes sense that HTML can be written within the Markdown.</p>
<p>When you're transforming user input, this can be risky and might open up the opportunity for an XSS attack.</p>
<p>The PHP League have thought about this though and added an option to the converter that will help out.</p>
<p>To begin using these configuration options, you need to provide an array when constructing the <code>League\CommonMark\CommonMarkConverter</code> object.</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;

$converter = new CommonMarkConverter([
    'html_input' =&gt; 'escape'
]);

$html = $converter-&gt;convertToHtml('# Hello World');
</code></pre>
<p>If you now change the Markdown being parsed and include some HTML, the result will be escaped.</p>
<pre><code class="language-php">use League\CommonMark\CommonMarkConverter;

$converter = new CommonMarkConverter([
    'html_input' =&gt; 'escape'
]);

$html = $converter-&gt;convertToHtml('&lt;h1&gt;Hello World&lt;/h1&gt;');
</code></pre>
<p>After being transformed, <code>$html</code> will now hold the string <code>&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;</code> which is the escaped version of the HTML being transformed.</p>
<blockquote>
<p>If you're interested in some of the other options available, visit the package's documentation on <em><a href="https://commonmark.thephpleague.com/1.5/configuration/">Configuration</a></em>.</p>
</blockquote>
<h2>Sign off</h2>
<p>Thanks for reading this article. In the next instalment, I'll be showing you some helpful extensions you can use to make your Markdown writing experience less painful.</p>
<p>Thanks for reading! 👋</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 07 Nov 2020 17:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Build a remaining character count component with Alpine.js]]></title>
                <link>https://ryangjchandler.co.uk/posts/build-a-remaining-character-count-component-with-alpinejs</link>
                <description><![CDATA[<p>Before we begin, let's lay down some basic markup for our character counter.</p>
<p>I'm going to be using <code>x-ref</code> directives to identify each part so that you can keep track of everything easily.</p>
<pre><code class="language-html">&lt;div&gt;
    &lt;textarea x-ref=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>On top of that, we need to ensure Alpine can initialise a new component. Let's add an <code>x-data</code> attribute to the root element, in this case a <code>&lt;div&gt;</code>, as well as a data property to hold the contents of the <code>&lt;textarea&gt;</code>.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ content: '' }&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>The new <code>content</code> property hasn't been hooked up to the <code>&lt;textarea&gt;</code> yet. The simplest way to do this would be using <code>x-model</code>, which will add an event listener to the element and update the property with the elements <code>value</code> property.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ content: '' }&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot; x-model=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>With data binding setup, all that's left to do is output the number of remaining characters. To do this, we need to know how many characters the content has and what the limit is.</p>
<p>I like to use <code>data</code> attributes for variable pieces of data, such as the character limit. I'll add a new <code>data-limit</code> attribute to hold this.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ content: '' }&quot; data-limit=&quot;100&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot; x-model=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>The reason I like using <code>data</code> attributes is because if you later decide to move the data object into a function, you can still see the arguments that change the behaviour of the component directly in the markup.</p>
<p>I'm also going to add a new property on our component to hold the limit.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ content: '', limit: $el.dataset.limit }&quot; data-limit=&quot;100&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot; x-model=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<blockquote>
<p>If you don't want to use a data attribute for the <code>limit</code>, you could put the value directly in the data object instead.</p>
</blockquote>
<p>The <code>$el</code> object being used is a magic variable provided by Alpine and is a reference to the root element (the <code>&lt;div&gt;</code>). Since this is just a regular <code>Element</code> object, we can use the <code>dataset</code> property to get the <code>data-limit</code>.</p>
<p>There are a couple of ways to go about actually <em>outputting</em> the remaining characters. I'll cover both of them here, since you might like one more than the other.</p>
<h3>Method One - template literals</h3>
<p>Using Alpine's <code>x-text</code> alongside <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals">template literals</a>, you can dynamically set the <code>innerText</code> of an element.</p>
<p>Applying this method to the element looks a little something like:</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ content: '', limit: $el.dataset.limit }&quot; data-limit=&quot;100&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot; x-model=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot; x-text=&quot;`You have ${limit - content.length} characters remaining.&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<h3>Method Two - dynamic <code>&lt;span&gt;</code></h3>
<p>Compared to the first method, this approach will only update the <code>innerText</code> of a single child element instead of the entire <code>&lt;p&gt;</code> element.</p>
<p>This means that you can render the non-dynamic content on the server, or statically.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ content: '', limit: $el.dataset.limit }&quot; data-limit=&quot;100&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot; x-model=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;
        You have &lt;span x-text=&quot;limit - content.length&quot;&gt;&lt;/span&gt; characters remaining.
    &lt;/p&gt;
&lt;/div&gt;
</code></pre>
<h2>Improvements</h2>
<h3>Preventing flashing content</h3>
<p>I personally prefer using server-rendered content to give the <code>&lt;span&gt;</code> some default text. In a Laravel application, I might do something like:</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ content: '', limit: $el.dataset.limit }&quot; data-limit=&quot;{{ $limit }}&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot; x-model=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;
        You have &lt;span x-text=&quot;limit - content.length&quot;&gt;{{ $limit }}&lt;/span&gt; characters remaining.
    &lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>In this case, the <code>$limit</code> variable is coming from the server and will be rendered as the default value inside of the <code>&lt;span&gt;</code> element. This helps with &quot;flashing&quot; content, since Alpine needs some time to evaluate the <code>x-text</code> directive and set the <code>innerText</code> of the element.</p>
<blockquote>
<p>You could also tackle the &quot;flashing&quot; problem using <code>x-cloak</code>, as described in <a href="https://ryangjchandler.co.uk/articles/hiding-elements-until-alpine-is-ready-with-x-cloak">this article</a>.</p>
</blockquote>
<h3>Using a &quot;computed property&quot;</h3>
<p>Alpine doesn't support computed properties in the same sense as Vue, but since the data object is just a regular object literal, you can make use of JavaScript's &quot;getters&quot;, as described in <a href="https://ryangjchandler.co.uk/articles/an-alternative-approach-to-computed-properties-in-alpinejs">this article</a>.</p>
<p>This can hide the calculation logic from the directive itself:</p>
<pre><code class="language-html">&lt;div x-data=&quot;{
    content: '',
    limit: $el.dataset.limit,
    get remaining() {
        return this.limit - this.content.length
    }
}&quot; data-limit=&quot;100&quot;&gt;
    &lt;textarea x-ref=&quot;content&quot; x-model=&quot;content&quot;&gt;&lt;/textarea&gt;
    &lt;p x-ref=&quot;remaining&quot;&gt;
        You have &lt;span x-text=&quot;remaining&quot;&gt;&lt;/span&gt; characters remaining.
    &lt;/p&gt;
&lt;/div&gt;
</code></pre>
<h2>Sign off</h2>
<p>If you would like to see an interactive version of this component, I've uploaded <a href="https://codepen.io/ryangjchandler/pen/ZEOrVPM">one to CodePen</a>.</p>
<p>If you enjoyed this article or have any feedback, please feel free to let me know on <a href="https://twitter.com/ryangjchandler">Twitter</a>.</p>
<p>Thanks for reading! 👋</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 29 Oct 2020 17:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Responsable classes (Unconventional Laravel)]]></title>
                <link>https://ryangjchandler.co.uk/posts/unconventional-laravel-responable-classes</link>
                <description><![CDATA[<p>In your typical Laravel application, you're probably used to using Laravel's helper methods for returning responses.</p>
<p>Those responses might also vary in type: you might have an HTML response, generated from a Blade view, or a JSON response if the route being hit is an API endpoint.</p>
<p>Here's an example:</p>
<pre><code class="language-php">class PostController
{
    public function index()
    {
        return view('posts.index', [
            'post' =&gt; Post::published()-&gt;get(),
        ]);
    }
}
</code></pre>
<p>We're going to look at how a controller like this can grow within an application, as well as how we can expand on this concept and turn the code above into the code snippet below:</p>
<pre><code class="language-php">class PostController
{
    public function index()
    {
        $posts = Post::published()-&gt;get();
        
        return new PostIndexResponse($posts);
    }
}
</code></pre>
<h2>The basic idea</h2>
<h3>Content negotiation</h3>
<p>In some applications, it makes sense to have a single route for both your HTML responses, as well as your API responses.</p>
<p>This technique is known as &quot;content negotiation&quot;. You check what sort of request is being made and send a specific type of response back, based on that request type.</p>
<p>Take the example above. If I wanted to return some JSON when the request wants that type of content, I would do the following:</p>
<pre><code class="language-php">class PostController
{
    public function index(Request $request)
    {
        $posts = Post::published()-&gt;get();
        
        if ($request-&gt;wantsJson()) {
            return $posts;
        }
        
        return view('posts.index', [
            'post' =&gt; $posts,
        ]);
    }
}
</code></pre>
<p>Thanks to Laravel's <code>Request::wantsJson()</code> method, you can easily check whether or not you need to return JSON or HTML in the response.</p>
<p>For small scenarios like this, custom response classes won't benefit you much. There's only 2 different conditions that determine the type of response that needs to be returned.</p>
<p>Let's use a hypothetical <code>Request::wantsRss()</code> method now.</p>
<pre><code class="language-php">class PostController
{
    public function index(Request $request)
    {
        $posts = Post::published()-&gt;get();
        
        if ($request-&gt;wantsRss()) {
            return RssFeed::from($posts)-&gt;create();
        }
        
        if ($request-&gt;wantsJson()) {
            return $posts;
        }
        
        return view('posts.index', [
            'post' =&gt; $posts,
        ]);
    }
}
</code></pre>
<p>As more and more of these different content types get added, the method will get more and more crowded. Let's try and tackle this with custom response classes.</p>
<p>The first step to creating a custom response class is implementing the <code>Responsable</code> interface and moving some of our response logic into the <code>toResponse</code> method.</p>
<pre><code class="language-php">class PostIndexResponse implements Responsable
{
    public function toResponse(Request $request)
    {
        if ($request-&gt;wantsRss()) {
            return RssFeed::from($posts)-&gt;create();
        }
        
        if ($request-&gt;wantsJson()) {
            return $posts;
        }
        
        return view('posts.index', [
            'post' =&gt; $posts,
        ]);
    }
}
</code></pre>
<p>First problem is that our <code>$posts</code> variable isn't here anymore. Thankfully, we can add a constructor the class and assign it to a property.</p>
<pre><code class="language-php">class PostIndexResponse implements Responsable
{
    private $posts;
    
    public function __construct($posts)
    {
        $this-&gt;posts = $posts;
    }
    
    public function toResponse(Request $request)
    {
        // ...
    }
}
</code></pre>
<p>If we head back to our controller, we can replace all of those <code>if</code> statements with a single instantiation of our new <code>PostIndexResponse</code> class.</p>
<pre><code class="language-php">class PostController
{
    public function index(Request $request)
    {
        $posts = Post::published()-&gt;get();
        
        return new PostIndexResponse($posts);
    }
}
</code></pre>
<h2>Creating a base response class</h2>
<p>The logic that we've just abstracted into a separate class is still a bit long and tedious to write out every time.</p>
<p>One way of working around this is by creating an abstract <code>BaseResponse</code> class that holds this logic instead.</p>
<p>Here's a super simple version:</p>
<pre><code class="language-php">abstract class BaseResponse implements Responsable
{
    public function toResponse($request)
    {
        if ($request-&gt;wantsJson()) {
            return $this-&gt;toJson();
        }
        
        return $this-&gt;toHtml();
    }
}
</code></pre>
<p>The logic is similar to the previous class, but now we're going to use some conventional method naming.</p>
<p>For requests that are expecting a JSON response, the <code>toJson</code> method should be used on the child class. By default, it will use the <code>toHtml</code> method, so you could return a view from here or an instance of <code>HtmlString</code>.</p>
<p>Let's take this new abstract class and apply it to our <code>PostIndexResponse</code>.</p>
<pre><code class="language-php">class PostIndexResponse extends BaseResponse
{
    private $posts;
    
    public function __construct($posts)
    {
        $this-&gt;posts = $posts;
    }
    
    public function toRss()
    {
        return RssFeed::from($this-&gt;posts)-&gt;create();
    }
    
    public function toJson()
    {
        return $this-&gt;posts;
    }
    
    public function toHtml()
    {
        return view('posts.index', [
            'posts' =&gt; $this-&gt;posts,
        ]);
    }
}
</code></pre>
<h3>Adding some magic</h3>
<p>If I wanted to add a new <code>wantsPng</code> condition to my <code>BaseResponse</code> class, I'd need to go into the <code>toResponse</code> method, check for it, add in a new method. This is tedious when you're using lots of different content types, so why don't we add a bit of magic to it.</p>
<p>I'm going to go down the route of assuming there is always a <code>wants{format}</code> method on the request object. This is probably going to be the case, especially if you're using the check in other places in your app, you'd probably want to macro it in.</p>
<pre><code class="language-php">abstract class BaseResponse implements Responsable
{
    protected $accepts = [
        'json', 'rss', 'png', 'jpg',
    ];

    public function toResponse($request)
    {
        foreach ($this-&gt;accepts as $accept) {
            $requestMethod = 'wants'.Str::studly($accept);
            $responseMethod = 'to'.Str::studly($accept);
          
            if ($request-&gt;{$requestMethod}()) {
                return $this-&gt;{$responseMethod}();
            }
        }
      
        return $this-&gt;toHtml();
    }
}
</code></pre>
<p>Now, instead of needing to write the condition yourself, you can simply add a new item to the <code>$accepts</code> property, define a <code>to{format}</code> method using <em>StudlyCase</em> and it should &quot;just work&quot;.</p>
<h2>Pros</h2>
<h3>Thin controllers</h3>
<p>One of the Laravel community's many &quot;best practices&quot; is to always have thin controllers. This just means that your controllers are always lightweight and small, resulting in a lot of logic being moved outside into models and actions, or in this case, custom response classes.</p>
<p>This best practice also helps with naming things, since each method or class will be appropriately named for what it does. Custom response classes have the same effect.</p>
<h3>Code clarity</h3>
<p>If this is a pattern that you adopt and use across your codebase, you'll probably find that finding things becomes a lot easier. The same idea can be found in single action controllers and form requests.</p>
<p>If you know the name of the current route / context, or can describe what you're viewing, as long as your custom response classes are named appropriately, you can do a quick search and find exactly what you're looking for.</p>
<h2>Cons</h2>
<h3>Hidden logic</h3>
<p>Despite me saying that code clarity is a <em>pro</em> for this pattern, you could also be making an early abstraction, meaning your logic and request flow is hidden away under a named object.</p>
<p>For small projects, that can be problematic, especially if you're not working on them 24/7 and know the structure like the back of your hand.</p>
<p>It can also be problematic for new developers on a project, since it's not conventional. But hey, that's what these posts are all about.</p>
<h3>Maintenance of accepted types</h3>
<p>Like I've shown, you can use a bit of magic to make the maintenance of this pattern a bit easier, but if you find yourself adding 100 different content types because you have 100 different contexts, you're probably using the wrong pattern.</p>
<p>With each type you add, you need to remember how it works, what should happen with the response and where that magic is even coming from.</p>
<h3>Unexpected errors</h3>
<p>If somebody makes a request to your route asking for an unexpected content type, your code probably won't have any support for it. That means the user is going to get a nasty 500 error and you're going to be sitting there debugging the problem. Even worse, depending on your default response type, you could even leak data because it will always return JSON, or HTML.</p>
<p>Be sure to protect your routes correctly, or tighten up the base response class to return an empty response by default instead.</p>
<h2>Sign off</h2>
<p>If you enjoyed this article or have any questions, I'd love to know on <a href="https://twitter.com/ryangjchandler">Twitter</a>. I'd also love to know if you have used this pattern in your own applications.</p>
<p>Thanks for reading!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 22 Oct 2020 16:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Middleware-as-a-Service-Provider (Unconventional Laravel)]]></title>
                <link>https://ryangjchandler.co.uk/posts/unconventional-laravel-middleware-as-a-service-provider</link>
                <description><![CDATA[<p>Service providers are the backbone of Laravel's powerful <a href="https://laravel.com/docs/8.x/container">service container</a>. They can be used to bind new services to the container, call setup methods on third party libraries and interact with first-party / core services (generally through <a href="https://laravel.com/docs/8.x/facades">facades</a>).</p>
<p>The problem with these classes is that they're global and generally registered and bootstrapped for <strong>every request</strong>. This means that if you want to do something based on the current request, your service provider needs to have some knowledge of the current request context.</p>
<p>Take the following example:</p>
<pre><code class="language-php">class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        if (! request()-&gt;is('admin/*')) {
            User::addGlobalScope('forTenant', new ForTenantScope);
        }
    }
}
</code></pre>
<p>In this example a <a href="https://laravel.com/docs/8.x/eloquent#global-scopes">global scope</a> is being applied to the <code>User</code> model, but <strong>only</strong> for routes / URLs that don't match the pattern <code>admin/*</code>.</p>
<p>On a small scale this is <em>probably</em> fine, but as your application grows and you find yourself adding more code inside of this <code>if</code> statement, things can get out of hand quickly and become a maintenance nightmare.</p>
<h2>The middleware approach</h2>
<p>Since this code is <strong>only</strong> going to be run for a specific group / set of routes, it can be moved to a piece of middleware and added to the stack for that group of routes.</p>
<pre><code class="language-php">class BootstrapWebRoutes
{
    public function handle(Request $request, Closure $next)
    {
        User::addGlobalScope('forTenant', new ForTenantScope);
    }
}
</code></pre>
<p>This code is doing the same thing as before, but we can now add this middleware to the non <code>admin/*</code> routes and remove the request logic and knowledge from our service provider.</p>
<pre><code class="language-php">Route::as('web.')
    -&gt;middleware(BootstrapWebRoutes::class)
    -&gt;group(function () {
        Route::get('users', [UserController::class, 'index'])-&gt;name('users.index');
    });
</code></pre>
<p>Our global boot process now doesn't need to know about the current request context and we can guarantee that this scope is only going to be applied when visiting a route inside of this group (unless the middleware is applied elsewhere, obviously).</p>
<h2>Pros</h2>
<h3>Thinner service providers</h3>
<p>The benefit with this approach is that our service providers will actually be slimmer and hopefully only contain things related to actual services.</p>
<p>Of course, global scopes aren't the best example, but as you use more third-party libraries that have configuration values dependent on the current request context (menu builders, breadcrumbs, authorisation), you'll be thankful that it's all contained in middleware classes that are easier to find and compose.</p>
<h3>Potentially faster bootups</h3>
<p>On a small scale, framework bootstrapping times won't necessarily be faster since the logic that has been moved isn't heavy.</p>
<p>If you were doing multiple bits of string manipulation, or lots of <code>preg_*</code> calls, then moving this out of the global application process <em>might</em> bring a performance improvement since it's only going to be done when it <strong>needs</strong> to be done.</p>
<h3>Modularity</h3>
<p>When building applications that use a modular structure, where each component of your application is grouped up into a smaller, Laravel-esque structure, this approach could definitely be of use.</p>
<p>You won't need to step out of the module's context into a global service provider to run logic, or even worse, conditionally register a service provider. You can move all of that logic into a middleware class inside of the current module and register it for a group of routes as shown above.</p>
<h2>Cons</h2>
<h3>Abstract thinking</h3>
<p>This concept isn't something that a lot of people will think to do when building there applications, because in a lot of cases libraries will directly tell you to add code inside of a <code>ServiceProvider</code> class. This is even the case with Laravel's own first-party packages.</p>
<p>Due to this, future you might find it difficult to find logic or configuration without sifting through project-wide search results.</p>
<h3>Late running</h3>
<p>Route middleware is executed after global middleware and any service registration (inside <code>ServiceProvider::register()</code>) so using this approach might not work for <em>all</em> scenarios.</p>
<p>Make sure that if you register any services from inside of this bootstrap middleware that it runs in the correct order, especially if another piece of middleware relies on one of those services.</p>
<p>Also be careful when working with third-party libraries as they could be hooked into those early stages of the framework startup, meaning none of your code inside of the middleware has been evaluated at the right time.</p>
<h2>Sign off</h2>
<p>As always, be careful when adopting patterns like this (especially prematurely). On small projects with one or two developers, this pattern might not be a beneficial one to use since you're going to know where things are 99% of the time and it will probably cause more damage than good.</p>
<p>I've seen this patterns used in a couple of different scenarios, mostly when working with <code>carbon/carbon</code> and different default formats are used depending on the context, or the base element for breadcrumbs is different based on the request URL.</p>
<p>If you enjoyed this article, I'd love to know on <a href="https://twitter.com">Twitter</a>. If you've ever used this pattern, let me know too!</p>
<p>Thanks for reading!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 29 Sep 2020 16:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Running GitHub Actions for certain commit messages]]></title>
                <link>https://ryangjchandler.co.uk/posts/running-github-actions-for-certain-commit-messages</link>
                <description><![CDATA[<p>I'm going to be honest with you all for a second. I write a lot of <code>wip</code> commits. These commits are normally small changes that I want to push up to GitHub so that:</p>
<ol>
<li>I don't lose things if anything goes wrong and my backup hasn't picked it up.</li>
<li>If I can't describe the change I have just made.</li>
<li>If I'm demonstrating something to somebody on a pull-request.</li>
</ol>
<p>The problem is, my actions are setup to run on <code>push</code>, so every single <code>wip</code> commit gets run through the CI process, whether it be running tests, linting or formatting.</p>
<p>After doing some research, I found a way of preventing these from running on every single commit.</p>
<pre><code class="language-yml">jobs:
  format:
    runs-on: ubuntu-latest
    if: &quot;! contains(github.event.head_commit.message, 'wip')&quot;
</code></pre>
<p>Now, whenever I push a <code>wip</code> commit or any commit that contains the word <code>wip</code>, it will be marked as skipped inside of GitHub actions.</p>
<p>You could also flip the logic and perhaps do something like:</p>
<pre><code class="language-yml">jobs:
  format:
    runs-on: ubuntu-latest
    if: &quot;contains(github.event.head_commit.message, '[build]')&quot;
</code></pre>
<p>Any commit that contains <code>[build]</code> will now trigger these jobs, everything else will be skipped.</p>
<p>You can thank me later! 😉</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 29 Sep 2020 12:00:00 +0000</pubDate>
                                    <category>GitHub Actions</category>
                            </item>
                    <item>
                <title><![CDATA[Custom pipeline classes (Unconventional Laravel)]]></title>
                <link>https://ryangjchandler.co.uk/posts/unconventional-laravel-custom-pipeline-classes</link>
                <description><![CDATA[<p>I'll start off by going over what the <code>Pipeline</code> class actually does. In <a href="https://en.wikipedia.org/wiki/Plain_English">layman's terms</a>, this class will take a value and pass it off to a collection of handler classes before being returned.</p>
<p>These handler classes are simple classes that are resolved from the container and only need a single <code>handle()</code> or <code>__invoke()</code> method.</p>
<h2>An example pipeline</h2>
<p>Imagine you have a blog and when you publish a post, you want to run through a series of tasks. Each task has its own &quot;action&quot;, or &quot;handler&quot;, class that will receive the post and do something to it.</p>
<p>Here's what your code might look like <strong>without</strong> using pipelines (with some pseudo methods):</p>
<pre><code class="language-php">&lt;?php
  
$post = Post::current();

$pipes = [
    MakeSurePostHasBeenPublished::class,
    SendTweetAboutNewPost::class,
    SendEmailAboutNewPost::class,
];

foreach ($pipes as $pipe) {
    $post = app($pipe)-&gt;handle($post);
}
</code></pre>
<p>There isn't anything immediately wrong with this code since it's on a small scale. Personally though, I don't like having that temporary variable that is only being used as the iterable for the <code>foreach</code> loop and I don't like that the <code>$post</code> variable is being re-assigned after each action. It makes for some confusing and messy code, especially as the number of &quot;pipes&quot; grows.</p>
<p>Let's replace this with a <code>Pipeline</code> implementation and see how much cleaner it is:</p>
<pre><code class="language-php">use Illuminate\Pipeline\Pipeline;

$post = app(Pipeline::class)
    -&gt;send(Post::current())
    -&gt;through([
        MakeSurePostHasBeenPublished::class,
        SendTweetAboutNewPost::class,
        SendEmailAboutNewPost::class,
    ])
    -&gt;thenReturn();
</code></pre>
<p>You can instantly follow the logic of the code, since it uses a fluent method chain with sensible method names. The idea is still the same as before. The current post is being <em>sent</em> through each <em>pipe</em> and <em>then</em> being <em>returned</em> to a <code>$post</code> variable.</p>
<p>The <code>Pipeline</code> itself is being resolved out of the container through the <code>app()</code> helper function since it needs an implementation of <code>Illuminate\Contracts\Container\Container</code> to resolve each pipe class.</p>
<h2>Taking it one step further</h2>
<p>We've already made an improvement to the code leaving the <code>foreach</code> loop behind and moving to an object-oriented approach, but we can take this even further by wrapping this same logic up inside of a custom pipeline class.</p>
<p>Let's start off by creating a new class called <code>PublishPostPipeline</code>:</p>
<pre><code class="language-php">use Illuminate\Pipeline\Pipeline;

class PublishPostPipeline extends Pipeline
{
    //
}
</code></pre>
<p>When the <code>Pipeline::through()</code> method is called, the array argument passed will be assigned to the <code>$pipes</code> property on the object. This means that method call can be circumvented and the pipes can be assigned directly to the <code>protected $pipes</code> property on the class.</p>
<p>This change also means there is only a single place to add, or remove, a pipe from the pipeline:</p>
<pre><code class="language-php">use Illuminate\Pipeline\Pipeline;

class PublishPostPipeline extends Pipeline
{
    protected $pipes = [
        MakeSurePostHasBeenPublished::class,
        SendTweetAboutNewPost::class,
        SendEmailAboutNewPost::class,
    ];
}
</code></pre>
<p>If we refactor our previous code to use this new <code>PublishPostPipeline</code> class, it would look something like:</p>
<pre><code class="language-php">$post = app(PublishPostPipeline::class)
    -&gt;send(Post::current())
    -&gt;thenReturn();
</code></pre>
<p>The method chain doesn't read very nicely now though, because it sounds like we're just sending the post and returning straight away.</p>
<p>This next part is optional, but I like to add a named constructor and runner method that will accept the <code>Post</code> as an argument and do all of this logic for me.</p>
<pre><code class="language-php">use Illuminate\Pipeline\Pipeline;

class PublishPostPipeline extends Pipeline
{
    protected $pipes = [
        MakeSurePostHasBeenPublished::class,
        SendTweetAboutNewPost::class,
        SendEmailAboutNewPost::class,
    ];

    public static function run(Post $post): Post
    {
        return app(static::class)-&gt;send($post)-&gt;thenReturn();
    }
}
</code></pre>
<p>Instead of having all of the logic for sending and returning in our caller method, we can just call <code>PublishPostPipeline::run()</code> and use the return value of that method.</p>
<p>The benefit here is that we can type the <code>$post</code> argument and also add a return type of <code>Post</code>, allowing the intellisense plugin of your editor to pick up on the variable type and provide better autocomplete / suggestions.</p>
<h2>Sign off</h2>
<p>I haven't seen this pattern used too much in the wild but I have used it a lot for making my code more DRY, especially when I use the same pipelines in controllers, queues and commands.</p>
<p>If you want to read up on the <code>Pipeline</code> class a little more, <a href="https://twitter.com/Jeffer_8a">Jeff Ochoa</a> has written a <a href="https://jeffochoa.me/understanding-laravel-pipelines">blog post</a> that goes over the basics.</p>
<p>The team over at <a href="https://zaengle.com/">Zaengle</a> have also created a <a href="https://github.com/zaengle/pipeline">package</a> that has a deeper approach to writing DRY pipelines, along with a few niceties.</p>
<p>I'd love to know what you thought about this blog post on <a href="https://twitter.com/ryangjchandler">Twitter</a>.</p>
<p>Thanks for reading!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 15 Sep 2020 11:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Writing reusable Alpine.js components]]></title>
                <link>https://ryangjchandler.co.uk/posts/writing-reusable-alpine-components</link>
                <description><![CDATA[<p>Since Alpine lives directly in the markup, it can be difficult to abstract components in the correct way. I'd like to go over a few ways that you can abstract your component logic into more re-usable components.</p>
<h3>The data function</h3>
<p>When you initialise an Alpine component, you probably put the object expression directly inside of the <code>x-data</code> attribute.</p>
<p>This approach works well for small components that only have a couple of pieces of state and is one of Alpine's strongest selling points. It can get out of hand for larger components, especially those that have large methods for sending AJAX requests, handling form logic, etc.</p>
<p>The simplest way to abstract these large methods is by using functions as your data source. This is similar to how the <code>data()</code> method in Vue works, where you return an object from that function.</p>
<p>This is a component before being abstracted.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{
    name: '',
    email: '',
    password: '',
    errors: {
        name: [],
        email: [],
        password: [],
    },
    validate() {
        if (! this.name) {
            this.errors.name.push('You must enter your name.')
        }

        if (this.email &amp;&amp; ! this.email.includes('@')) {
            this.errors.email.push('You must enter a valid email address')
        }

        if (this.password &amp;&amp; this.password.length &lt; 8) {
            this.errors.password.push('Your password must be at least 8 characters long.')
        }
    }
}&quot;&gt;
    &lt;input type=&quot;text&quot; x-model=&quot;name&quot; @input=&quot;validate&quot;&gt;

    &lt;template x-for=&quot;error in errors.name&quot;&gt;
        &lt;p x-text=&quot;error&quot;&gt;&lt;/p&gt;
    &lt;/template&gt;

    &lt;input type=&quot;text&quot; x-model=&quot;email&quot; @input=&quot;validate&quot;&gt;

    &lt;template x-for=&quot;error in errors.email&quot;&gt;
        &lt;p x-text=&quot;error&quot;&gt;&lt;/p&gt;
    &lt;/template&gt;

    &lt;input type=&quot;password&quot; x-model=&quot;password&quot; @input=&quot;validate&quot;&gt;

    &lt;template x-for=&quot;error in errors.password&quot;&gt;
        &lt;p x-text=&quot;error&quot;&gt;&lt;/p&gt;
    &lt;/template&gt;
&lt;/div&gt;
</code></pre>
<p>Pretty nasty, right? Moving this to a function is pretty simple. You need to create a function inside of a <code>&lt;script&gt;</code> tag somewhere on the page and make the entire <code>x-data</code> object the return value of that function.</p>
<pre><code class="language-html">&lt;script&gt;
window.profileForm = function () {
    return {
        name: '',
        email: '',
        password: '',
        errors: {
            name: [],
            email: [],
            password: [],
        },
        validate() {
            if (! this.name) {
                this.errors.name.push('You must enter your name.')
            }
    
            if (this.email &amp;&amp; ! this.email.includes('@')) {
                this.errors.email.push('You must enter a valid email address')
            }
    
            if (this.password &amp;&amp; this.password.length &lt; 8) {
                this.errors.password.push('Your password must be at least 8 characters long.')
            }
        }
    }
}
&lt;/script&gt;
</code></pre>
<p>Then replace the value of <code>x-data</code> with the name of the function, in this case <code>profileForm</code>.</p>
<pre><code class="language-html">&lt;div x-data=&quot;profileForm()&quot;&gt;
    &lt;input type=&quot;text&quot; x-model=&quot;name&quot; @input=&quot;validate&quot;&gt;

    &lt;template x-for=&quot;error in errors.name&quot;&gt;
        &lt;p x-text=&quot;error&quot;&gt;&lt;/p&gt;
    &lt;/template&gt;

    &lt;input type=&quot;text&quot; x-model=&quot;email&quot; @input=&quot;validate&quot;&gt;

    &lt;template x-for=&quot;error in errors.email&quot;&gt;
        &lt;p x-text=&quot;error&quot;&gt;&lt;/p&gt;
    &lt;/template&gt;

    &lt;input type=&quot;password&quot; x-model=&quot;password&quot; @input=&quot;validate&quot;&gt;

    &lt;template x-for=&quot;error in errors.password&quot;&gt;
        &lt;p x-text=&quot;error&quot;&gt;&lt;/p&gt;
    &lt;/template&gt;
&lt;/div&gt;
</code></pre>
<p>When you look at this again in the future, it will be much easier to read since you won't have the bloat of the <code>x-data</code> directive hiding all of the markup.</p>
<p><strong>Note</strong>: this is a simple trick for larger components but you should be careful to not abstract too early. If you are finding it difficult to manage your Alpine component from the <code>x-data</code> attribute, this one is definitely for you.</p>
<p>Since I'm a Laravel developer, I generally use a <code>@stack</code> on my layout file and push to it from inside of this partial.</p>
<pre><code class="language-html">@push('scripts')
&lt;script&gt;
window.profileForm = function () {
    return {
        name: '',
        email: '',
        password: '',
        errors: {
            name: [],
            email: [],
            password: [],
        },
        validate() {
            if (! this.name) {
                this.errors.name.push('You must enter your name.')
            }
    
            if (this.email &amp;&amp; ! this.email.includes('@')) {
                this.errors.email.push('You must enter a valid email address')
            }
    
            if (this.password &amp;&amp; this.password.length &lt; 8) {
                this.errors.password.push('Your password must be at least 8 characters long.')
            }
        }
    }
}
&lt;/script&gt;
@endpush
</code></pre>
<p>If you're using the latest version of Laravel, you can also wrap this <code>@push</code> in an <code>@once</code> and it will only ever be pushed to the stack once in the same render.</p>
<p><strong><code>x-spread</code></strong></p>
<p>This directive, <code>x-spread</code>, was introduced in <a href="https://github.com/alpinejs/alpine/releases">v2.4 of Alpine</a>. It allows you to bind a collection of directives to a component, similar to <code>x-bind=&quot;{}&quot;</code> in Vue.</p>
<p>This one kinds of follows on from the previous tip, where you can extract some re-usable logic into a function and then use <code>x-spread</code> to apply multiple directives at once.</p>
<p>Here's an example of a simple dropdown component built with Alpine. It involves binding some <code>aria-</code> attributes and a few click handlers. It also has no styles (but I'm sure you could make it look pretty).</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ open: false }&quot; @keydown.window.escape=&quot;open = false&quot; @click.away=&quot;open = false&quot;&gt;
    &lt;div&gt;
        &lt;span&gt;
            &lt;button @click=&quot;open = !open&quot; type=&quot;button&quot; id=&quot;options-menu&quot; aria-haspopup=&quot;true&quot; x-bind:aria-expanded=&quot;open&quot;&gt;
                Options
            &lt;/button&gt;
        &lt;/span&gt;
    &lt;/div&gt;

    &lt;div x-show=&quot;open&quot;&gt;
        &lt;div&gt;
            &lt;div&gt;
                &lt;a href=&quot;#&quot; role=&quot;menuitem&quot;&gt;Account settings&lt;/a&gt;
                &lt;a href=&quot;#&quot; role=&quot;menuitem&quot;&gt;Support&lt;/a&gt;
                &lt;a href=&quot;#&quot; role=&quot;menuitem&quot;&gt;License&lt;/a&gt;
                &lt;form method=&quot;POST&quot; action=&quot;#&quot;&gt;
                    &lt;button type=&quot;submit&quot; role=&quot;menuitem&quot;&gt;
                        Sign out
                    &lt;/button&gt;
                &lt;/form&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>The first step here is to move to an <code>x-data</code> function, like we did earlier. This is only going to hold a single piece of state, but it will be much easier to setup the <code>x-spread</code> directives later on.</p>
<pre><code class="language-html">&lt;div x-data=&quot;dropdown()&quot; @keydown.window.escape=&quot;open = false&quot; @click.away=&quot;open = false&quot;&gt;
    &lt;!-- Rest of markup here --&gt;
&lt;/div&gt;
</code></pre>
<pre><code class="language-js">window.dropdown = function () {
    return {
        open: false
    }
}
</code></pre>
<p>To start using the <code>x-spread</code> directive, we need to define an object on our component that will be used to bind the rest of the directives.</p>
<p>Let's first start with the <code>keydown</code> and <code>click</code> handlers on the parent element. I'm going to refer to this particular element as the &quot;wrapper&quot;, so let's call the object <code>wrapper</code>.</p>
<pre><code class="language-js">window.dropdown = function () {
    return {
        open: false,
        wrapper: {
            ['@keydown.window.escape']() {
                this.open = false
            },
            ['@click.away']() {
                this.open = false
            }
        }
    }
}
</code></pre>
<p>The <code>wrapper</code> object now contains 2 methods, each one matches the name of the directive it will replace and the function logic matches that of the expression.</p>
<p><strong>Note</strong>: Since this is now running inside of a function, Alpine will bind your data object to the <code>this</code> context of the function so be sure to use <code>this.[prop]</code> when reading and writing props.</p>
<p>The only thing left to do with our wrapper element is to remove the directives and add the new <code>x-spread</code> directive:</p>
<pre><code class="language-html">&lt;div x-data=&quot;dropdown()&quot; x-spread=&quot;wrapper&quot;&gt;
    &lt;!-- Rest of markup here --&gt;
&lt;/div&gt;
</code></pre>
<p>Under the hood, Alpine will go through the <code>wrapper</code> object and take each method name, setup the directive as usual and use the function as the expression / callback for the directive.</p>
<p>The same technique can be applied for the rest of the components too - the <code>trigger</code> and <code>menu</code> itself.</p>
<pre><code class="language-js">window.dropdown = function () {
    return {
        open: false,
        wrapper: {
            ['@keydown.window.escape']() {
                this.open = false
            },
            ['@click.away']() {
                this.open = false
            }
        },
        trigger: {
            ['@click']() {
                this.open = ! this.open
            },
            ['x-bind:aria-expanded']() {
                return this.open
            }
        },
        menu: {
            ['x-show']() {
                return this.open
            }
        }
    }
}
</code></pre>
<p>And the markup...</p>
<pre><code class="language-html">&lt;div x-data=&quot;dropdown()&quot; x-spread=&quot;wrapper&quot;&gt;
    &lt;div&gt;
        &lt;span&gt;
            &lt;button type=&quot;button&quot; id=&quot;options-menu&quot; aria-haspopup=&quot;true&quot; x-spread=&quot;trigger&quot;&gt;
                &lt;!-- Button markup here --&gt;
            &lt;/button&gt;
        &lt;/span&gt;
    &lt;/div&gt;

    &lt;div x-spread=&quot;menu&quot;&gt;
        &lt;!-- Rest of markup here --&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h3>Mixins</h3>
<p>In the context of a Vue component, <a href="https://vuejs.org/v2/guide/mixins.html">mixins</a> are just a way of having small bits of re-usable code that could be used throughout your application, in multiple types of component.</p>
<p>Since Alpine evaluates vanilla JavaScript and all of the data is powered by an object, this pattern is even easier to achieve through the use of the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">spread operator</a>.</p>
<p>Let's take our dropdown function from the previous section and use that as an example.</p>
<p>Imagine I had a component that needed the logic for a dropdown, but also some extra logic on top for changing the icon shown inside of a <code>&lt;button&gt;</code> element. The icon changing logic is only specific to this single component so it doesn't make much sense to abstract that out into the <code>dropdown()</code> function.</p>
<p>How about this, instead:</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ icon: 'up', ...dropdown() }&quot;&gt;
    &lt;!-- Rest of markup here --&gt;
&lt;/div&gt;
</code></pre>
<p>It's truly that simple. Since the <code>window.dropdown</code> function returns an object when invoked, we can &quot;spread&quot; the contents of that object into our data and still have access to the <code>trigger</code>, <code>wrapper</code> and <code>menu</code> objects for use with <code>x-spread</code>.</p>
<p>This pattern is really powerful for renderless components that are likely going to be used in multiple projects too. You could move the <code>window.dropdown</code> method into a re-usable JavaScript file or package and use it anywhere and everywhere (Alpine exists), then sprinkle your styling on top (hopefully with <a href="https://tailwindcss.com">Tailwind</a>).</p>
<p><strong>Note</strong>: You should be careful of any property name clashes, for example, multiple <code>open</code> props. To workaround this, you might accept an argument to the <code>dropdown()</code> function that has a unique &quot;key&quot; or &quot;prefix&quot; and add that to each of the props returned.</p>
<h2>Sign off</h2>
<p>This article was quite a long one, but these are some of the more common patterns for abstracting component logic and making your components more re-usable.</p>
<p>I didn't touch on server-side abstraction too much because not everybody has the power of <a href="https://laravel.com/docs/7.x/blade#components">Blade components</a> at their disposal, but I'm sure you can find your own ways of doing that too.</p>
<p>If you enjoyed this article and found it useful, I'd love to know on <a href="https://twitter.com/ryangjchandler">Twitter</a> since I would like to cover these concepts in more detail with better examples in the future.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 30 Aug 2020 18:30:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Accessing helper methods in your Livewire components]]></title>
                <link>https://ryangjchandler.co.uk/posts/accessing-helper-methods-in-your-livewire-components</link>
                <description><![CDATA[<p>Anyone who is familiar with <a href="https://laravel-livewire.com/">Livewire</a> has probably used <a href="https://laravel-livewire.com/docs/properties#computed-properties">computed properties</a> at some point. The magic behind them isn't actually all that magic.</p>
<p>Computed properties are accessed using the <code>$this</code> context of the Blade view. Livewire has a custom Blade compiler that essentially binds an instance of the component to <code>$this</code> so that magic methods can be used to intercept calls to non-existent &quot;computed&quot; properties.</p>
<p>This does open up some cool ideas though - one of them being helper methods on the component class.</p>
<h2>The idea</h2>
<p>Wouldn't it be amazing if you could change:</p>
<pre><code class="language-html">&lt;div&gt;
    &lt;select wire:model=&quot;selected&quot;&gt;
        @foreach(range(1, 100) as $number)
            &lt;option value=&quot;{{ $number }}&quot;&gt;
                {{ $number }}
            &lt;/option&gt;
        @endforeach
    &lt;/select&gt;
    
    @if($selected &gt; 0 &amp;&amp; $selected % 2 === 0 &amp;&amp; $selected &lt; 50)
        &lt;strong&gt;
            Congrats! Your number is even and in the correct range!
        &lt;/strong&gt;
    @endif
&lt;/div&gt;
</code></pre>
<p>Into this:</p>
<pre><code class="language-html">&lt;div&gt;
    &lt;select wire:model=&quot;selected&quot;&gt;
        @foreach($this-&gt;range() as $number)
            &lt;option value=&quot;{{ $number }}&quot;&gt;
                {{ $number }}
            &lt;/option&gt;
        @endforeach
    &lt;/select&gt;
    
    @if($this-&gt;selectionIsValid())
        &lt;strong&gt;
            Congrats! Your number is even and in the correct range!
        &lt;/strong&gt;
    @endif
&lt;/div&gt;
</code></pre>
<p>All of the logic for the iterable value and whether or not a valid selection has been can be moved out of the view and into the component class.</p>
<h2>The how</h2>
<p>It's not difficult. Move all of the logic into methods on the component class and Bob's your uncle, you've refactored to helper methods on your component class.</p>
<pre><code class="language-php">class Selection extends Component
{
    public function range()
    {
        return range(1, 100);
    }
    
    public function selectedIsValid()
    {
        return $this-&gt;selected &gt; 0 &amp;&amp; $this-&gt;selected &lt; 50 &amp;&amp; $this-&gt;selected % 2 === 0;
    }
}
</code></pre>
<h2>The why</h2>
<p>Personally, I like this approach since it my views are clearer and easier to follow. I'm not having to search through a clouded chunk of conditional mayhem to find out where something is being output. Instead, I can use appropriately named methods to describe the condition being checked and move on with my life.</p>
<p>Another benefit is that I can now use any <code>protected</code> or <code>private</code> dependencies from my class without needing to explicitely pass them through to the view, or use a computed property.</p>
<h2>Sign off</h2>
<p>If you found this little trick useful, let me know on <a href="https://twitter.com/ryangjchandler">Twitter</a> and share some examples of where you have benefited from it.</p>
<p><strong>Note</strong>: This feature isn't documented as part of Livewire's public API, so there could be some unexpected behaviour if used incorrectly. The same API is used for computed properties so without a major version update and breaking changes, this is unlikely going to change any time soon.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 24 Aug 2020 10:00:00 +0000</pubDate>
                                    <category>Livewire</category>
                            </item>
                    <item>
                <title><![CDATA[Creating custom magic variables in Alpine.js]]></title>
                <link>https://ryangjchandler.co.uk/posts/creating-custom-magic-variables-in-alpinejs</link>
                <description><![CDATA[<p>DRY code is important and it can be difficult to be <em>completely</em> DRY with your code, especially when you're using a front-end framework such as Alpine.</p>
<p>There a couple of ways to reduce code duplication, especially when it comes to utility functions for string manipulation or HTTP requests. With the release of Alpine v2.5 we can register custom magic variables that will allow us to reduce that duplication without copying and pasting functions, or adding a load of functions to the global namespace.</p>
<h2>The entry point</h2>
<p>All of Alpine's public API runs through a global <code>window.Alpine</code> object. Registering magic variables is no different.</p>
<p>A single call to <code>Alpine.addMagicProperty</code> will get you well on your way.</p>
<pre><code class="language-js">Alpine.addMagicProperty('property', function ($el) {

});
</code></pre>
<p>The first argument is the name of the magic property. If you're familiar with Alpine, you have probably already used <code>$refs</code>, <code>$dispatch</code> or <code>$el</code>.</p>
<p><strong>The name you provide doesn't need to have any prefix, Alpine will automatically add a <code>$</code> prefix so that it is more inline with the Alpine ones.</strong></p>
<p>The second argument is the callback for the magic variable. This function will receive the root element for the component, <strong>not</strong> the component instance itself.</p>
<p>You can use this callback to return a scalar value such as a string, boolean or integer, or even return another function so that the magic variable can be invoked.</p>
<h2>A good example</h2>
<p>Nowadays I try to avoid using third-party libraries (where possible) and ship JavaScript that utilises native browser APIs. Let's take this approach and create a little helper for the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>.</p>
<p>I want a magic variable called <code>$post</code> that will send a <code>POST</code> request to the URL provided as the first argument and pass along any data that I provide as the second argument.</p>
<pre><code class="language-js">Alpine.addMagicProperty('post', function () {
    return function (url, data = {}) {
        return fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            redirect: 'follow',
            body: JSON.stringify(data)
        });
    }
});
</code></pre>
<p>By returning a function from our callback, we can now invoke the <code>$post</code> property:</p>
<pre><code class="language-html">&lt;button type=&quot;button&quot; x-on:click=&quot;$post('/posts', { id: 1, title: 'Awesome New Post' })&quot;&gt;
  Create Post
&lt;/button&gt;
</code></pre>
<p>Pretty sweet, eh?</p>
<h2>Sign off</h2>
<p>This was just a short article to show you the API for creating custom magic variables / properties in your Alpine components.</p>
<p><strong>Note</strong>: This API is not documented and you should be careful using it.</p>
<p>If you want to see some more examples of magic properties, <a href="https://twitter.com/kevinbatdorf">Kevin Batdorf</a> has created a collection of packages  / helpers for you to use. Here is <a href="https://github.com/KevinBatdorf/alpine-magic-helpers">the GitHub link</a>. (Huge shoutout to Kevin for being so active and helpful on the <a href="https://discord.com/invite/snmCYk3">Alpine.js Discord</a> too!)</p>
<p>If you create any cool helper functions, please share them on <a href="https://twitter.com/ryangjchandler">Twitter</a>, I'm sure we'd all love to see them!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 23 Aug 2020 16:50:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Replicating `$.slideToggle` with Tailwind CSS & Alpine.js]]></title>
                <link>https://ryangjchandler.co.uk/posts/replicating-slidetoggle-with-tailwind-css-alpinejs</link>
                <description><![CDATA[<p>I think jQuery's greatest feature is all of the animation / transition utilities. These methods truly changed how fast you can build a clean and interactive UI with some nice animations along the way.</p>
<p>As people move away from jQuery though, it is hard to find a solid answer on how you can achieve a similar effect to <code>slideToggle</code>. I'm going to be using Tailwind v1.2+ alongside Alpine, using some modern CSS transformation rules.</p>
<h2>The basics</h2>
<p>CSS provides such really useful transformation properties that allow you to modify the appearance of an element. In this case, we want to use the <code>scaleY</code> transformation function. This will allow us to change the height of an element and Tailwind provides <code>scale-y-0</code> and <code>scale-y-100</code> classes for this.</p>
<p>We also want to add some transitions for this scale change, so we'll use Tailwind's <code>transition-</code> classes too.</p>
<p>On the Alpine side of things, we can use some <code>data-</code> attributes and event handlers to trigger the slide.</p>
<h2>The click</h2>
<p>The first thing needed is some sort of trigger. I'm going to use a <code>&lt;button&gt;</code> for this.</p>
<pre><code class="language-html">&lt;button @click.prevent=&quot;&quot;&gt;Toggle&lt;/button&gt;
</code></pre>
<p>We also need a scale target. You could hard-code this, but I want to make this re-usable and will instead use a <code>data-target</code> attribute. We can use this to declare the query selector of our target element.</p>
<pre><code class="language-html">&lt;button @click.prevent=&quot;&quot; data-target=&quot;#toggleTarget&quot;&gt;Toggle&lt;/button&gt;
</code></pre>
<p>It would help if that target <em>actually</em> existed on the page. I'll make it a sibling of the <code>&lt;button&gt;</code>, but you could put it anywhere on the page really.</p>
<pre><code class="language-html">&lt;button @click.prevent=&quot;&quot; data-target=&quot;#toggleTarget&quot;&gt;Toggle&lt;/button&gt;

&lt;div id=&quot;toggleTarget&quot;&gt;&lt;/div&gt;
</code></pre>
<h2>The base styles</h2>
<p>Our target also needs some classes for this to function correctly. These classes will apply some sensible defaults to the element so that we need to do less work with Alpine.</p>
<pre><code class="language-html">&lt;button @click.prevent=&quot;&quot; data-target=&quot;#toggleTarget&quot;&gt;Toggle&lt;/button&gt;

&lt;div id=&quot;toggleTarget&quot;
     class=&quot;transition-transform ease-out overflow-hidden origin-top transform&quot;
&gt;&lt;/div&gt;
</code></pre>
<p><code>transition-transform</code> will make sure that our target element will transform when any <code>transform: ...</code> properties change. The <code>ease-out</code> class defines our timing function, in this case: <code>transition-timing-function: ease-out</code>.</p>
<p>We want to hide any overflow inside of our target so that any text doesn't hang outside of it whilst scaling.</p>
<p><code>origin-top</code> will ensure our transformation uses the <strong>top</strong> of the element as its origin / base point. If you change this to <code>origin-bottom</code>, the <code>scale</code> will go from the top to the <strong>bottom</strong> of the element. Change this depending on which effect you prefer.</p>
<p><code>transform</code> tells Tailwind to add a master <code>transform</code> rule that will react to changes of CSS custom properties, made by the <code>scale-y-*</code> classes I mentioned earlier.</p>
<h2>Making it move</h2>
<p>Now that we have some basic classes on the target element, we can go ahead and start on toggle itself. I'm going to write all of this JavaScript inside of the <code>@click.prevent</code> on the <code>&lt;button&gt;</code>, but you are free to move this into a function.</p>
<p>We first need to get the target element:</p>
<pre><code class="language-html">&lt;button data-target=&quot;#toggleTarget&quot;
    @click.prevent=&quot;document.querySelector($event.target.dataset.target)&quot;
&gt;Toggle&lt;/button&gt;
</code></pre>
<p>Then we need to toggle the <code>scale-y-0</code> class.</p>
<pre><code class="language-html">&lt;button data-target=&quot;#toggleTarget&quot;
    @click.prevent=&quot;document.querySelector($event.target.dataset.target).classList.toggle('scale-y-0')&quot;
&gt;Toggle&lt;/button&gt;
</code></pre>
<p>If you add some dummy text to the target element, you'll notice that it toggles state correctly but there's no smooth animation. That is because we haven't added a <code>transition-duration</code> property to our target element.</p>
<p>There are a couple of options here:</p>
<ol>
<li>
<p>Add a class with a default duration. For example, <code>duration-500</code> will make sure that the transformation takes <strong>500ms</strong> to finish.</p>
</li>
<li>
<p>Add a class and support a <code>data-duration</code> attribute to change it on a trigger basis.</p>
</li>
</ol>
<p>The first option is pretty self-explanatory but I'd like to show you how to do the section approach too.</p>
<h2><code>data-duration</code> support</h2>
<p>Add a <code>data-duration</code> attribute to the trigger element. I'll use 700 as my default value.</p>
<pre><code class="language-html">&lt;button data-target=&quot;#toggleTarget&quot;
    data-duration=&quot;700&quot;
    @click.prevent=&quot;document.querySelector($event.target.dataset.target)&quot;
&gt;Toggle&lt;/button&gt;
</code></pre>
<p>Now, inside of your click handler we need to set the property on our target element, so let's do a little refactoring too:</p>
<pre><code class="language-html">&lt;button data-target=&quot;#toggleTarget&quot; 
    data-duration=&quot;700&quot;
    @click.prevent=&quot;
        const target = document.querySelector($event.target.dataset.target)
                    
        if ($event.target.dataset.duration) {
            target.style.transitionDuration = `${$event.target.dataset.duration}ms`            
        }
                    
        target.classList.toggle('scale-y-0')
    &quot;
&gt;Toggle&lt;/button&gt;
</code></pre>
<p>Since we need the target more than once, we can assign it to a constant. Then, using the <code>style</code> property of the element, set the <code>transitionDuration</code> property using the new <code>data-duration</code> attribute.</p>
<h2>Live example</h2>
<p>I've made a prettier example <a href="https://codepen.io/ryangjchandler/pen/YzqXzqo">here</a> for you to check out. You could take this a step-further and make a <code>window.$slideToggle</code> variable that has this as a function so that you can use it throughout your application.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 08 Aug 2020 16:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Route groups and `$router` (Unconventional Laravel)]]></title>
                <link>https://ryangjchandler.co.uk/posts/unconventional-laravel-route-groups-and-router</link>
                <description><![CDATA[<p>I'd estimate that 99% of Laravel applications register their routes using the <code>Illuminate\Support\Facades\Route</code> class. It looks a little something like:</p>
<pre><code class="language-php">use Illuminate\Support\Facades\Route;

Route::get('/projects', 'ProjectsController@index');
</code></pre>
<p>The official documentation tells you this is the way to register routes and most applications use this method.</p>
<h2>Route groups</h2>
<p>A route group is a way of collecting a number of routes and assigning the same properties, or options, to them. For example, you could prefix a group of routes with the same url:</p>
<pre><code class="language-php">Route::prefix('/projects')-&gt;group(function () {
    Route::get('/', 'ProjectsController@index');
    Route::get('/{project}', 'ProjectsController@show');
});
</code></pre>
<p>This is a super convenient way of reducing the amount of duplication you would get from individually registering routes with that <code>/projects</code> prefix.</p>
<p>But did you know that you can drop the use of the <code>Route</code> facade inside of the group callback and make use of a <code>$router</code> parameter instead?</p>
<h2>The <code>$router</code> parameter</h2>
<p>The <code>Closure</code> that is passed to the <code>group()</code> method can actually take an argument. I tend to call it <code>$router</code> but you can call it whatever you want. So taking the previous example of a route group, you can do this:</p>
<pre><code class="language-php">Route::prefix('/projects')-&gt;group(function ($router) {
    $router-&gt;get('/', 'ProjectsController@index');
    $router-&gt;get('/{project}', 'ProjectsController@show');
});
</code></pre>
<p>If you wanted to type-hint parameter, you should type hint the <code>Illuminate\Routing\Router</code> class. The line of code responsible can be <a href="https://github.com/illuminate/routing/blob/1206eeb0456e9760e321c64338b9f0e305263628/Router.php#L421">found here</a>.</p>
<h2>Pros &amp; Cons</h2>
<p>To be honest, there aren't really any big pros or cons to this approach. It's more of a &quot;Did you know you <em>could</em> do this?&quot; one.</p>
<p>Some people might think that there is a performance benefit since you're not calling a method on the <code>Route</code> facade each time, but after testing this with 100 routes the difference was literally a couple of milliseconds. This would be down to the fact that, under the hood, Laravel caches the underlying instance so that it doesn't need to be resolved from the container each time.</p>
<h2>Sign off</h2>
<p>If you've ever seen or used this approach before, I'd love to know on <a href="https://twitter.com/ryangjchandler">Twitter</a>.</p>
<p>Thanks for reading 👋</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 13 Jul 2020 16:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Synchronous jobs for reusability (Unconventional Laravel)]]></title>
                <link>https://ryangjchandler.co.uk/posts/unconventional-laravel-synchronous-jobs-for-reusability</link>
                <description><![CDATA[<p>Most applications use jobs as a way of pushing heavy logic off of the main thread and doing work asynchronously, in the background.</p>
<p>After looking at some larger applications, I found a few that used synchronous jobs as a way of splitting up application logic into reusable components.</p>
<h2>The idea</h2>
<p>Laravel provides some convenient ways of dispatching jobs. If you had a job called <code>CreateSubscription</code> you could push it to the queue using <code>CreateSubscription::dispatch()</code>. You could also process it synchronously using <code>CreateSubscription::dispatchNow()</code>.</p>
<p>A little known fact is that you can actually return things from the job itself.</p>
<p>Let's create a barebones job:</p>
<pre><code class="language-php">use App\Models\User;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\Queue\ShouldQueue;

class CreateSubscription implements ShouldQueue
{
    use Dispatchable;
    
    private $user;
  
    private $plan;
    
    public function __construct(User $user, string $plan)
    {
        $this-&gt;user = $user;
        $this-&gt;plan = $plan;
    }
}
</code></pre>
<p>The job will receive an instance of <code>App\Models\User</code> and store it in a <code>private</code> property. The visibility of this property isn't important since this job will be self handling.</p>
<p>Here's the <code>handle</code> method:</p>
<pre><code class="language-php">public function handle()
{
    $subscription = SomeSubscriptionService::create([
        'email' =&gt; $this-&gt;user-&gt;email,
        'plan' =&gt; $this-&gt;plan,
    ]);

    $this-&gt;user-&gt;update([
        'subscription_id' =&gt; $subscription-&gt;id,
    ]);

    return $subscription;
}
</code></pre>
<p>The logic isn't important for this article. The important part is the <code>return $subscription</code> at the end of the method.</p>
<p>If we were to dispatch this job inside of a controller:</p>
<pre><code class="language-php">class SubscriptionController
{
    public function store(Request $request)
    {
        $subscription = CreateSubscription::dispatchNow(
            $request-&gt;user(),
            $request-&gt;input('plan')
        );
        
        return redirect()-&gt;route('subscription.thank-you', [
            'plan' =&gt; $subscription-&gt;plan,
        ]);
    }    
}
</code></pre>
<p>The return value of the job will be given back to the controller, in this case assigned to a variable so that it can be used further along.</p>
<h2>Pros</h2>
<h3>It's a job, queue it when you want</h3>
<p>Since this is just a regular Laravel job that implements the <code>ShouldQueue</code> marker interface, you could just as easily push it to the queue using <code>CreateSubscription::dispatch()</code>.</p>
<p>There's no need to change the logic at all, since the return value will just get thrown away, it won't harm the queue.</p>
<p>With the example above where you <em>need</em> the subscription afterwards, it doesn't make much sense, but for something like <code>RenewSubscription</code>, you could use the job synchronously when the user manually renews in the browser, then use the same job from a scheduled command that handles automatic renewals or something.</p>
<h3>Reusability</h3>
<p>These jobs are reusable and can be used anywhere in your applications (controllers, listeners, commands, etc). This benefit is a little less important because in reality you could create any sort of class and have it do the same thing, just like the &quot;action&quot; pattern that is quite popular.</p>
<h2>Cons</h2>
<h3>It's different</h3>
<p>Jobs aren't designed for this. They can do it, but according to convention they shouldn't. If a new developer comes on to a project and sees this, they're probably going to think &quot;What the f&amp;$*?&quot;.</p>
<h3>It's not officially documented</h3>
<p>This functionality won't be found anywhere in the <a href="https://laravel.com">official Laravel docs</a>, so it could disappear in a major version update. I doubt it will, but it <strong>could</strong>.</p>
<h2>Sign off</h2>
<p>If you've ever used this pattern, let me know on <a href="https://twitter.com/ryangjchandler">Twitter</a> because I'd love to know. Let me know if you have any questions or things you think I missed.</p>
<p>I'd like to shout out <a href="https://laravel.io">laravel.io</a> too (<a href="https://twitter.com/driesvints">Dries</a>), since this is where I initially discovered this functionality. You can take a look at the <a href="https://github.com/laravelio/laravel.io">GitHub repo</a> to find out a bit more.</p>
<p>As always, thanks for reading! 👋</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 05 Jul 2020 16:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Auto-validating models (Unconventional Laravel)]]></title>
                <link>https://ryangjchandler.co.uk/posts/unconventional-laravel-auto-validating-models</link>
                <description><![CDATA[<p>In most applications validation logic is placed in standardised places. You can do it inside of <code>FormRequest</code> objects or as part of your controller logic. You could even do it inside of your middleware if you really wanted to.</p>
<p>Have you ever considered removing that logic from your main request / response flow and holding the model accountable instead? If not, let me show you how it can be done and some of the pros and cons.</p>
<h2>How?</h2>
<h3>Model events</h3>
<p>Most Laravel developers have used model events at some point in their career. If you haven't, here is how they work.</p>
<pre><code class="language-php">&lt;?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class Post extends Model
{
    public static function boot()
    {
        parent::boot();

        static::creating(function (Post $post) {
            if (!$post-&gt;slug) {
                $post-&gt;slug = Str::slug($post-&gt;title);
            }
        });
    }
}
</code></pre>
<p>When a new <code>Post</code> model is created using the <code>Post::create()</code> method, our closure will be run before it has actually been saved / persisted. <code>Model::creating()</code> is just one example. There are <code>::created()</code>, <code>::saving()</code>, <code>::saved()</code> and so many more. You can read more about them in the <a href="https://laravel.com/docs/7.x/eloquent#events">Laravel documentation</a>.</p>
<p>Generally speaking, these events are used to ensure that some property is always present or auto-generated on the model. Ensuring something exists kind of sounds like validation, doesn't it?</p>
<h3>Validating the model</h3>
<p>Now that we know how model events work, we can utilise them and validate our models on creation. Take a look at the following code:</p>
<pre><code class="language-php">&lt;?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Validator;

class Post extends Model
{
    public static $rules = [
        'title' =&gt; 'required|string|max:255',
        'slug' =&gt; 'required|string',
        'excerpt' =&gt; 'nullable|string|max:160',
        'published_at' =&gt; 'nullable|date',
    ];

    public static function boot()
    {
        parent::boot();

        static::creating(function (Post $post) {
            Validator::validate($post-&gt;toArray(), static::$rules);
        });
    }
}
</code></pre>
<p>The rules are defined on the model as a static property, since they're unlikely to change. In the event that they do change, you could always define a <code>getRulesArray()</code> method on the model, and use the following snippet instead.</p>
<pre><code class="language-php">static::creating(function (Post $post) {
    Validator::validate($post-&gt;toArray(), $post-&gt;getRulesArray());
});
</code></pre>
<pre><code class="language-php">public function getRulesArray(): array
{
    return [
        'title' =&gt; 'required|string|max:255',
        'slug' =&gt; 'required|string',
        'excerpt' =&gt; 'nullable|string|max:160',
        'published_at' =&gt; 'nullable|date',
    ];
}
</code></pre>
<p>The second approach would make more sense when you need to conditionally apply some logic based on a property on the model, but in most cases I'd find a <code>static</code> array to be fine. One example might be a <code>unique</code> rule that needs to ignore the current model when updating / saving.</p>
<h2>Things to note</h2>
<p><strong>Hidden properties</strong></p>
<p>Unfortunately Laravel's validator doesn't work with objects, meaning the <code>Model::toArray()</code> method is needed. The problem here is you might not actually be able to validate all of the properties if you're using the <code>protected $hidden</code> property on the model.</p>
<p>This would be the case for the default <code>User</code> model that Laravel provides and the <code>password</code> column. One way to work around this is by making those properties visible during validation:</p>
<pre><code class="language-php">protected $hidden = ['published_at'];

static::creating(function (Post $post) {
    $post-&gt;makeVisible(['published_at']);
  
    Validator::validate($post-&gt;toArray(), static::$rules);
});
</code></pre>
<p>Now when the <code>$post-&gt;toArray()</code> call is made, the <code>published_at</code> column will be present and processed.</p>
<h2>Pros</h2>
<h3>Knowledge encapsulation</h3>
<p>One common thing, especially in more domain-driven patterns, is ensuring that your HTTP layer knows as little as possible about your database. In Laravel, this means your model becomes a God class full of database knowledge, and your controllers simply call methods without knowing what columns are present and what data types they are.</p>
<p>With this auto-validation pattern, that is easy enough to achieve. Your controller no longer needs to do any validation or worry about what data is being validated. Your model handles all of that and encapsulates it in a single place.</p>
<h3>Re-usability</h3>
<p>Even if you didn't want to do the whole auto-validation thing, you could still place your rules on the model and use those elsewhere. This is another point on top of my last one. As long as you know the name of the method (use some sort of interface if you want), your controller won't know anything about the rules present, just that it needs to do some sort of validation.</p>
<p>A smaller point is that any changes to the rules will be applied everywhere. You won't need to go through all of your controllers / form requests and change them.</p>
<h3>Forget about the boring stuff</h3>
<p>Validation is boring. This approach will mean you only have to do is in one place, just create your models as regular elsewhere. Forget about the boring stuff and enjoy the magic.</p>
<h2>Cons</h2>
<h3>Redirect loops</h3>
<p>Since the <code>Validator::validate()</code> method throws a <code>ValidationException</code> when validation fails, Laravel will try to catch that exception and redirect back to the previous location.</p>
<p>If for whatever reason your previous location was the same as the route where validation is failing, you will probably get stuck an a redirect loop.</p>
<p>Be sure to only use this auto-validation pattern on separate routes, i.e. <code>GET /posts</code> and <code>POST /posts</code> would be fine.</p>
<h3>Side effects</h3>
<p>As mentioned a second ago, Laravel will pick up on the <code>ValidationException</code> and try to redirect the user back with some errors. This means that something that happens in the database layer <em>could</em> have some effect on the HTTP layer of your application.</p>
<p>This doesn't bother me much, but there will be some people who find this disgusting and some sort of anti-pattern. Remember though, this is an <strong>unconventional</strong> thing to do.</p>
<h3>&quot;Bottom of the drawer&quot; logic</h3>
<p>The final con that I'd like to mention is that this pattern will push all of your validation to the &quot;bottom of the drawer&quot;. By that I mean the validation itself is hidden when looking at your controllers and other parts of your application, so when something goes wrong or you need to add a new validation rule, it might cause some headaches or digging to find out where it is all taking place.</p>
<h2>Sign off</h2>
<p>Thanks for reading! I'm super excited to write some more articles about strange patterns you can use in your Laravel applications.</p>
<p>If you're interested in using this automatic validation pattern in your applications, I've created a small package that will can make it a bit easier to get started with. Check it out on my <a href="https://github.com/ryangjchandler/laravel-auto-validate-models">GitHub</a> or click <a href="https://github.com/ryangjchandler/laravel-auto-validate-models">this link</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 02 Jul 2020 16:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Add classes to active links in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/add-classes-to-active-link-in-laravel</link>
                <description><![CDATA[<p>Generally speaking, the easiest way to do this is comparing the name of the current route and the one you'd like to test against.</p>
<p>Luckily, Laravel's <code>Illuminate\Support\Facades\Route</code> class provides a nice <code>currentRouteName()</code> method that we can use to make a comparison.</p>
<p>Let's create a little function that you can re-use throughout your application.</p>
<pre><code class="language-php">use Illuminate\Support\Facades\Route;

function active_route(string $name): bool
{
    return Route::currentRouteName() === $name;
}
</code></pre>
<p>This function is great, but it doesn't do anything with classes. Let's add a second parameter so that a class string such as <code>'bg-gray-900'</code> could be passed through.</p>
<pre><code class="language-php">use Illuminate\Support\Facades\Route;

function active_route(string $name, string $classes): bool
{
    if ($active = Route::currentRouteName() === $name) {
        echo $classes;
    }
  
    return $active;
}
</code></pre>
<p>Perfect! Now we can pass in the name of a route and a class string and it will <code>echo</code> the class if the current route matches the one provided.</p>
<p>If we wanted to, we could also wrap this into a custom Blade directive. In any <code>ServiceProvider::boot()</code>, add the following snippet:</p>
<pre><code class="language-php">Blade::directive('active', function ($expression) {
    return &quot;&lt;?php \active_route({$expression}); ?&gt;&quot;
});
</code></pre>
<p>Inside of a Blade template, we could now do:</p>
<pre><code class="language-blade">@active('projects.index', 'bg-gray-900 hover:bg-gray-500')
</code></pre>
<p>And it would work just the same as calling <code>active_route()</code> directly. Nice!</p>
<h2>Going beyond</h2>
<p>One way this could be improved is conditionally checking whether or not a second parameter is passed through via the directive. This means you could treat <code>@active</code> as an <code>if</code> statement and do something based on the true and false conditions.</p>
<p>Let's make the second parameter to <code>active_route()</code> optional and add some checks to see how many parameters the directive receives:</p>
<pre><code class="language-php">use Illuminate\Support\Facades\Route;

function active_route(string $name, string $classes = null): bool
{
    if ($active = Route::currentRouteName() === $name &amp;&amp; $classes) {
        echo $classes;
    }
  
    return $active;
}
</code></pre>
<pre><code class="language-php">use Illuminate\Support\Facades\Blade;

Blade::directive('active', function ($expression) {
    $parts = explode(',', str_replace(['(', ')'], '', $expression));
  
    if (count($parts) === 1) {
        return &quot;&lt;?php if (active_route({$expression})) : ?&gt;&quot;;
    }
  
    return &quot;&lt;?php \active_route({$expression}); ?&gt;&quot;
});
</code></pre>
<p>It seems a bit confusing at first, but I'll break it down:</p>
<ol>
<li>
<p>When our custom directive handler is called, it will receive <code>$expression</code> as a string. For example, <code>@active('projects.index')</code> will mean expression is <code>('projects.index')</code>. The parentheses are included, so we need to remove those from the string before running <code>explode()</code>.</p>
</li>
<li>
<p><code>explode(',', ...)</code> will split the string after each <code>,</code>. If two arguments are provided, then were should be a comma separating them. You could run into problems here if you use commas in your route names, but I've never seen anybody do that, most people use full-stops. In the case that no commas are present, <code>$parts</code> will just be an array with a single item.</p>
</li>
<li>
<p>If there is only 1 &quot;part&quot; (the length of <code>$parts</code> is 1), then we can assume that we're in <code>if else</code> mode, so we return an <code>if</code> statement instead of the string. Luckily, our <code>active_route()</code> function already returns a boolean, no matter the number of arguments received.</p>
</li>
</ol>
<p>Now, we can do something like:</p>
<pre><code class="language-php">@active('projects.index') bg-gray-900 hover:bg-gray-500 @else bg-gray-400 @endif
</code></pre>
<h3>@endactive vs. @endif</h3>
<p>We've only got a single <code>if</code> statement, so using <code>@endif</code> is perfectly fine. If you wanted to make it a bit prettier, you could just add the following bit of code;</p>
<pre><code class="language-php">Blade::directive('endactive', function () {
    return '&lt;?php endif; ?&gt;';
});
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 29 Jun 2020 15:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Share data with your frontend in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/share-data-with-your-frontend-in-laravel</link>
                <description><![CDATA[<p>Have you ever needed access to the current user's name or email address in your applications JavaScript? There are many different ways it can be done, but let's take a look at the 2 simplest methods.</p>
<h2>Constrained access</h2>
<p>It's not always the best idea to put this data everywhere on your site. You might only need it when working with a particular element or view, this is where <code>data-</code> attributes come in handy.</p>
<p>Given the following HTML, I need to show the current user's name when the button is clicked, otherwise, just show a generic &quot;Hello&quot; message. By default, it will show the generic message.</p>
<pre><code class="language-html">&lt;button type=&quot;button&quot; id=&quot;show&quot;&gt;Show Email Address&lt;/button&gt;
&lt;p id=&quot;message&quot;&gt;Hello&lt;/p&gt;
</code></pre>
<p>Let's add a <code>data-name</code> attribute to the <code>&lt;p&gt;</code> element.</p>
<pre><code class="language-html">&lt;button type=&quot;button&quot; id=&quot;show&quot;&gt;Show Email Address&lt;/button&gt;
&lt;p id=&quot;message&quot; data-name=&quot;{{ $user-&gt;name }}&quot;&gt;Hello&lt;/p&gt;
</code></pre>
<p>Now if we want to access it inside of our JavaScript, we can:</p>
<pre><code class="language-js">document.getElementById('show').addEventListener('click', el =&gt; {
    const el = document.getElementById('message')
    
    el.innerText = `Hello, ${el.dataset.name}`
})
</code></pre>
<p>Any <code>data-*</code> attributes can be accessed using the &quot;camel case&quot; equivalent. For example, <code>data-first-name</code> can be accessed using <code>el.dataset.firstName</code>.</p>
<p>In the case you have a model, you'll need to <code>{{ $user-&gt;toJson() }}</code> in the Blade template and then <code>JSON.parse(el.dataset.user)</code> in JavaScript to access it correctly.</p>
<h2>Global object</h2>
<p>The next one is useful if you've got loads of different scripts that rely on the data.</p>
<p>In a layout file, we can add a <code>&lt;script&gt;</code> somewhere in <code>&lt;head&gt;</code> of the document.</p>
<pre><code class="language-html">&lt;head&gt;
    &lt;script&gt;
        window.sharedData = {}
    &lt;/script&gt;
&lt;/head&gt;
</code></pre>
<p>It's just an empty object, but there is 2 different approaches we can take here. Either declare the property using JavaScript and ensure we <code>json_encode()</code> each value, or instead <code>json_encode()</code> an associative array and let PHP handle it all (nearly).</p>
<h3>Each item</h3>
<pre><code class="language-html">&lt;head&gt;
    &lt;script&gt;
        window.sharedData = {
            user: {{ json_encode(auth()-&gt;user()) }},
            ids: {{ json_encode([1, 2, 3]) }}
        }
    &lt;/script&gt;
&lt;/head&gt;
</code></pre>
<h3>Associative array</h3>
<pre><code class="language-html">&lt;head&gt;
    &lt;script&gt;
        window.sharedData = json_encode([
            'user' =&gt; auth()-&gt;user(),
            'ids' =&gt; [1, 2, 3],
        ])
    &lt;/script&gt;
&lt;/head&gt;
</code></pre>
<p>It's worth noting that any objects that get serialized will have all of their <code>public</code> properties exposed in the resulting object.</p>
<p>If you want to customise the serialized form, you can implement the <code>JsonSerializable</code> interface and add a <code>jsonSerialize()</code> method. This method should return an array with the things you'd like to expose.</p>
<h2>Going beyond</h2>
<p>The methods above don't take all scenarios into account. For example, any class that implements the <code>Arrayable</code> or <code>Jsonable</code> contracts won't be serialized using the <code>toArray()</code> or <code>toJson()</code> methods.</p>
<p>You should also be careful of any HTML or double quotes when serialising user-created values. I'd suggest passing through the <code>JSON_HEX_QUOT | JSON_HEX_APOS</code> flags to <code>json_encode()</code>. These flags will convert all <code>&quot;</code> and <code>'</code> to their Unicode equivalent.</p>
<p>There are plenty of packages out there that can share server-side values with your client-side scripts (<a href="https://github.com/coderello/js-shared-data">coderello/js-shared-data</a> comes to my mind), but for the simpler cases, the 2 methods above should be enough.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 26 Jun 2020 13:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Manually refreshing a Livewire component]]></title>
                <link>https://ryangjchandler.co.uk/posts/manually-refreshing-a-livewire-component</link>
                <description><![CDATA[<p>Livewire's polling API is great for periodically refreshing your component or invoking an action, but one of the more quietly documented features is the ability to manually refresh a component using a &quot;magic&quot; action.</p>
<p>Here's how:</p>
<pre><code class="language-html">&lt;div&gt;
    &lt;button wire:click=&quot;$refresh&quot;&gt;Reload Component&lt;/button&gt;
&lt;/div&gt;
</code></pre>
<p>And that is it! The &quot;magic&quot; <code>$refresh</code> action can be used, anywhere an action can, in your component. Livewire will pick up the action name and simply re-render the component.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 10 Jun 2020 11:00:00 +0000</pubDate>
                                    <category>Livewire</category>
                            </item>
                    <item>
                <title><![CDATA[Clearer time values with Carbon]]></title>
                <link>https://ryangjchandler.co.uk/posts/clearer-time-values-with-carbon</link>
                <description><![CDATA[<p>Lots of applications involve date and time manipulation. Whether it's figuring out what day of the week it is, how many seconds are in a week or how many hours are in a century.</p>
<p>Quite often, you'll see something like:</p>
<pre><code class="language-php">$minutesInAWeek = 7 * 24 * 60
</code></pre>
<p>On a small scale, it's quite clear what is going on, but if you wrap this bit of logic in a function or another calculation, you can quickly lose sight of what <code>60</code> represents.</p>
<p>Luckily, <a href="https://carbon.nesbot.com/">Carbon</a> provides a set of <a href="https://carbon.nesbot.com/docs/#api-constants">constants</a> that can clear it up, making it easy to see what each number represents.</p>
<p>Lets take our example above and use these constants to make what's happening clearer:</p>
<pre><code class="language-php">use Carbon\Carbon;

$minutesInAWeek = Carbon::DAYS_PER_WEEK * Carbon::HOURS_PER_DAY * Carbon::MINUTES_PER_HOUR;
</code></pre>
<p>Yes, it's verbose. But this kind of verbosity is good, in my opinion.</p>
<p>If we wanted to take this further and figure out how many seconds are in a year, we could do:</p>
<pre><code class="language-php">use Carbon\Carbon;

$minutesInAWeek = Carbon::DAYS_PER_WEEK * Carbon::HOURS_PER_DAY * Carbon::MINUTES_PER_HOUR;

$secondsInAYear = $minutesInAWeek * Carbon::SECONDS_PER_MINUTE * Carbon::WEEKS_PER_YEAR;
</code></pre>
<p>There's some more constants too, you can check out <a href="https://carbon.nesbot.com/docs/#api-constants">the full list in the documentation</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 08 Jun 2020 21:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Generate an array of dates using Carbon]]></title>
                <link>https://ryangjchandler.co.uk/posts/generate-an-array-of-dates-using-carbon</link>
                <description><![CDATA[<p>When a customer at <a href="https://surewise.com">Surewise</a> wants to take out a new insurance policy, they can only take one out with a start date within the next thirty days.</p>
<p>Date pickers are horrendnous with browser compatibility, given IE11 and Safari don't support them, so we instead choose to use a simple <code>&lt;select&gt;</code> element with the dates as <code>&lt;option&gt;</code> inside.</p>
<p>Here's how you can generate an array of dates for a given period:</p>
<pre><code class="language-php">use Carbon\{
    CarbonPeriod,
    Carbon
};

CarbonPeriod::create(
    Carbon::now(),
    Carbon::now()-&gt;addDays(30)
);
</code></pre>
<p>Calling this method will return an instance of <code>Carbon\CarbonPeriod</code> which has implements the  <code>Iterator</code> interface and can therefore be used inside of a <code>foreach</code> statement.</p>
<p>When looping over the <code>CarbonPeriod</code> instance, the iteration variable will be an instance of <code>Carbon\Carbon</code>, so you can call all of the regular <code>format</code> and <code>toDateTimeString()</code> methods.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 02 Jun 2020 18:00:00 +0000</pubDate>
                                    <category>PHP</category>
                            </item>
                    <item>
                <title><![CDATA[Simple repositories in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/simple-repositories-in-laravel</link>
                <description><![CDATA[<p>The &quot;Repository pattern&quot; is essentially another level of abstraction on top of your database abstraction layer. In the context of Laravel, these are simple classes with methods that call more complex chains of methods on your model classes.</p>
<p>Generally, each repository is responsible for <strong>one</strong> entity within your application. For example, a <code>UserRepository</code> should only be responsible for retrieving <code>User</code> records.</p>
<h2>Abstract implementation</h2>
<p>I've seen various people use traits to implement repositories directly inside of their models. Personally I think this gives the model too much responsibility, especially since models in Laravel are essentially &quot;God classes&quot; already.</p>
<p>Instead, I'll create an <strong>abstract class</strong> that all of the repository classes will extend:</p>
<pre><code class="language-php">&lt;?php
  
namespace App\Repositories;

abstract class Repository
{
    //
}
</code></pre>
<p>All of the repository classes will live inside of the <code>app/Repositories</code> folder and are namespaced accordingly. If you're following a domain-driven design, you could put this class inside of a &quot;shared&quot; domain.</p>
<p>Each repository needs to have some model-based context, so we'll add a <code>static</code> property to our base class.</p>
<pre><code class="language-php">&lt;?php
  
namespace App\Repositories;

abstract class Repository
{
    protected static string $model;
}
</code></pre>
<p>I've chosen to make this <code>protected</code> since I don't need to access it externally, but I still need to have access to it / overwrite it in the child class. You could make it <code>public</code> if you wanted to do some conditional logic based on the value.</p>
<p>This <code>$model</code> property should contain the fully-qualified namespace of a model class, for example <code>User::class</code>.</p>
<p>The reason this implementation of the repository pattern is so simple is that all method calls from inside of the class will be delegated to an instance of <code>$model</code>.</p>
<p>The missing piece of the puzzle is the all-mighty magic <code>__call()</code> method.</p>
<pre><code class="language-php">&lt;?php
  
namespace App\Repositories;

use Illuminate\Support\Facades\App;

abstract class Repository
{
    protected static string $model;

    public function __call(string $name, array $arguments)
    {
        return App::make(static::$model)-&gt;{$name}(...$arguments);
    }
}
</code></pre>
<p>Now whenever we call a method that doesn't exist on your repository class, it will instead be delegated / deferred to an instance of the underlying <code>$model</code>.</p>
<h2>An example</h2>
<p>A quick example would be creating a <code>UserRepository</code> that has some useful methods for finding a <code>User</code> by <code>email</code>, <code>name</code> and <code>id</code>.</p>
<pre><code class="language-php">&lt;?php
  
namespace App\Repositories;

use App\User;

class UserRepository extends Repository
{
    protected static string $model = User::class;
  
    public function findByName(string $name): ?User
    {
        return $this-&gt;where('name', $name)-&gt;first();
    }
  
    public function findByEmail(string $email): ?User
    {
        return $this-&gt;where('email', $email)-&gt;first();
    }
  
    public function findById(int $id): ?User
    {
        return $this-&gt;find($id);
    }
}
</code></pre>
<p>Then, inside of a controller you could pull the repository in using dependency injection:</p>
<pre><code class="language-php">&lt;?php
  
namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController
{
    protected $users;
  
    public function __construct(UserRepository $users)
    {
        $this-&gt;users = $users;    
    }
}
</code></pre>
<h2>Sign off</h2>
<p>I'd love to know if anyone else has used this pattern in their applications and how they implemented it. Comment below or <a href="https://twitter.com/ryangjchandler">tweet me</a> if you have.</p>
<p>See ya! 👋</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sun, 24 May 2020 18:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[Directive precedence in Alpine]]></title>
                <link>https://ryangjchandler.co.uk/posts/directive-precedence-in-alpine</link>
                <description><![CDATA[<p>Since Alpine doesn't have a virtual DOM and doesn't compile your templates, it evaluates a component's directives procedurally, in the order that they are defined.</p>
<h2>Directive evaluation</h2>
<p>When defining your directives on a component, the order <strong>does</strong> matter.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ text: 'Hello' }&quot;&gt;
    &lt;p x-text=&quot;text&quot; x-bind:style=&quot;color: red;&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>In the example above, our text will be set <strong>before</strong> the <code>style</code> attribute is updated. This could cause problems since you will see a flash of black, or whatever the default <code>color</code> is, before the <code>x-bind:style</code> directive is evaluated.</p>
<p>To counter this problem, you could swap the two directives around:</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ text: 'Hello' }&quot;&gt;
    &lt;p x-bind:style=&quot;color: red;&quot; x-text=&quot;text&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>Now the <code>x-bind:style</code> is reached first, then our <code>x-text</code> directive is evaluated.</p>
<p>Another option would be adding <code>x-cloak</code> to the element, <strong>at the end</strong>.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ text: 'Hello' }&quot;&gt;
    &lt;p x-text=&quot;text&quot; x-bind:style=&quot;color: red;&quot; x-cloak&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>Now the <code>&lt;p&gt;</code> will be hidden (<a href="https://ryangjchandler.co.uk/articles/hiding-elements-until-alpine-is-ready-with-x-cloak">as long as you have the correct CSS</a>) until Alpine has completely initialised the element.</p>
<p>If you're interested in the piece of code that handles all of the evaluation, you can find it <a href="https://github.com/alpinejs/alpine/blob/67493c138e9e9282dd85839f5c410791981a798f/src/component.js#L250">here in the GitHub repository</a>.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 19 May 2020 20:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Hiding elements until Alpine loads with `x-cloak`]]></title>
                <link>https://ryangjchandler.co.uk/posts/hiding-elements-until-alpine-is-ready-with-x-cloak</link>
                <description><![CDATA[<p>If you've used Alpine before, you might have seen a brief flick when you load your site up. This is common if you have components that are conditionally rendered and are hidden by default.</p>
<p>What's happening is the DOM is ready before Alpine takes controls of the element, so it shows up and then disappears. It can be quite jarring if you have lots of components on your site.</p>
<p>To counter the problem, Alpine will look for an <code>x-cloak</code> attribute and remove it once it has loaded. This lets you defined some CSS that will set the element to <code>display: none</code> when the page loads.</p>
<p>Add this bit of CSS to your site:</p>
<pre><code class="language-css">[x-cloak] {
    display: none !important;
}
</code></pre>
<p>And Bob's your uncle, the flicker problem has been fixed!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 15 May 2020 16:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Maintainable Alpine.js components]]></title>
                <link>https://ryangjchandler.co.uk/posts/organising-your-alpine-components</link>
                <description><![CDATA[<p>I've been using Alpine for the last couple of months in most of my projects and have experimented with different organisation patterns that improve the maintainability of my components.</p>
<p>I'd like to take you through some of them, as well as the pros and cons of each.</p>
<h2>Data functions</h2>
<p>This one shouldn't be new to regular Alpine users. This approach replaces the inline <code>x-data</code> object literal with a function that returns an object instead.</p>
<pre><code class="language-html">&lt;div x-data=&quot;data()&quot;&gt;
    &lt;p x-text=&quot;text&quot;&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;script&gt;
    function data() {
        return {
            text: &quot;Hello, World!&quot;
        }
    }
&lt;/script&gt;
</code></pre>
<p><strong>Pros</strong>:</p>
<ul>
<li>For component with larger datasets, it's far easier to manage than an object string.</li>
<li>You can add methods to the returned object that it also easier to manage.</li>
<li>Makes using Alpine with third-party libraries simpler.</li>
</ul>
<p><strong>Cons</strong>:</p>
<ul>
<li>Function must be defined on the <code>window</code> object, so a large number of unique components starts to add lots of bloat to the global namespace.</li>
<li>These objects aren't structured in any particular way, your data is sat directly next to your methods.</li>
<li>When placed in an inline <code>&lt;script&gt;</code> tag, you lose the ability to minify your JavaScript and reduce data transfer sizes.</li>
</ul>
<p><strong>Summary</strong></p>
<p>This approach works great for small sites and developers who don't mind explicitely putting everything under <code>window</code> . It's also useful if you're integrating with third party libraries that interact with your Alpine components.</p>
<h2>Async components</h2>
<p>If you have used Vue before, you'll probably be familiar with the concept of asynchronous components, a design pattern that only loads the component / JavaScript when a particular component is needed.</p>
<p>This is especially useful when using code-splitting / browser-supported ES modules. I'll show you an example using browser-supported ES modules:</p>
<pre><code class="language-javascript">// index.js (loaded in browser using &lt;script type=&quot;module&quot;&gt;
;(async function() {
    if (document.querySelector('[x-data=&quot;example()&quot;]')) {
        await import('./components/example.js').then(module =&gt; window['example'] = module.default)
    }
})()

// ./components/example.js
export default function() {
    return {
        message: 'Hello!',
        clear() {
            this.message = ''
        }
    }
}
</code></pre>
<p>The code above is taking advantage of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports"><strong>dynamic imports</strong></a>. This is supported in all major modern browsers, not IE11. If you need to support IE11, I'd suggest creating a separate bundle that has support for it.</p>
<p>In this instance, we are checking to see if any <code>example</code> components are found on the page. If one is found, we want to load the code for that component. This is stored inside <code>components/example.js</code> . Again, this example is using ES modules hence the exports.</p>
<p>When the component is found on the page, we want to dynamically import the file responsible for the component and assign the default export to a <code>window.example</code> variable so that Alpine can call it.</p>
<p><strong>Pros</strong>:</p>
<ul>
<li>Uses modern JavaScript features with no transpilation, can run directly in the browser.</li>
<li>Only the code that is needed gets loaded, so no unnecessary data transfer.</li>
<li>Component logic can be separated into individual files, on a component by component basis.</li>
</ul>
<p><strong>Cons</strong>:</p>
<ul>
<li>Uses modern JavaScript features with no transpilation so won't run directly in IE11.</li>
<li>Won't be useful when dynamically inserting content into page, since it does not re-evaluate on page mutation, but this could easily be fixed with a <code>MutationObserver</code> .</li>
<li>Still a big blur of data properties and logical methods.</li>
<li>Still using puts functions on <code>window</code> object.</li>
</ul>
<p>To counter the last &quot;con&quot;, I've found a way that makes it clearer what is what in my head.</p>
<pre><code class="language-javascript">// utils.js
export const buildComponent = (data, methods, __init) {
    return () =&gt; {
        return {
            ...data,
            ...methods,
            __init
        }
    }
}
</code></pre>
<p>Inside of your component file, you can then import this function and use it to separate your data, methods and init method.</p>
<pre><code class="language-javascript">import { buildComponent } from '../utils.js'

const data = {
    message: 'Hello!',
}

const methods = {
    clear() {
        this.message = ''
    }
}

export default buildComponent(data, methods)
</code></pre>
<p>The only thing that I don't like about <em>this</em> approach is referencing <code>this</code> inside of my methods doesn't give my any autocomplete, nor is it clear what <code>this</code> is.</p>
<h2>Laravel Blade Components</h2>
<p>For Laravel developers, this one will most likely work the best.</p>
<p>Instead of using regular partials, you can turn your Alpine component into a Blade component and use it like a regular HTML element.</p>
<pre><code class="language-blade">// components/input.blade.php
&lt;div x-data=&quot;{ text: '' }&quot;&gt;
    &lt;input x-model=&quot;text&quot; {{ $attributes }}&gt;
&lt;/div&gt;

// index.blade.php
&lt;div&gt;
    &lt;x-input type=&quot;text&quot; name=&quot;hello&quot; id=&quot;hello&quot; /&gt;
&lt;/div&gt;
</code></pre>
<p>Unless your smaller components are being used in lots of different places, this probably won't be useful for most sites. For larger components, such as modals and dropdowns, you can nicely hide all of the logic in your component file and still pass the regular HTML attributes through.</p>
<p>If you're using JavaScript functions to setup your component and data, you could add a custom <code>@pushonce</code> directive so that you can use inline <code>&lt;script&gt;</code> tags. The idea behind this is that you include a <code>&lt;script&gt;</code> tag with the component, inside of the <code>@pushonce</code> directive that is pushed to an <code>@stack</code> in your layout file.</p>
<p>This approach is going to be most similar to a single file Vue component, since you have your markup, JavaScript and you could even <code>@pushonce</code> your CSS too.</p>
<p><strong>Pros</strong>:</p>
<ul>
<li>Excellent reusability of both the markup and the JavaScript.</li>
<li>Most familiar to Vue single file component pattern.</li>
<li>Fluent use of HTML-like tags, with support for passing regular attributes through.</li>
</ul>
<p><strong>Cons</strong>:</p>
<ul>
<li>Requires Laravel (or a Blade package for external use).</li>
<li>JavaScript being inlined with <code>@pushonce</code> can't be minified.</li>
<li>Only really good for high usage components, no real gain for single use components.</li>
</ul>
<p>Here's that <code>@pushonce</code> directive for you:</p>
<pre><code class="language-php">Blade::directive('pushonce', function ($expression) {
    [$pushName, $pushSub] = explode(':', trim(substr($expression, 1, -1)));

    $key = '__pushonce_'.str_replace('-', '_', $pushName).'_'.str_replace('-', '_', $pushSub);

    return &quot;&lt;?php if(! isset(\$__env-&gt;{$key})): \$__env-&gt;{$key} = 1; \$__env-&gt;startPush('{$pushName}'); ?&gt;&quot;;
});
				 
Blade::directive('endpushonce, function () {
    return '&lt;?php $__env-&gt;stopPush(); endif; ?&gt;';
});
</code></pre>
<h3>Outside of Laravel</h3>
<p>If you're using other frameworks, or completely different languages, most templating engines have the concept of partials where you could apply the same pattern, just without the nice HTML-ish tags.</p>
<h2>Sign off</h2>
<p>I'm glad you made it this far. These were just a couple of tips on organising your Alpine components and how I've personally been doing it recently.</p>
<p>As the project evolves, there will definitely be new and improved ways to do this so I'll be sure to keep an eye out for new ideas and share them with you all too.</p>
<p>I'd also like to say another thank you for sponsoring me, it means a lot that people are genuinely interested and support what I do. As always, all feedback is welcome no matter how good or bad it is, so let me know what you thought through <a href="https://twitter.com/ryangjchandler">Twitter</a> or Discord.</p>
<p>Have a good one! 👋</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Fri, 15 May 2020 11:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Track your users last activity in Laravel]]></title>
                <link>https://ryangjchandler.co.uk/posts/track-your-users-last-activity-in-laravel</link>
                <description><![CDATA[<p>Although there's many ways to do this in Laravel, the simplest way is with a piece of <code>web</code> middleware.</p>
<h2>The setup</h2>
<p>When an authenticated user visits a route in our application, we want to store the timestamp in the database for use later on. Let's store it in a column called <code>last_active_at</code>.</p>
<p>All you need to do is create a migration:</p>
<pre><code class="language-bash">php artisan make:migration add_last_active_at_to_users_table --table=users
</code></pre>
<p>And add the following line in the <code>up()</code> method:</p>
<pre><code class="language-php">$table-&gt;timestamp('last_active_at')-&gt;nullable();
</code></pre>
<p>If the user has never visited a route, it will remain <code>NULL</code> in the database.</p>
<p>We also want to make sure this field is &quot;fillable&quot;, so add <code>last_active_at</code> to the <code>protected $fillable</code> array on your <code>User</code> model.</p>
<p>As well as being able to update <code>last_active_at</code> using <code>User::update()</code>, we want to cast it to a <code>Carbon\Carbon</code> instance when using it so that we can make use of time comparison methods.</p>
<h2>The middleware</h2>
<h3>Logic</h3>
<p>The middleware will be responsible for checking the authentication status and updating the <code>last_active_at</code> column.</p>
<pre><code class="language-php">namespace App\Http\Middleware;

use Illuminate\Http\Request;
use Closure;

class TrackLastActiveAt
{
    public function handle(Request $request, Closure $next)
    {
        if (! $request-&gt;user()) {
            return $next($request);
        }

        if (! $request-&gt;user()-&gt;last_active_at || $request-&gt;user()-&gt;last_active_at-&gt;isPast()) {
            $request-&gt;user()-&gt;update([
                'last_active_at' =&gt; now(),
            ]);
        }

        return $next($request);
    }
}
</code></pre>
<p>Here's what happens in order:</p>
<ol>
<li>We check the current user is authenticated. If they're not, we're returning early so that the rest of the middleware has no effect.</li>
<li>If the current user <code>last_active_at</code> date &amp; time is <code>NULL</code> or is in the past, we want to update it using the current date and time. Thankfully, Laravel has a <code>now()</code> helper function that returns an instance of <code>Carbon\Carbon</code> for the current date and time.</li>
<li>Forward the current request on to the next middleware.</li>
</ol>
<h3>Registration</h3>
<p>We have a couple of different options for registering the middleware. If you want to track your users activity across <strong>all</strong> routes, it should be registered under the <code>web</code> array in <code>App\Http\Kernel</code>:</p>
<pre><code class="language-php">protected $middlewareGroups = [
    'web' =&gt; [
        // ...
        \App\Http\Middleware\TrackLastActiveAt::class,
    ]
]
</code></pre>
<p>If you only want to track the latest activity for particular routes, you can register the middleware as part of your route registration:</p>
<pre><code class="language-php">Route::get('/foo', 'FooController')-&gt;middleware([\App\Http\Middleware\TrackLastActiveAt::class]);
</code></pre>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Thu, 23 Apr 2020 23:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[An alternative approach to computed properties in Alpine.js]]></title>
                <link>https://ryangjchandler.co.uk/posts/an-alternative-approach-to-computed-properties-in-alpinejs</link>
                <description><![CDATA[<p>The other day, I wrote an article on <a href="/articles/pseudo-computed-properties-in-alpine">how to achieve a similar effect to computed properties</a> in <a href="https://github.com/alpinejs/alpine">Alpine.js</a>. The approach that I took involved simply calling a method that returned a value:</p>
<pre><code class="language-html">&lt;div x-data=&quot;data()&quot;&gt;
    &lt;span x-text=&quot;hello()&quot;&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;script&gt;
function data() {
    return {
        hello: function () {
            return &quot;Hello!&quot;
        }
    }
}
&lt;/script&gt;
</code></pre>
<p>This works quite well, but they're not <em>really</em> properties anymore. The <code>&lt;span&gt;</code> <em>is</em> still reactive, so if the return value depended on another data property, the UI would be updated when the dependency gets changed. To my eyes, <code>property()</code> isn't as pretty as <code>property</code> on its own.</p>
<p>Today though, I saw a tweet from <a href="https://twitter.com/sebdedeyne">Sebastian De Deyne</a> that took a different approach to the same concept.</p>
<div class="flex justify-center">
<blockquote class="twitter-tweet"><p lang="en" dir="ltr"><a href="https://twitter.com/calebporzio?ref_src=twsrc%5Etfw">@calebporzio</a> Quick Alpine question, can I use getters in x-data, or am I going to shoot myself in the foot somehow? <a href="https://t.co/nBo4YcVNzZ">pic.twitter.com/nBo4YcVNzZ</a></p>&mdash; Sebastian De Deyne (@sebdedeyne) <a href="https://twitter.com/sebdedeyne/status/1252562642172067840?ref_src=twsrc%5Etfw">April 21, 2020</a></blockquote> &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8">&lt;/script>
</div>
<p>This approach just didn't occur to me at first. It's probably because I hadn't actually tried it. The first thing I did was hop into CodePen and try it out:</p>
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="ryangjchandler" data-slug-hash="rNOWBrB" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Getters Alpine.js">
  <span>See the Pen <a href="https://codepen.io/ryangjchandler/pen/rNOWBrB">
  Getters Alpine.js</a> by Ryan Chandler (<a href="https://codepen.io/ryangjchandler">@ryangjchandler</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
&lt;script async src="https://static.codepen.io/assets/embed/ei.js">&lt;/script>
<p>Out of the box, it just works! Click the button on the right and watch the <code>&lt;span&gt;</code> below update. I almost feel kind of stupid that I hadn't though of this originally. Since Alpine is using an object literal as its source of data, we can use all of the normal things an object provides, such as <a href="https://javascript.info/property-accessors">getters and setters</a>.</p>
<p>The other added benefit this method provides is that you <strong>don't</strong> need to add the parentheses anymore because when Alpine tries to access the property, the JavaScript engine will recognise that there is a getter defined and call that for us.</p>
<h2>Browser compatibility</h2>
<p>Regular <code>getters</code> and <code>setters</code> are supported in all modern browsers and ... 🥁 all the way back to Internet Explorer 9. The only thing that isn't supported that far back is computed property names, so you can't do things like:</p>
<pre><code class="language-javascript">function data() {
    return {
        get [expression]() {
            return 'Hello!'
        }
    }
}
</code></pre>
<p>The expression is dynamic and acts like a fallthrough if the property doesn't exist or doesn't have a getter defined already. That's not a big deal, because nobody should be using IE9 today. Seriously, <strong>nobody</strong>.</p>
<h2>Sign off</h2>
<p>Thanks to <a href="https://twitter.com/sebdedeyne">Sebastian</a> for tweeting about this. You can read some of his blog posts on <a href="https://sebastiandedeyne.com/">his personal blog</a> too.</p>
<p>Personally I'm going to be using this approach going forward, especially since the browser support is so good (unusual, I know).</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Mon, 20 Apr 2020 23:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Anonymous Alpine.js components]]></title>
                <link>https://ryangjchandler.co.uk/posts/anonymous-alpine-components</link>
                <description><![CDATA[<p>At its core, Alpine depends on an <code>x-data</code> attribute. At the time of writing this article, there isn't any other way to let Alpine know your component exists. One fun fact is that your <code>x-data</code> attribute can actually be empty and have no value at all.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{}&quot;&gt;&lt;/div&gt;

// this gets treated the same as above
&lt;div x-data&gt;&lt;/div&gt;
</code></pre>
<p>Alpine will default to using an empty object literal, so you don't have to worry about it. By doing this, we aren't setting up any data properties that need to be reactive in our UI, but we can still take advantage of Alpine's Vue-esque event binding syntax.</p>
<pre><code class="language-html">&lt;div x-data&gt;
  &lt;button x-on:click=&quot;eventHandler()&quot;&gt;Click me!&lt;/button&gt;
&lt;/div&gt;
</code></pre>
<p>I like to call this concept <em>Anonymous Components</em>, since Alpine has no data context to keep track of. If you're familiar with Laravel and the new Blade Components in version 7, you would have heard the same name being used for components that have no class handler and are simply regular Blade views (Thanks <a href="https://twitter.com/driesvints">Dries</a>!).</p>
<h2>Why though?</h2>
<p>The real question is &quot;Why not?&quot;. Let's list the alternative routes:</p>
<ol>
<li>Inline event registration using <code>&lt;button onclick=&quot;eventHandler()&quot;&gt;</code></li>
<li>Event property registration using <code>el.onclick = eventHandler</code></li>
<li>Registering event listeners using <code>el.addEventListener('click', eventHandler)</code>.</li>
</ol>
<p>This anonymous component approach is, syntactically, most similar to option number one. You are registering the event listener / handler using an attribute on the element itself.</p>
<p>Option number two is nearly the same, except this code needs to be executed from inside of a <code>&lt;script&gt;</code> tag, much like option number three.</p>
<p>Despite some of the performance problems with option number one, before using Alpine, I wouldn't actually have a problem with doing this for smaller components on my sites.</p>
<p>When looking at the markup, I can clearly see what function is going to be called when the event fires and for which event it is triggered for. Unless I actually need to edit or write the function, there is no need to switch context either. I don't need to do a project wide search for this function, or traipse through JavaScript files to find where and when the function is being called.</p>
<p>Under the hood, Alpine is using option number three (<code>addEventListener</code>) to actually register the event so the only performance bottleneck is going to be how quickly Alpine can traverse the DOM and find the <code>x-on:</code> or <code>@</code> attributes. Given the small size of Alpine and its declarative nature, this is something I'm quite happy to forget about since its going to be minimally different from writing the code myself in an inline <code>&lt;script&gt;</code> tag, or importing a JavaScript file.</p>
<h2>Things to be aware of</h2>
<p>If you decide to use this approach in your applications, there are a couple of things to keep in mind.</p>
<h3>Your function / handler must be defined on the global scope</h3>
<p>This can become a problem if you are transpiling / bundling your JavaScript, since it's normally scoped down to the module level automatically.</p>
<p>To circumvent this problem, explicitly define your functions on the <code>window</code> variable:</p>
<pre><code class="language-javascript">// bad
function eventHandler() {
  ...
}

// good
window.eventHandler = function () {
  ...
}
</code></pre>
<h3>You need the parentheses in the expression</h3>
<p>In other Alpine components, you might choose to define functions on the data object itself. When doing this, you can reference your event callback functions without the ending <code>()</code> parentheses. Alpine does this automatically for functions defined on your data object by checking the return value of your expression, then calling it if it is of the type <code>function</code>.</p>
<p>If you are using a function that's defined on the global scope, you will need to add those <code>()</code> parentheses yourself.</p>
<pre><code class="language-html">// bad
&lt;button x-on:click=&quot;eventHandler&quot;&gt;Click me&lt;/button&gt;

// good
&lt;button x-on:click=&quot;eventHandler()&quot;&gt;Click me&lt;/button&gt;
</code></pre>
<h3>The event won't be automatically passed through</h3>
<p>When using functions defined on your data object (as mentioned above), your function will receive a magic <code>$event</code> property as the first argument. This behaviour is the same as any other event handler in JavaScript, most commonly shortened to a single <code>e</code>.</p>
<p>Since we're having to put the parentheses in yourselves, we'll also need to pass through any of those mystical Alpine properties too.</p>
<pre><code class="language-html">&lt;button x-on:click=&quot;eventHandler($event)&quot;&gt;Click me&lt;/button&gt;
</code></pre>
<p>Now we can access properties such as <code>$event.target</code> or <code>$event.type</code> in our function.</p>
<h3>You don't have to write a function</h3>
<p>All the way through this post, I've used a function on the global scope as my event handler. Since Alpine will evaluate the expression inside of the attribute, you could also write some inline JavaScript too.</p>
<pre><code class="language-javascript">&lt;button x-on:click=&quot;$event.target.style.display = 'none'&quot;&gt;Hide me&lt;/button&gt;
</code></pre>
<h2>Sign off</h2>
<p>This is probably my current favourite use case for Alpine. Sure, the reactivity is cool but this can be so much cooler.</p>
<p>If you do get stuck with this approach at all, feel free to ask me questions on <a href="https://twitter.com/ryangjchandler">Twitter @ryangjchandler</a>. I've also put a quick example <a href="https://codepen.io/ryangjchandler/pen/wvKzypX?editors=1111">here on CodePen</a>.</p>
<p>Thanks for sticking around this far, have a good one!</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 18 Apr 2020 23:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Pseudo-computed properties in Alpine.js]]></title>
                <link>https://ryangjchandler.co.uk/posts/pseudo-computed-properties-in-alpine</link>
                <description><![CDATA[<p>I've been trying to use <a href="https://github.com/alpinejs/alpine">Alpine.js</a> more and more throughout my projects, both personal and professional. At work, most of the JavaScript is still using good ol' jQuery (yeah, I know 🤦‍♂️) so it's been super nice to sprinkle some lightweight reactivity and interactive goodness in there too.</p>
<p>Most of Vue's general API has been matched in Alpine. The directives, modifiers and general functionality is near enough identical. One thing that Alpine doesn't have out of the box is <a href="https://vuejs.org/v2/guide/computed.html">computed properties</a>. In reality a computed property is just a function that returns a value, as opposed to a property with a value assigned to it directly.</p>
<p>My example for this article will be reversing a string. Let's take a look at the Vue implementation first, taken straight from the docs:</p>
<h2>Vue</h2>
<pre><code class="language-html">&lt;div id=&quot;example&quot;&gt;
    &lt;p&gt;Original message: &quot;{{ message }}&quot;&lt;/p&gt;
    &lt;p&gt;Computed reversed message: &quot;{{ reversedMessage }}&quot;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<pre><code class="language-javascript">var vm = new Vue({
    el: '#example',
    data: {
        message: 'Hello'
    },
    computed: {
        // a computed getter
        reversedMessage: function() {
            // `this` points to the vm instance
            return this.message.split('').reverse().join('')
        }
    }
})
</code></pre>
<p>When we take a look at the HTML in the browser, we get this:</p>
<p><img src="https://raw.githubusercontent.com/ryangjchandler/ryangjchandler.co.uk/jigsaw/source/assets/images/vue-computed-properties.png" alt="Vue Computed Properties Example" /></p>
<p>When we use <code>{{ reversedMessage }}</code> in our HTML / template, Vue will look for a property inside of the <code>computed</code> array with the same name and call the function to get the value.</p>
<h2>Alpine</h2>
<p>Let's try and recreate this with Alpine:</p>
<pre><code class="language-html">&lt;div x-data=&quot;data()&quot;&gt;
    &lt;p&gt;Original message: &quot;&lt;span x-text=&quot;message&quot;&gt;&lt;/span&gt;&quot;&lt;/p&gt;
    &lt;p&gt;Computed reversed message: &quot;&lt;span x-text=&quot;reversedMessage&quot;&gt;&lt;/span&gt;&quot;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<pre><code class="language-javascript">function data() {
    return {
        message: 'Hello',
        reversedMessage: function () {
            return this.message.split('').reverse().join('')
        }
    }
}
</code></pre>
<p>This is what we get:</p>
<p><img src="https://raw.githubusercontent.com/ryangjchandler/ryangjchandler.co.uk/jigsaw/source/assets/images/alpine-computed-properties-1.png" alt="Alpine Computed Properties Attempt" /></p>
<p>The problem here is that Alpine doesn't know that our <code>reversedMessage</code> expression inside of <code>x-text</code> needs to be evaluated as a function. Instead, the function gets cast to a string by the browser.</p>
<p>The way to fix this would be by changing <code>reversedMessage</code> to <code>reversedMessage()</code> and voila:</p>
<p><img src="https://raw.githubusercontent.com/ryangjchandler/ryangjchandler.co.uk/jigsaw/source/assets/images/alpine-computed-properties-2.png" alt="Alpine Computed Properties Working" /></p>
<p>Now it's calling the function and setting the return value as the text for our element. It's really that easy! I'm calling these &quot;pseudo computed properties&quot; since Alpine doesn't automatically determine whether or not the property is a function, but they are actually computed properties.</p>
<p>These computed properties are reactive too. Changing the value of <code>message</code> using an <code>&lt;input&gt;</code> field or similar would update the computed value too.</p>
<h2>Sign off</h2>
<p>The example a above is a bit redundant and could actually be done as an inline expression with Alpine &amp; Vue. This might become more useful for certain types of data, such as the price of a product. You could use a computed property to prefix the output with a currency symbol (£, $, etc) and ensure that there is always 2 decimal points.</p>
<p>If you like this little trick, please consider sharing on Twitter and keep an eye out for more posts on cool things you can do with Alpine.js!</p>
<p>Have a good one :)</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Wed, 15 Apr 2020 23:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
                    <item>
                <title><![CDATA[Get an array of unique values in JavaScript]]></title>
                <link>https://ryangjchandler.co.uk/posts/get-an-array-of-unique-values-in-javascript</link>
                <description><![CDATA[<p>For anyone who has used PHP before, you're probably familiar with the <code>array_unique()</code> function. You would use it like this:</p>
<pre><code class="language-php">array_unique([1, 2, 3, 4, 5, 5, 6, 7, 7]); // returns [1, 2, 3, 4, 5, 6, 7]
</code></pre>
<p>Unfortunately, JavaScript doesn't have a the core functionality to achieve the same result. Luckily for us, there is a couple of different ways to get there.</p>
<p>These methods are going to assume that you are using primitive values (string, number, etc).</p>
<h2>Distinct Filtering</h2>
<p>This approach requires a method that filters the array down. We'll start by defining the <code>distinct()</code> method:</p>
<pre><code class="language-javascript">function distinct(value, index, items) {
    return items.indexOf(value) === index;
}

// or a single-liner
const distinct = (value, index, items) =&gt; items.indexOf(value) === index;
</code></pre>
<p>All this function does it check to see if the <code>index</code> of our current <code>value</code> inside of the <code>items</code> array matches our current index. If it returns <strong>true</strong>, then we want to keep it in the array since its the first occurrence. If it returns <strong>false</strong>, it means that the <code>value</code> has been found somewhere else in the array so it gets filtered out.</p>
<p>Of course, this function doesn't do the removing so we need to pass it into <code>Array.filter()</code>:</p>
<pre><code class="language-javascript">const distinct = (value, index, items) =&gt; items.indexOf(value) === index;

let numbers = [1, 2, 3, 4, 5, 5, 6, 7, 7];

let distinctNumbers = numbers.filter(distinct); // returns [1, 2, 3, 4, 5, 6, 7]
</code></pre>
<p>That wasn't hard now, was it?</p>
<h2>Set objects</h2>
<p>If you've not heard of <code>Set</code> objects before, they are essentially arrays that can store primitive values, as well as object references, but have enforced uniqueness. That means no two values can be the same inside of a <code>Set</code>, which helps us out a bunch.</p>
<pre><code class="language-javascript">let distinctNumbers = new Set([1, 2, 3, 4, 5, 5, 6, 7, 7])
</code></pre>
<p>Our <code>numbers</code> variable now holds an instance of <code>Set</code> with <code>[1, 2, 3, 4, 5, 6, 7]</code>. For most of us, this wouldn't be a problem since <code>Set</code> has various methods such as <code>forEach()</code>, <code>values()</code> and <code>entries()</code> so we could do common operations on the <code>Set</code> directly, but what if we needed to use the <code>.indexOf()</code> method again? It won't work, correct!</p>
<p>The next step is transforming our <code>Set</code> into an <code>Array</code>. In modern browsers, that can be done really easily using the spread (<code>...</code>) operator.</p>
<pre><code class="language-javascript">let distinctNumbers = [...new Set([1, 2, 3, 4, 5, 5, 6, 7, 7])]
</code></pre>
<p>That's all. We now have an array of unique values. If you wanted, you could package this into a nice little helper function called <code>arrayUnique</code>:</p>
<pre><code class="language-javascript">const arrayUnique = (array) =&gt; [...new Set(array)]
</code></pre>
<p>Copy and paste that into your <code>utils.js</code> file or wherever you store those sort of functions.</p>
<h2>Sign off</h2>
<p>Thanks for reading the article. Not much to read really, but it's a useful helper function to have until it gets implemented on the <code>Array</code> object.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 07 Apr 2020 23:00:00 +0000</pubDate>
                                    <category>JavaScript</category>
                            </item>
                    <item>
                <title><![CDATA[Prevent updating or saving of Laravel models]]></title>
                <link>https://ryangjchandler.co.uk/posts/prevent-updating-or-saving-of-laravel-models</link>
                <description><![CDATA[<p>For example, after a model gets created I don't want anyone to be able to update that record again. Instead, it should get overwritten with a brand new record and archived.</p>
<p>Here's a simple trait that you can use on your models to disable updating:</p>
<pre><code class="language-php">trait PreventsUpdating
{
    public static function bootPreventsUpdating()
    {
        static::updating(function (Model $model) {
            return false;
        });
    }
}
</code></pre>
<p>Simply use this on your model and you will no longer be able to update it.</p>
<h3>Improvements</h3>
<p>We could take this a step further and make it more reusable and DRY-er.</p>
<pre><code class="language-php">trait PreventsModelEvents
{
    public static function bootPreventsModelEvents()
    {
        foreach (static::$prevents as $event) {
            static::{$event}(function (Model $model) {
                return false;
            });
        }
    }
}
</code></pre>
<p>Now when we want to use it on a model, we can do this:</p>
<pre><code class="language-php">class User extends Model
{
    use PreventsModelEvents;

    protected static $prevents = ['updating'];
}
</code></pre>
<p>When we try to update our <code>User</code> model, it will be stopped and will return false. This can be applied to the other events such as <code>saving</code> and <code>creating</code> too.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Tue, 31 Mar 2020 11:00:00 +0000</pubDate>
                                    <category>Laravel</category>
                            </item>
                    <item>
                <title><![CDATA[What is Alpine.js?]]></title>
                <link>https://ryangjchandler.co.uk/posts/what-is-alpinejs</link>
                <description><![CDATA[<p>If you're a part of the Laravel community, you've probably already heard of Alpine. It's a minimalistic JavaScript framework that ditches the virtual DOM in favour of raw DOM updates and operations. The documentation says to <em>Think of it like <a href="https://tailwindcss.com/">Tailwind</a> for JavaScript.</em></p>
<p>Syntactically, it's inspired by Vue. This isn't a problem because Vue has the most beginner friendly and natural syntax in my opinion.</p>
<p>Let me show you where it all starts:</p>
<pre><code class="language-html">&lt;div x-data=&quot;{}&quot;&gt;
    &lt;span&gt;Sweet, sweet content.&lt;/span&gt;
&lt;/div&gt;
</code></pre>
<p>Everything in Alpine begins with a custom attribute, <code>x-data</code>. If you come from the Vue world, this is essentially the <code>data</code> property on one of your components. Alpine will search through your DOM, find all of the elements with this attribute and set them up for some sweet vanilla reactivity.</p>
<h2>What can I put in this attribute?</h2>
<p>That's a good question. In the same way as your Vue component data, the <code>x-data</code> attribute should contain a JavaScript object, something like this:</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ foo: 'bar' }&quot;&gt;
    &lt;span&gt;Sweet, sweet content.&lt;/span&gt;
&lt;/div&gt;
</code></pre>
<p>When the DOM is scanned, Alpine will take this <code>x-data</code> attribute, run it through a clever little <code>eval</code> function (don't worry, it's not the regular core <code>eval()</code> function) that is powered by <code>Function</code> objects and then start to observe the data.</p>
<blockquote>
<p>One thing to note here is that Alpine does not observe the original data object directly. Instead, it will make a clone of that object and store it elsewhere for observations.</p>
</blockquote>
<h2>Okay, that's cool. How do I use this data?</h2>
<p>It's simple. Just like Vue, Alpine provides a variety of different directives that can be used to access and control your data.</p>
<p>Let's start by making the text inside of the <code>span</code> match the value of our <code>foo</code> data property.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ foo: 'bar' }&quot;&gt;
    &lt;span x-text=&quot;foo&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
</code></pre>
<p>Now, when we view this HTML inside of the browser, we'll see that our <code>&lt;span&gt;</code> has the word <code>bar</code> inside of it. Want to know the best part of this? There is no virtual DOM, no crazy diff process going on. Just 7kb of JavaScript.</p>
<h3>Changing the value of data properties</h3>
<p>The example above is a bit pointless really. There's no way for us to change the value of <code>foo</code> so it's just static. Let's change this now by adding an input field.</p>
<pre><code class="language-html">&lt;div x-data=&quot;{ foo: 'bar' }&quot;&gt;
    &lt;span x-text=&quot;foo&quot;&gt;&lt;/span&gt;
    &lt;input type=&quot;text&quot; x-model=&quot;foo&quot;&gt;
&lt;/div&gt;
</code></pre>
<p>Alpine provides another directive <code>x-model</code> which acts the same way as the one in Vue. Whenever we change the value inside of the input, our <code>foo</code> property will be updated and the text inside of our <code>&lt;span&gt;</code> will react.</p>
<p>I've put this on CodePen so you can play around with it <a href="https://codepen.io/ryangjchandler/pen/oNXJaKg">here</a>, or use the embed below:</p>
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="html,result" data-user="ryangjchandler" data-slug-hash="oNXJaKg" data-preview="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Alpine.js Simple Data Reactivity ">
  <span>See the Pen <a href="https://codepen.io/ryangjchandler/pen/oNXJaKg">
  Alpine.js Simple Data Reactivity </a> by Ryan Chandler (<a href="https://codepen.io/ryangjchandler">@ryangjchandler</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
&lt;script async src="https://static.codepen.io/assets/embed/ei.js">&lt;/script>
<h2>Show me more</h2>
<p>I'm going to post some more articles on using Alpine and how it might be able to replace Vue or React in some of your applications.</p>
<p>If you want to get ahead of the game, check out <a href="https://github.com/alpinejs/alpine">the README file in the GitHub repo</a> which is the current official documentation.</p>
<p>Let me know what you thought about this article on Twitter! I'm always up for improving my writing so every opinion is welcome.</p>
]]></description>
                <author><![CDATA[Ryan Chandler]]></author>
                <pubDate>Sat, 28 Mar 2020 00:00:00 +0000</pubDate>
                                    <category>Alpine.js</category>
                            </item>
            </channel>
</rss>
