<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://matthewdaly.co.uk</id>
    <title>Matthew Daly</title>
    <updated>2025-12-31T20:24:27.914Z</updated>
    <generator>GatsbyJS</generator>
    <author>
        <name>Matthew Daly</name>
        <email>matthew@matthewdaly.co.uk</email>
        <uri>https://matthewdaly.co.uk</uri>
    </author>
    <link rel="alternate" href="https://matthewdaly.co.uk"/>
    <link rel="self" href="/atom.xml"/>
    <subtitle>I'm a web developer in Norfolk. This is my blog...</subtitle>
    <icon>https://matthewdaly.co.uk/favicon-32x32.png</icon>
    <rights>All rights reserved Matthew Daly 2025</rights>
    <contributor>
        <name>Matthew Daly</name>
        <email>matthew@matthewdaly.co.uk</email>
        <uri>https://matthewdaly.co.uk</uri>
    </contributor>
    <entry>
        <title type="html"><![CDATA[Goodbye 2025]]></title>
        <id>https://matthewdaly.co.uk/blog/2025/12/31/goodbye-2025/</id>
        <link href="https://matthewdaly.co.uk/blog/2025/12/31/goodbye-2025/"/>
        <updated>2025-12-31T12:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>OK, today&#x27;s the last day of 2025, and while I&#x27;m not usually one for blogging specifically about things like this, I feel like this year it would be helpful to make an exception. It&#x27;s been a year when my interests have covered quite a bit of stuff outside web development, and as a result I&#x27;ve done more different things that I wouldn&#x27;t have done beforehand.</p><h2>What I&#x27;ve done this year</h2><p>As I write this, I realise I haven&#x27;t actually written <em>any</em> blog posts this year before today, which is unfortunate, but I&#x27;ve had other priorities. In my own time, I&#x27;ve taken a bit of a step back from web development in many ways, and have done very little outside my day job on it. To some extent that reflects a certain maturity in my learning path - I&#x27;m well into senior/lead developer territory now, professionally speaking, and I&#x27;m more confident that I don&#x27;t have anything to prove.</p><p>If I needed to pivot to a new language or framework, I could do so easily, and in fact this year I&#x27;ve built my first two full-stack Typescript applications from scratch as Azure functions to demonstrate this. And I&#x27;m well placed to navigate the changes caused by AI adoption in the industry - I consider myself a realist and I have adopted it as a tool while being well aware of its downsides. Three years ago I observed that it was likely to move the developer&#x27;s role from the productive to a more executive capacity, and largely that&#x27;s what&#x27;s happened as we&#x27;ve gone through from better autocomplete with Copilot through to largely autonomous agents. If suddenly I had to do without those I&#x27;d survive, but at the same time they&#x27;re a potentially useful tool when used right.</p><p>It&#x27;s not that I&#x27;ve plateaued in my work, by any means, but there&#x27;s only so many languages and frameworks that you can usefully pick up in a career, and there&#x27;s little point learning a new framework you&#x27;re not likely to end up doing useful work with. At this point if we&#x27;re talking learning skills specifically for work purposes, some of the softer skills may offer better rewards at my career stage.</p><h3>Dabbled in further education</h3><p>I came to web development via a rather circuitous route. I had to move schools in year 11 (15-16 in the UK education system), which was not conducive to doing well in my GCSE&#x27;s because that&#x27;s the year in which the exams happen. There were differences between the curriculum taught in the two schools that meant in practice I had to drop several subjects, while in others I missed out on specific coursework and lessons, as a result of which I got worse grades than perhaps I would have otherwise. Technically I did meet the standard required to study at A-level and I did start out on those, but I&#x27;d had a lot of trouble adapting to the new school and that came to a head, leading to me being asked to leave them and do something else.</p><p>As a result I never had the benefit of a university education, instead winding up spending over a decade working for a life insurer in a dull back-office role before web development caught my interest, and after several years on a correspondence course I finally left to take up my first web development role. I&#x27;ve now had a successful career in web development for nearly a decade and a half, but that didn&#x27;t mean I didn&#x27;t feel the absence of a university education. There&#x27;s definitely things that with the benefit of hindsight I&#x27;d like to study more at that sort of level, not necessarily for professional reasons.</p><p>At the same time, I&#x27;ve also taken to using ChatGPT for exploring ideas. There are legitimate questions about its accuracy and validity, but it&#x27;s interactive in a way a more static resource like Wikipedia isn&#x27;t - you can say &quot;Is X an example of Y?&quot; if you&#x27;re not sure and get a reasonably accurate response. Off the back of one particular conversation about the International Baccalaureate I wound up signing up for a Theory of Knowledge fully remote course offered by Oxford University&#x27;s Lifelong Learning programme. This was genuinely one of the most worthwhile things I&#x27;ve ever done - it taught me a <em>huge</em> amount, both about epistemology, and about what I&#x27;m interested in. Off the back of that I&#x27;m going to be doing more of these part-time remote courses.</p><p>In particular, a lot of this reflection has led me to realise I lost out a lot in terms of humanities subjects in education. History was one of the subjects I had to give up at school, and English Literature was one that took a particular hit from the move (if you read different books to your classmates you&#x27;re going to struggle to get good marks for the coursework when you have to study it at the last minute). I was always good at STEM subjects and foreign languages, but the humanities are more slow-burning knowledge that leads less obviously to a stable career in the early stages, but can often start to help more mid-career, as well as being enjoyable in their own right.</p><h3>Been healthier</h3><p>A few years ago I had a health issue that required I make changes to my diet in particular. Since adopting the whole &quot;30 plants a week&quot; idea I&#x27;ve felt a lot better, physically speaking. I&#x27;ve also made a point of getting out in the fresh air and sunshine more often, which has been beneficial for my general health too.</p><p>Also, late in 2024 I tore my rotator cuff and was prescribed some simple physiotherapy to help fix it. This has been very helpful too - the injury is now largely resolved and the improvement to my general fitness is beneficial too.</p><h2>What I want to do next year</h2><h3>Own my own content</h3><p>Yes, yes, yes. We all know intellectually, and have done for years, that we should really own our own content, and using someone else&#x27;s platform puts you under their restrictions. The trouble is, that always felt very abstract, and hard to actually live in practice. Historically there wasn&#x27;t an easy way to both own your content, and connect to non-technical friends or family, and for all their flaws, the social media and blogging platforms hadn&#x27;t become objectionable enough to make it worthwhile.</p><p>Now, things have changed. As Cory Doctorow has mentioned, the &quot;enshittification&quot; of big social media platforms is proceeding apace and they&#x27;re becoming progressively worse all the time. Twitter, though, took a <em>very</em> sharp turn towards getting bad, very quickly. In July 2023, after trying everything I could to improve my experience, including installing a browser extension that blocked &quot;verified&quot; users, I finally gave up, requested my archived data, and closed my account after over fifteen years on the platform. I switched my microblogging activity over to Mastodon, though nowadays I&#x27;m finding myself using Bluesky a lot more.</p><p>The trouble is, that archived data really isn&#x27;t of much use outside the context of that social network. I can potentially make it into a searchable archive, but it doesn&#x27;t easily carry over to a new site - I can&#x27;t import it into Bluesky to retain my old posts in context. And if I completely dumped Facebook, say, the same issue occurs - your data&#x27;s only actually that useful in the context of a specific social network. In the case of Twitter the cost of staying became bad enough to override the disruption of leaving, but Facebook isn&#x27;t quite that objectionable yet, and there&#x27;s little prospect of it becoming open enough that people could leave and maintain their connections on the site.</p><p>So I&#x27;m keen to ensure in future any content I write is hosted on a platform I either control myself (eg a blog), or can at least theoretically migrate elsewhere (eg Mastodon or to some extent Bluesky if I decided it was wroth using a Personal Data Server). I&#x27;m also keen on the principles behind the <a href="https://indieweb.org/">Indieweb</a>. Which leads to...</p><h3>New blogging platform</h3><p>At some point in the near future, I want to ditch Gatsby.js for this site. I&#x27;ve gone through the following platforms in the nearly 16 years I&#x27;ve been using this domain name:</p><ul><li>Flat HTML site</li><li>Wordpress</li><li>Octopress</li><li>My own bespoke static site generator, built as a Grunt plugin using Handlebars</li><li>Gatsby.js</li></ul><p>Interestingly, I always got the best search engine results on the bespoke static site generator. I don&#x27;t want to go back to that, but I think I need something simpler than Gatsby.js, which has always felt quite cumbersome. Using GraphQL to query for your post data on a personal blog feels cumbersome and overly complex. I liked using React.js and Typescript, so other platforms that use that are an option. I used Next.js for High Performance Laravel, and it worked, but querying for blog posts is still a bit cumbersome with that, particularly if your setup stores them as Markdown rather than in a database. Also, Next.js can still be frustrating to work with if you&#x27;re not hosting it on Vercel.</p><p>I would also like to eventually have a &quot;Notes&quot; section on my site, which would essentially be an ActivityPub-powered microblog with its own feed. That way I could use that to engage with commenters on Mastodon or other ActivityPub-powered platforms without going through a third party. It&#x27;s not core functionality, though, so it could be added later, with the main blog functionality still a static site generator.</p><p>I&#x27;m therefore thinking Astro may be the way to go:</p><ul><li>It&#x27;s a relatively simple hybrid platform that supports React or Preact in islands, if you need it, but you don&#x27;t need to use them to get things done.</li><li>It supports using Typescript if you need it</li><li>Astro DB allows use of a relational database when needed (ideal for that &quot;Notes&quot; functionality, even if the core doesn&#x27;t need it.</li></ul><p>This won&#x27;t be the first time I&#x27;ve used it, so there&#x27;s not a huge learning curve involved.</p><h3>Blog more, but about more different things</h3><p>I want to write more, but not necessarily about web development. In recent years I&#x27;ve got more politically engaged and more interested in philosophy, partly off the back of that Theory of Knowledge course mentioned above, but I want to keep that entirely separate from posting about web development. I&#x27;m therefore planning an entirely separate blog about those matters. The bones of that is in place and I have the domain name, I just need to get around to finishing it off and choosing a first post to make.</p><p>That doesn&#x27;t mean I&#x27;m giving up on posting here, though. But I&#x27;m less interested nowadays in writing about specific tools or even design patterns than I was. I have some vague ideas about which way I see the industry going in the near future, which I may be interested in exploring in future posts.</p><h3>Read more, but different stuff</h3><p>I&#x27;ve long been someone who reads a lot, but not necessarily widely or deeply. Reading on the train is generally quite good for getting X number of pages read, but not necessarily in-depth. I want to make a point of reading things I wouldn&#x27;t have thought to read before, and to do so more deliberately, to the point of being able to answer serious questions about it. My own reading history is largely SF, with some technical books, pop-science and occasional forays into fantasy or non-genre. I&#x27;m planning to actively read more non-genre fiction that I wouldn&#x27;t have considered previously.</p><p>And I <em>really</em> want to reread <em>Stand on Zanzibar</em> by John Brunner again. The point of SF isn&#x27;t to predict the future, but that book in particular predicted the outline of the future exceptionally well. Plenty of the details are wrong (unsurprising given it was written over 50 years ago), but it&#x27;s truly staggering how much Brunner predicted in general form if not in specific details. The &quot;information overload&quot; aspect of a world spinning out of control feels scarily prescient, even though it&#x27;s seen primarily through the lens of television, rather than the Internet which actually caused a similar effect. And we can easily imagine many aspects of it could be quite easily tweaked to mesh better with today&#x27;s world.</p><h3>Other interests</h3><p>Recently I started getting back into playing the guitar. I still had it lying around so it&#x27;s a cheap hobby to pick up (unless I start buying effects pedals again...), and with no plans to actively pursue anything beyond being able to play something on it again it&#x27;s lower risk.</p><p>I also began drawing a bit. It randomly occurred to me that I hadn&#x27;t drawn anything since leaving school, and while I never had any particular artistic inclinations, it was something I generally enjoyed when I did it. It also struck me that I needed at least one hobby that didn&#x27;t involve a screen, and if I was to draw landscapes it might get me outside, in nature a bit more. I&#x27;d also like to do more creative writing.</p><h2>Final thoughts</h2><p>So, yes, this year has involved a lot of thoughts about what I&#x27;d like to do outside work, in my own time. Much of that has been unrelated to work, and quite frankly it&#x27;s unhealthy how many people in our industry spend a lot of their spare time on industry-related projects. I&#x27;d definitely like to make more time for unrelated things in future.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Using Dolt with Lando]]></title>
        <id>https://matthewdaly.co.uk/blog/2024/07/28/using-dolt-with-lando/</id>
        <link href="https://matthewdaly.co.uk/blog/2024/07/28/using-dolt-with-lando/"/>
        <updated>2024-07-28T17:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>For some years now, I&#x27;ve been using <a href="https://lando.dev/">Lando</a> as my main development environment at work. It&#x27;s a convenient and flexible way to work with most stacks I might need to use, as it&#x27;s Docker-based it&#x27;s more lightweight than things like Vagrant which depend on virtual machines, and the presets for Laravel, Drupal and WordPress cover the most common use cases I typically have.</p><p>One particular issue I often come across on one project in particular is the need to repeatedly run an importer to verify that it works as expected, then roll the changes back if the end result isn&#x27;t what I expect. This importer is very hefty and takes a long time to run, and the database itself is very large and importing it takes a good while. I&#x27;d love a way to revert the changes when testing the importer so I can get it running again without having to reimport it.</p><p><a href="https://docs.dolthub.com/">Dolt</a> offers a possible solution to this problem. It basically combines a MySQL-compatible database with a Git-inspired versioning system that allows you to commit and roll back changes to your database.</p><p>Conveniently, Dolt is available as several Docker images, including <code>dolthub/dolt-sql-server</code>, which provides only the MySQL-compatible database server itself. Lando allows creating custom services using Docker images, so in principle we can just define that image as a service, specify a command and the right ports, add appropriate tooling, and we should be able to use Dolt largely as we would with MySQL, as in this example:</p><pre><code class="language-yml">name: myapp
recipe: laravel
config:
  webroot: public
  php: &#x27;8.1&#x27;
services:
  database:
    api: 3
    type: lando
    services:
      image: dolthub/dolt-sql-server:latest
      ports:
        - 3306:3306
      command: tini -- docker-entrypoint.sh
tooling:
  mysql:
    service: appserver
    cmd: mysql -u root -h database
</code></pre><p>Unfortunately, since Dolt isn&#x27;t an officially supported database service for Lando, it doesn&#x27;t set up the database for you the way it would with MySQL. You therefore need to first of all connect to the database by running <code>lando mysql</code>, then running the following commands:</p><pre><code class="language-sql">CREATE DATABASE laravel;
CREATE USER &#x27;laravel&#x27;@&#x27;%&#x27; IDENTIFIED BY &#x27;laravel&#x27;;
GRANT ALL PRIVILEGES ON laravel.* TO &#x27;laravel&#x27;@&#x27;%&#x27;;
FLUSH PRIVILEGES:
</code></pre><p>Once that&#x27;s done, we can then interact with our database largely as normal. In this example of a Laravel app, I can run the migrations as usual with <code>lando artisan migrate</code>. Then, we can examine the database state with a simple <code>SELECT</code> command against the <code>dolt_status</code> virtual table:</p><pre><code class="language-sql">&gt; SELECT * FROM dolt_status;
+------------------------+--------+-----------+
| table_name             | staged | status    |
+------------------------+--------+-----------+
| chirps                 |      0 | new table |
| failed_jobs            |      0 | new table |
| migrations             |      0 | new table |
| password_resets        |      0 | new table |
| personal_access_tokens |      0 | new table |
| users                  |      0 | new table |
+------------------------+--------+-----------+
6 rows in set (0.005 sec)
</code></pre><p>We can add the changes we want to commit:</p><pre><code class="language-sql">call dolt_add(&#x27;chirps&#x27;, &#x27;failed_jobs&#x27;, &#x27;migrations&#x27;, &#x27;password_resets&#x27;, &#x27;personal_access_tokens&#x27;, &#x27;users&#x27;);
+--------+
| status |
+--------+
|      0 |
+--------+
1 row in set (0.016 sec)
</code></pre><p>And commit them:</p><pre><code class="language-sql">call dolt_commit(&#x27;-m&#x27;, &#x27;Created initial schema&#x27;);
+----------------------------------+
| hash                             |
+----------------------------------+
| qj0cikee1nlv0j5n9tgqfjgq53b9hp2d |
+----------------------------------+
1 row in set (0.018 sec)
</code></pre><p>Suppose we make a changes in the database we want to roll back. We can do so as follows:</p><pre><code class="language-sql">&gt; call dolt_reset(&#x27;--hard&#x27;);
+--------+
| status |
+--------+
|      0 |
+--------+
1 row in set (0.015 sec)
</code></pre><p>Nice, eh? Before you start switching all your applications over to Dolt, there are two things to bear in mind:</p><ul><li>The performance isn&#x27;t quite as good as MySQL. This is more likely to be an issue in production, but apparently there are people using it there, so your mileage may vary.</li><li>While it aims to be MySQL compatible, it&#x27;s not impossible that there might be some compatibility issues between MySQL and Dolt. If you&#x27;re wanting to use MySQL in production and Dolt in development, you may want to be wary of this possibility.</li></ul><p>Nonetheless, it offers some really exciting possibilities for when working with databases locally.</p><h1>Summary</h1><p>This approach is quite limited because you need to set up the database manually, rather than having Lando set it up for you as specified out of the box. Given that the Docker SQL server container used above is intended to be as closely compatible as possible with the MySQL server already shipping with Lando, it sounds to me like in principle, adding support for Dolt via its own plugin would be straightforward and could be a relatively simple fork of the existing MySQL plugin. I&#x27;ve opened an issue in the repository to discuss this idea, but will have to see what happens. There&#x27;s some suggestion it might be possible to run those database commands as build steps, but I couldn&#x27;t get them working.</p><p>In local development, it may be worth your while considering whether the benefits of using Dolt over MySQL are worth it for your application. I&#x27;d personally be reluctant to consider using in production, but the benefits for local development sound pretty compelling.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[So... I learned Drupal]]></title>
        <id>https://matthewdaly.co.uk/blog/2024/05/27/so-i-learned-drupal/</id>
        <link href="https://matthewdaly.co.uk/blog/2024/05/27/so-i-learned-drupal/"/>
        <updated>2024-05-27T13:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>Late last year, at work they were looking for people to train up and get certified on working with Drupal so we could bid for jobs working with it. I can&#x27;t say I&#x27;m a big fan of certification in general (before getting my first job, I got CIW certification, but no-one I&#x27;ve interviewed with has ever even heard of it), but I know in general that many larger organisations of the sort that use Drupal tend to require certification as a matter of course, and I wanted to spread my wings a bit so I put my hand up. Then, at the end of January I passed the Acquia Site Builder - Drupal 10 certification.</p><p>So far, I&#x27;ve been quite impressed with Drupal. It&#x27;s a lot better than I had been led to believe, and the workflow is far superior to working with WordPress, even with Bedrock.</p><h2>Why are you impressed with Drupal?</h2><p>Drupal has been around since before I started my development career, but I hadn&#x27;t used it before, and had always assumed it was rather dated. To my surprise, Drupal actually satisfies most of <a href="/blog/2020/09/28/what-i-want-in-a-php-cms/">what I want in a PHP CMS</a> nowadays:</p><ul><li>By default, you use Composer to create new projects, and install and update modules, and you can use it to pull in additional dependencies</li><li>You can in theory fork <code>drupal/recommended-project</code> and use it as a basis for your project</li><li>It has a proper, documented object-oriented API that isn&#x27;t a million miles away from what you&#x27;d see in a modern framework. It also has a decent coding standard, and uses PHPStan (not my first choice as I&#x27;d prefer Psalm, but I can live with it)</li><li>While it doesn&#x27;t <em>completely</em> exclude the ability to edit presentation, it does seem to limit it to a modest degree that I can live with in most themes I&#x27;ve tried.</li><li>It uses Twig, a proper templating engine, for front end templates.</li><li>It&#x27;s possible to create custom content types and taxonomies easily as and when you need them (I&#x27;d prefer they were defined exclusively in code so there was no risk of a production site getting out of sync with a dev site, but there are ways to define them in code).</li><li>Drush allows most admin tasks to be done from the command line.</li><li>It can be used as a headless CMS.</li></ul><p>Also, it&#x27;s noticeable that it&#x27;s flexible enough that a lot of functionality which in other CMS solutions would require a plugin (cough... WordPress) or bespoke development can be done with just the core CMS. This eliminates the &quot;wood for the trees&quot; issue I&#x27;ve had with WordPress whereby you can find many plugins that do sort of what you want, but all of them seem to cater to a specific use case that&#x27;s not quite what you want. For instance, if I needed to create event listing functioality, all I would need to do is to create a new content type for the events with the required fields (possibly with another content type for the locations and a relation between them).</p><p>I&#x27;d always heard that Drupal was particularly hard to use, but after having used it for a bit, I really don&#x27;t agree with that. I came to it after having used multiple other CMS solutions and if you&#x27;ve already been exposed to the underlying concepts like taxonomies and different content types, it&#x27;s really not hard to understand. It has a powerful permissions system that allows you to grant and remove permissions in a very granular way, and the only way I could see clients struggling to understand it would be if they were given permissions that they didn&#x27;t need - a good developer shouldn&#x27;t be doing this.</p><p>I&#x27;m sure that prior versions of Drupal would have been much worse on these points, but I so far haven&#x27;t used a version below 10 so I can&#x27;t really comment on it. I&#x27;m impressed that unlike with Wordpress, they haven&#x27;t been afraid to make breaking changes for the sake of the long-term health of the project and haven&#x27;t left in in a state where it&#x27;s a tired backwater of bad practices that&#x27;s able to keep going solely due to the popularity of the platform.</p><p>I maintain a large legacy Zend 1 application at work, and a rewrite of that has been on the cards for a while. Drupal is the first off the shelf CMS where I haven&#x27;t been able to dismiss using it as the basis of a rewrite out of hand. I honestly couldn&#x27;t conclusively say at the moment how viable it would be to rebuild it from scratch in Drupal, since it would depend on a <em>lot</em> of bespoke module development that I wouldn&#x27;t yet feel confident about quoting for, but the mere fact I haven&#x27;t been able to dismiss it is a testament to its flexibility and power. Working with Drupal so far hasn&#x27;t felt like I&#x27;m stuck in a ghetto of bad practices and dated code like it does with WordPress.</p><h2>Summary</h2><p>I don&#x27;t want this to sound like a sponsored post, and so far my experience with it is quite limited, but so far I&#x27;ve been pleasantly surprised by how good Drupal is these days. It&#x27;s a far more modern PHP CMS than WordPress, and the developer experience is a lot better. While I haven&#x27;t really got too far into it and have yet to delve into bespoke theme and module development, I&#x27;m looking forward to doing so in the future.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Retiring Laravel Azure Storage]]></title>
        <id>https://matthewdaly.co.uk/blog/2024/03/24/retiring-laravel-azure-storage/</id>
        <link href="https://matthewdaly.co.uk/blog/2024/03/24/retiring-laravel-azure-storage/"/>
        <updated>2024-03-24T16:30:00.000Z</updated>
        <content type="html"><![CDATA[<p>Today I abandoned my most popular open source package, <a href="https://github.com/matthewbdaly/laravel-azure-storage">Laravel Azure Storage</a>. According to Packagist, it&#x27;s been installed nearly two million times down the years, and it has 221 stars and 45 forks on GitHub. And today it comes to an end.</p><p>It&#x27;s been inevitable for a while that this had to happen, and here&#x27;s why.</p><h2>Why am I abandoning it?</h2><p>The package doesn&#x27;t actually do very much itself. Laravel&#x27;s Filesystem storage abstraction is built on top of the Flysystem package, and uses that to provide the underlying functionality to integrate with multiple storage backends. Writing a custom driver for this is therefore pretty easy as long as there&#x27;s an existing Flysystem driver for the storage method in question.</p><p>In March 2023 Microsoft announced that they were retiring the PHP SDK for working with Azure Storage, in favour of working directly with the REST API. Off the back of this, the creator of Flysystem announced he could no longer maintain the Azure driver as a result of this, and that it too would be retired at the same time. As my package was directly dependent on the Flysystem package, which was itself also dependent on the PHP SDK, if it was going to have any future, then barring replacement packages for both of those, it was going to have to be completely rebuilt to include the functionality of both third party packages.</p><p>If I had a genuine need for the package, it might have been worth doing so, however that wasn&#x27;t the case. I&#x27;ve actually never used this package myself except for testing. I originally worked with Azure Blob Storage in a Laravel application I built in 2015 at a previous employer, which was the first time I&#x27;d used Laravel, and used Graham Campbell&#x27;s Flysystem package. It was only later that I realised I could have had a better experience by rolling a custom driver, and wound up producing the package. In the intervening period a few people contributed features and bug fixes, and I tightened up the code base a bit with type checking, more comprehensive tests, and better documentation, but the core of it didn&#x27;t change much. It remained something of an annoyance to some extent - something I&#x27;d created for a specific project that I never even used, but wound up maintaining anyway.</p><p>Ironically, I did actually have a client at work wanting to use Azure Blob Storage for a use case only the other day. I&#x27;d built out a command line script that generated some text files and dropped them into a storage medium using Flysystem, and the client asked if they could use Azure storage for it. The Flysystem driver would have been useful for that, but as it&#x27;s being retired I don&#x27;t want to use it, and will instead need to move it away from Flysystem and work directly with the REST API to store the files. As it&#x27;s not a Laravel project, I wouldn&#x27;t find this project useful anyway, but the fact that I&#x27;ve only used Azure storage twice in my career, and those nearly two decades apart, emphasises that it&#x27;s really not worth my time to continue working on this package if I need to do a load more development on it to keep it viable.</p><h2>I&#x27;m using this package on a project. Where do I go from here?</h2><p>As at right now, there does seem to be an effort to create <a href="https://github.com/Azure-OSS/azure-storage-php">an open source fork of the underlying Microsoft PHP SDK</a>. This only covers the Microsoft SDK, not the Flysystem Azure driver, or this package, so it&#x27;s not a drop in replacement for this, however there is talk on the issues of that repository around creating a Flysystem driver and possibly forking this package to work with it.</p><p>You could potentially fork this package and the Flysystem Azure driver, and adjust them both to use that package, but that would be a fair amount of work, and is probably only worth doing if you really have to continue using Azure Blob Storage and can&#x27;t switch to an alternative like Amazon S3 or Digital Ocean Spaces.</p><p>Saying goodbye to this package will be a relief. It&#x27;s been a bit of a time sink given the fact I&#x27;ve never used it, and given I have only had limited dealings with the Azure ecosystem since it was always a pain to maintain and test. It also provided some useful lessons on how to accept issues on GitHub - many of the feature requests and bug fixes were for things the package couldn&#x27;t do because it was just a layer on top of Flysystem, so I wound up producing some quite complex issue templates to weed out things I couldn&#x27;t do a thing about or that needed to be done in one of the dependencies.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Why I haven't posted much this year]]></title>
        <id>https://matthewdaly.co.uk/blog/2023/08/26/why-i-havent-posted-much-this-year/</id>
        <link href="https://matthewdaly.co.uk/blog/2023/08/26/why-i-havent-posted-much-this-year/"/>
        <updated>2023-08-26T18:39:00.000Z</updated>
        <content type="html"><![CDATA[<p>If you regularly read this blog, you may have noticed that I haven&#x27;t posted much this year. There&#x27;s a reason for this - a lot of my spare time has been taken up working on a new personal project, which has just gone live.</p><p>One issue in particular that has been bugging me for a long time is misinformation about application performance, particularly when relating to Laravel. If you visit many PHP or web development-related communities, such as the PHP subreddit, it&#x27;s quite common for inexperienced developers to post questions along the lines of &quot;What is the fastest framework?&quot;. A lot of barely-more experienced commenters will then leap in with ill-informed comments about which frameworks are supposedly slower or faster, based on benchmarks. In actual fact, the idea of a framework being faster or slower really doesn&#x27;t make sense - a framework isn&#x27;t an application, the way something like WordPress is, and to compare the same &quot;Hello world&quot; application implemented in different frameworks gives a really poor idea of what the real reasons for poor application performance are. The actual causes of a slow application are nearly always something that isn&#x27;t framework specific, and rewriting a working application into a supposedly &quot;faster&quot; framework won&#x27;t generally resolve the issue.</p><p>And that, in a nutshell, is why I&#x27;ve created <a href="https://highperformancelaravel.com/">High Performance Laravel</a>. It&#x27;s intended to be a repository of articles that will explain the following:</p><ul><li>Common performance myths relating to Laravel and PHP</li><li>How to measure performance</li><li>The actual bottlenecks likely to occur in your application</li><li>How to optimise your application</li></ul><p>A lot of this isn&#x27;t <em>necessarily</em> specific either to Laravel or PHP, but it&#x27;s written from the perspective of a Laravel developer. As such, if you work with a different framework or language, you still might find plenty of useful content there.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Why (nearly) every PHP class you write should be abstract or final]]></title>
        <id>https://matthewdaly.co.uk/blog/2023/08/13/why-nearly-every-php-class-you-write-should-be-abstract-or-final/</id>
        <link href="https://matthewdaly.co.uk/blog/2023/08/13/why-nearly-every-php-class-you-write-should-be-abstract-or-final/"/>
        <updated>2023-08-13T15:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>If your introduction to object-oriented PHP was anything like mine, inheritance was probably touted as one of the biggest advantages. It allowed you to easily extend existing code with minimal effort, and bend existing third-party packages to suit your needs. However, after nearly twelve years in the industry, I&#x27;ve come to the conclusion that in fact, inheritance is only a <em>comparatively</em> fringe benefit of object-oriented PHP. Nowadays, I declare most classes I write as final. Where I don&#x27;t (probably less than 10% of all the classes I write), I nearly always declare them as abstract. And I&#x27;m finding it increasingly hard to <em>ever</em> justify leaving any class as neither abstract nor final.</p><p>I&#x27;ve come to appreciate that explicitly declaring every class you can as either abstract or final is a powerful method for enforcing certain aspects of good software design, for the following reasons:</p><h2>It signifies intent</h2><p>If you declare a class as final, you are stating to any other developers that it&#x27;s designed to do one thing, and one thing only, and so it&#x27;s not intended to be extended to do something else. This is consistent with the Single Responsibility principle in SOLID.</p><p>Similarly, if you declare a class as abstract, you are stating to any other developers working with the code that this class has been designed specifically to be extended, and so they should feel free to do so as appropriate.</p><h2>It prevents other developers shooting themselves in the foot</h2><p>It&#x27;s relatively easy to design a class to do one thing and one thing only. It&#x27;s a <em>lot</em> harder to design a class to do multiple things, or to do things in a generic fashion, and it&#x27;s outright dangerous to just assume that your use case for something isn&#x27;t different enough that you&#x27;re going to have problems if you extend a class that&#x27;s not designed to be extended.</p><p>It also means you&#x27;re dependent on the private API of the code you&#x27;re extending remaining compatible with the rest of the code. If you extend a third-party class, and make use of private methods declared on that class, then potentially <em>any</em> changes made to that class can break your class, not just documented changes to the public API.</p><p>In addition, if you develop or maintain a library, framework or other application that can be extended by other developers such as a content management system, declaring all your classes as abstract or final can potentially save you a lot of grief. If you receive a bug report on said project which touches on a class that is neither abstract nor final, it&#x27;s entirely possible that said class has been inappropriately extended, and that the issue is actually caused by something in the reporter&#x27;s class which extends yours.</p><h2>It prevents the &quot;inheritance chain of doom&quot;</h2><p>We&#x27;ve all seen it, a long chain of classes where each one extends a preceding one slightly, with the ones lowest in the chain having been amended just to fix some minor inconvenience. Often the change is itself something comparatively trivial, such as a getter or setter, but often it&#x27;s something that would be better solved through other means. Which leads us to...</p><h2>It encourages the use of composition over inheritance</h2><p>Consider the use case of an existing class within a framework which fetches a user based on an ID, and can be swapped with an alternative implementation of the same class. This class means that every time the page loads while a user is logged in, it carries out the same query to get the user. This query could potentially be cached to improve application performance.</p><p>You <em>could</em> extend that class and add caching, but it&#x27;s not a very good way to do it:</p><ul><li>It&#x27;s dependent on the private API of that class, so in theory any undocumented changes to that API could break the class.</li><li>It&#x27;s bound to that class only, and can&#x27;t be reused for alternative implementations.</li><li>Adding caching to the wrapped class violates the single responsibility principle.</li></ul><p>So instead, you could use composition, by creating a decorator class, which implements the same interface as the original class, but wraps the original class in a caching layer. This resolves both issues:</p><ul><li>The decorator class is completely independent of the original class, so it can be reused for alternative implementations without any changes.</li><li>The decorator class relies <em>only</em> on the public API of the original class, so changes to the private API of the original class won&#x27;t affect the decorator class in the slightest.</li><li>If the public API of the interface changes, it will very obviously break the decorator class, making it easy to identify and fix.</li></ul><p>This isn&#x27;t a purely theoretical example - <a href="/blog/2020/03/11/caching-the-laravel-user-provider-with-a-decorator/">I&#x27;ve used exactly this approach myself in Laravel</a>. And it&#x27;s a far more elegant, flexible and reusable approach than extending the class.</p><h2>A lot of classes don&#x27;t ever need to be extended</h2><p>For many classes in a typical project, particularly those built with an off-the-shelf MVC framework, you&#x27;ll never need to extend them. Migrations are a good example of this - each migration does one thing and one thing only, and if you extend a migration you&#x27;re doing something <em>seriously</em> dodgy. And there&#x27;s very little need to ever extend controllers - if you&#x27;re building a REST API, it might be useful to place common functionality in one resource controller for reuse, but it just doesn&#x27;t make sense to extend one concrete class with another. Instead you&#x27;re better off creating an abstract <code>ResourceController</code> class, and having your concrete resource classes extend that.</p><h2>Isn&#x27;t OOP all about inheritance? Surely I&#x27;m giving up some of the benefits of OOP?</h2><p>No, and this is a very bad misconception it took me <em>years</em> to unlearn.</p><p>The first web application I built solo in PHP, back in 2012, was using CodeIgniter 2, and at that point in my career I was still writing what was effectively procedural code, but stuffing it inside objects. That wasn&#x27;t OOP, and it wasn&#x27;t for around another five years before I realised that OOP wasn&#x27;t about just <em>putting code in objects</em>, but about the <em>interactions between objects</em>. Nowadays, I rarely use primitive types such as arrays and scalar variables, because objects that can be more specifically typed are more type-safe (making tools like Psalm happier), and you can add functionality to them to make interactions easier.</p><p>The more granular you can make a class, the more likely it is that it can be easily reused (again, this is part of the single responsibility principle). Understanding this was a pivotal moment in my career. If each class is a relatively small thing that does one thing only, and depends on an interface, code reuse <em>really</em> doesn&#x27;t require inheritance all that often. It&#x27;s actually quite rare these days that I have any need whatsoever to extend a class, because most of my classes can be reused as-is, without the need for any changes, or if they do need extending, I can do so via composition.</p><h2>But if my classes are declared final, I can&#x27;t mock them in tests?</h2><p>No, you can&#x27;t, unless you&#x27;re going to <a href="https://github.com/dg/bypass-finals">jump through hoops to do so</a>. However, a sufficiently well-designed class shouldn&#x27;t need you to do that anyway. For an awful lot of use cases, mocking isn&#x27;t the best option anyway during testing:</p><ul><li>For value objects, you are probably best off working directly with the value objects themselves, rather than creating a mock of them. Creating an instance of a value object is often easier than creating a mock anyway. For instance, if I had the need to unit test a Laravel controller, I&#x27;d create a request object rather than mocking it.</li><li>Likewise, many other utility classes are better off just being used directly. Something like a Laravel collection class is a good example - you may as well just use that as-is.</li><li>For any class which implements an interface, you can just mock that interface. Any class that you might conceivably want to extend in the future should probably implement an interface anyway - the <em>only</em> ones where it doesn&#x27;t make sense are generally single, irreplaceable classes like models or controllers. Even if it&#x27;s a service that&#x27;s irreplaceable (such as a third party service whose continued existence is essential to the project), it should <em>probably</em> implement an interface - you don&#x27;t know what alternatives might become available in future, it may be useful to be able to decorate the service to add caching or logging, and it might also be useful to create a &quot;dummy&quot; version of said service for testing purposes.</li></ul><h2>But if I can&#x27;t extend classes, I can&#x27;t reuse X part of the functionality of that class</h2><p>This is a code smell, suggesting that said class is probably too large, and does too much. You should consider extracting that functionality into a new class, which is then a dependency of that class.</p><p>For instance, say you have a library that sends emails to users, and that has drivers for, say, SMTP, and the Mailgun API. Suppose you want to create a new driver for Mailchimp transactional emails which also works over HTTP, so you want to reuse some of the functionality from the Mailgun driver. Extending the Mailgun driver to reuse the HTTP request functionality that makes the requests <em>might</em> allow you to achieve that, but it causes several additional problems:</p><ul><li>The Mailgun driver is now a dependency of the Mailchimp driver, so any change to the Mailgun driver can potentially break the Mailchimp driver.</li><li>If Mailgun driver is removed, the functionality will need to be moved over to the Mailchimp driver.</li></ul><div>Yes, this is a somewhat contrived (and probably rather excessive) example, but it demonstrates the point.</div><p>Under these circumstances, the best solution would likely be to create a <code>Transport</code> interface, extract the HTTP functionality into a new <code>HttpTransport</code> class that implements the <code>Transport</code> interface, and then use the class in both the Mailgun and Mailchimp drivers. This would also allow the transport method to be mocked, so it could be tested more easily without sending actual HTTP requests. Another option might be to extract the HTTP functionality to an <code>HttpDriver</code> abstract class, which is extended by both the Mailgun and Mailchimp API drivers.</p><h2>Surely making the mistakes stopped by declaring classes final is just a training issue?</h2><p>No, it&#x27;s more complex than that.</p><p>If I&#x27;m not your line manager or a member of the same development team, I&#x27;m not responsible for your training and personal development as a coder, and likely can have little influence on that. But even if our only interaction is in regards to, say, a library I wrote and put on Github that you&#x27;re using, I have a vested interest in making sure you use it in a way I&#x27;d consider safe. If you go and extend it and report a bug that turns out to be in a class that extends mine, that&#x27;s going to be a waste of my time to deal with. And I can fill my documentation with notes about &quot;This class isn&#x27;t meant to be extended. Don&#x27;t extend it&quot;, but I&#x27;ve still got no guarantees. But if I add one single final keyword I have a cast-iron guarantee that it&#x27;s impossible to extend, and I don&#x27;t need to think about it any more.</p><p>Preventing people from taking the quick and easy way of extending a class that&#x27;s not intended to be extended also stops quick-and-dirty solutions, and enables teachable moments. If someone on my team can&#x27;t extend a class I wrote, they&#x27;ll go looking for other ways around it, and will likely discover a more appropriate alternative, such as the decorator pattern. And if someone does the same with an open source library I wrote, either they&#x27;ll do the same through research, or if they come to me, I merely need to point them at a more appropriate alternative approach.</p><h2>Isn&#x27;t this a bit of a fringe view?</h2><p>Not in the slightest. Here are some other posts by experienced PHP developers that cover the same subject:</p><ul><li><a href="https://ocramius.github.io/blog/when-to-declare-classes-final/">When to declare classes final</a></li><li><a href="https://verraes.net/2014/05/final-classes-in-php/">Final classes in PHP</a></li><li><a href="https://matthiasnoback.nl/2018/09/final-classes-by-default-why/">Final classes by default, why?</a></li></ul><h2>Okay, I&#x27;m sold. How can I enforce this on my projects?</h2><p>There are a number of ways you can do so:</p><ul><li>PHP CS Fixer has a <a href="https://cs.symfony.com/doc/rules/class_notation/final_class.html">rule</a> to enforce that every class <strong>must</strong> be abstract or final, except for Doctrine classes. If you&#x27;re not <em>quite</em> ready to adopt that, you may want to consider enforcing that <a href="https://cs.symfony.com/doc/rules/class_notation/final_internal_class.html">all internal classes should be final</a>, and/or that <a href="https://cs.symfony.com/doc/rules/class_notation/final_public_method_for_abstract_class.html">all public methods of abstract classes must be final</a>.</li><li>The Slevomat coding standard for PHP Codesniffer has a <a href="https://github.com/slevomat/coding-standard/blob/master/doc/classes.md#slevomatcodingstandardclassesrequireabstractorfinal-">sniff</a> that enforces that every class must be abstract or final.</li><li>The <a href="https://pestphp.com/docs/arch-testing">Pest Architecture plugin</a> has rules that allow you to enforce use of the abstract or final modifier on classes based on rules you define.</li></ul><h2>Summary</h2><p>Explicitly declaring all classes I can as either <code>abstract</code> or <code>final</code> has greatly improved the quality of my code. It&#x27;s forced me to up my game in terms of application design, by stopping me from taking all kinds of dodgy shortcuts, and to find better solutions. It&#x27;s also encouraged me to shrink my classes down to be more granular, enabling code reuse <em>without</em> extension. I highly recommend giving it a try if you aren&#x27;t already, and seeing what kind of difference it makes to the code you write in the long term.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Two techniques for handling recursive relationships in MySQL]]></title>
        <id>https://matthewdaly.co.uk/blog/2022/12/18/two-techniques-for-handling-recursive-relationships-in-mysql/</id>
        <link href="https://matthewdaly.co.uk/blog/2022/12/18/two-techniques-for-handling-recursive-relationships-in-mysql/"/>
        <updated>2022-12-18T14:15:00.000Z</updated>
        <content type="html"><![CDATA[<p>When modelling users in a hierarchical organization, it&#x27;s common to need to retrieve the line manager or subordinates of a given user. In MySQL, two of the techniques that can be used to handle these recursive relationships are the <code>WITH RECURSIVE</code> common table expression and using closure tables.</p><h3>Using CTEs with <code>WITH RECURSIVE</code></h3><p>A common table expression (CTE) is a temporary result set that is defined within the execution scope of a single SQL statement. In MySQL, you can use the <code>WITH RECURSIVE</code> clause to define a CTE that can be used to retrieve all of the users above or below a given user in the hierarchy.</p><p>Say we have a <code>users</code> table that looks like this:</p><pre><code class="language-sql">CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  manager_id INTEGER REFERENCES users(id)
);
</code></pre><p>To create a CTE that gets the users above a given user, you can use the following query:</p><pre><code class="language-sql">WITH RECURSIVE managers AS (
  SELECT id, name, manager_id
  FROM users
  WHERE id = :user_id
UNION ALL
  SELECT u.id, u.name, u.manager_id
  FROM users u
  INNER JOIN managers m ON m.manager_id = u.id
)
SELECT * FROM managers;
</code></pre><p>This query uses the <code>WITH RECURSIVE</code> clause to define a CTE called <code>managers</code> that first selects the user with the given <code>user_id</code> and then uses the <code>UNION ALL</code> operator to combine that user with all of the users above them in the hierarchy. The <code>INNER JOIN</code> clause is used to link the <code>managers</code> CTE to the users table, so that the <code>managers</code> CTE can keep growing until it includes all of the users above the given user in the hierarchy.</p><p>To get the users below a given user, you can use a similar query, but with the <code>manager_id</code> and <code>id</code> fields swapped in the INNER JOIN clause:</p><pre><code class="language-sql">WITH RECURSIVE subordinates AS (
  SELECT id, name, manager_id
  FROM users
  WHERE id = :user_id
UNION ALL
  SELECT u.id, u.name, u.manager_id
  FROM users u
  INNER JOIN subordinates s ON s.id = u.manager_id
)
SELECT * FROM subordinates;
</code></pre><p>This query uses the same technique as the previous example, but it retrieves the users below the given user instead of above.</p><h3>Using closure tables</h3><p>Another technique for handling recursive relationships in MySQL is to use closure tables. A closure table is a special type of table that is used to represent hierarchical data in a relational database. It consists of two tables: one for the entities in the hierarchy (e.g. users) and one for the relationships between those entities.</p><p>To create a closure table for a hierarchy of users, you can use the following DDL statement:</p><pre><code class="language-sql">CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name VARCHAR(255) NOT NULL
);

CREATE TABLE hierarchy (
  ancestor INTEGER NOT NULL REFERENCES users(id),
  descendant INTEGER NOT NULL REFERENCES users(id),
  PRIMARY KEY (ancestor, descendant),
  CHECK (ancestor != descendant)
);
</code></pre><p>The users table is similar to the one in the previous example, but it only contains the <code>id</code> and <code>name</code> fields. The relationships between the users are defined in the <code>hierarchy</code> table.</p><p>To insert data into these tables, you would first need to insert rows into the users table for each user in the hierarchy, and then insert rows into the hierarchy table to define the relationships between those users. Here is an example of how this could be done:</p><pre><code class="language-sql">INSERT INTO users (id, name) VALUES
  (1, &#x27;Alice&#x27;),
  (2, &#x27;Bob&#x27;),
  (3, &#x27;Carol&#x27;),
  (4, &#x27;Dave&#x27;),
  (5, &#x27;Eve&#x27;);

INSERT INTO hierarchy (ancestor, descendant) VALUES
  (1, 1),
  (1, 2),
  (1, 3),
  (1, 4),
  (1, 5),
  (2, 2),
  (2, 3),
  (2, 4),
  (3, 3),
  (4, 4);
</code></pre><p>This inserts five users into the <code>users</code> table and then inserts rows into the <code>hierarchy</code> table to define the relationships between those users. The ancestor and descendant values are both set to the same id for each user, which indicates that each user is a descendant of themselves. The hierarchy table also defines the relationships between the users, with each user being a descendant of the user above them in the hierarchy.</p><p>To get all of the users above a given user using a closure table, you can use the following query:</p><pre><code class="language-sql">SELECT u.*
FROM users u
INNER JOIN hierarchy h ON h.descendant = :user_id
WHERE u.id = h.ancestor
</code></pre><p>This query uses an <code>INNER JOIN</code> to link the <code>users</code> table to the <code>hierarchy</code> table, and then filters the results to only include users that are ancestors of the user with the given <code>user_id</code>. This query will return a list of all of the users above the given user in the hierarchy.</p><p>To get the users below a given user, you can use a similar query, but with the ancestor and descendant fields swapped in the INNER JOIN clause:</p><pre><code class="language-sql">SELECT u.*
FROM users u
INNER JOIN hierarchy h ON h.ancestor = :user_id
WHERE u.id = h.descendant
</code></pre><p>This query will return a list of all of the users below the given user in the hierarchy.</p><p>One downside of the closure table approach is that when the hierarchical structure changes, the <code>hierarchy</code> table needs to be updated to reflect the changes. There are a number of approaches you can take to handle this, including:</p><ul><li>Creating MySQL triggers to update the <code>hierarchy</code> table automatically when a user is inserted, updated or deleted</li><li>Using events, such as Eloquent model events, to apply the changes in application code</li><li>Truncating and repopulating the <code>hierarchy</code> table from scratch</li></ul><p>The first approach is generally the most efficient, but has the downside that triggers aren&#x27;t generally exported from <code>mysqldump</code>, making it difficult to manage when importing the production database locally. The last approach often makes the most sense in cases where users are populated from some kind of regular import, in which case the hierarchy will only ever change as a result of that import.</p><h3>Which one should I use?</h3><p>Which of these approaches you should choose in a given situation is highly dependent on the specific needs of your application, since each has advantages and limitations.</p><p>Using a closure table results in a smaller, simpler, and generally more efficient query that is easy to express using an ORM or query builder, but requires that you take steps to update the separate closure table when the hierarchy changes. Using the <code>WITH RECURSIVE</code> CTE doesn&#x27;t require a separate table, eliminating the need to populate said table, but for some queries it may not be as efficient. In addition, it can be difficult to express with some ORMs and query builders, necessitating either additional third party packages or falling back to raw queries. If you&#x27;re stuck using an older version of MySQL, such as on a legacy application, and can&#x27;t upgrade, you might also not be able to use <code>WITH RECURSIVE</code> (though at this point you <em>really</em> shouldn&#x27;t be using a version that old).</p><p>At times I&#x27;ve found it necessary to combine both techniques. One application I maintain has a nightly import process for all the users and derives the permissions to view various pieces of content in part from the hierarchy - the only way to determine the hierarchy is by following the line managers back all the way to the managing director for each individual user, but permissions can be assigned to individual business units within the company and cascade down to child business units, and so to know what permissions a user has, we need to know where they sit in the hierarchy. This query would be too cumbersome to perform on the fly for each user, so we use the <code>WITH RECURSIVE</code> CTE to detetermine a user&#x27;s place within the hierarchy, and then populate a closure table from it, as a part of the nightly import.</p><h3>Conclusion</h3><p>In MySQL, there are a number of techniques that can be used to handle recursive relationships in hierarchical data, but two of the most performant and flexible are the <code>WITH RECURSIVE</code> CTE and using closure tables. Both techniques have their own benefits and drawbacks, and the best choice will depend on the specific requirements of your application.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[What I think ChatGPT means for developers]]></title>
        <id>https://matthewdaly.co.uk/blog/2022/12/11/what-i-think-chatgpt-means-for-developers/</id>
        <link href="https://matthewdaly.co.uk/blog/2022/12/11/what-i-think-chatgpt-means-for-developers/"/>
        <updated>2022-12-11T19:20:00.000Z</updated>
        <content type="html"><![CDATA[<p>I&#x27;m sure you&#x27;ve heard some of the buzz about <a href="https://chat.openai.com/">ChatGPT</a>. There&#x27;s been examples of it <a href="https://wptavern.com/chatgpt-creates-a-working-wordpress-plugin-on-the-first-try">creating a working Wordpress plugin on demand</a>, <a href="https://twitter.com/ZacYungblut/status/1598593759532355584?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1598593759532355584%7Ctwgr%5E7278d2255112f76225493be1370af0fa7a975285%7Ctwcon%5Es1_&amp;ref_url=https%3A%2F%2Fd-35506373891512421835.ampproject.net%2F2211250451000%2Fframe.html">recreating the Apple website</a>, acting as a Linux terminal, and writing astonishingly detailed code samples for various purposes on demand.</p><p>Naturally I decided to have a tinker with it as I was curious about it, and I&#x27;ve found it very useful for coding. Here are some samples of things I&#x27;ve asked it to do for me.</p><h3>An example of writing code with ChatGPT</h3><p>Given the popularity of React.js and my own experience using it, I figured that was something ChatGPT would probably handle OK and that I would be able to evaluate for myself. I therefore asked ChatGPT to create a React-based alert system for me. As I&#x27;ve implemented something similar myself, I was interested to see how well it would do against my own implementation which is in production:</p><blockquote><p>Please create a hook-based toast-style alert system in React.js using hooks</p></blockquote><p>It responded with:</p><blockquote><p>Sure, here is an example of a toast-style alert system in React.js using hooks:</p></blockquote><pre><code class="language-javascript">import React, { useState, useEffect } from &#x27;react&#x27;;

function useToast() {
  const [isShowing, setIsShowing] = useState(false);
  const [message, setMessage] = useState(&#x27;&#x27;);

  function showToast(msg) {
    setMessage(msg);
    setIsShowing(true);
  }

  function hideToast() {
    setIsShowing(false);
  }

  useEffect(() =&gt; {
    let timeoutId;
    if (isShowing) {
      timeoutId = setTimeout(() =&gt; setIsShowing(false), 3000);
    }

    return () =&gt; clearTimeout(timeoutId);
  }, [isShowing]);

  return {
    isShowing,
    message,
    showToast,
    hideToast
  };
}

function App() {
  const { isShowing, message, showToast, hideToast } = useToast();

  return (
    &lt;div&gt;
      {isShowing &amp;&amp; (
        &lt;div className=&quot;toast&quot;&gt;
          &lt;p&gt;{message}&lt;/p&gt;
          &lt;button onClick={hideToast}&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      )}
      &lt;button onClick={() =&gt; showToast(&#x27;This is a toast message!&#x27;)}&gt;
        Show Toast
      &lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre><blockquote><p>In this example, the <code>useToast</code> hook manages the state for the toast, including whether it is showing, the message to display, and methods for showing and hiding the toast. The <code>App</code> component uses the <code>useToast</code> hook to show and hide the toast when a button is clicked.</p></blockquote><blockquote><p>The <code>useToast</code> hook uses the <code>useState</code> hook to manage the state for the toast, and the <code>useEffect</code> hook to automatically hide the toast after a certain amount of time. This is just one example of how to implement a toast-style alert system in React.js using hooks, and you can modify it to suit your specific needs.</p></blockquote><p>Looks OK, but it only supports a single message at once, so I followed it up:</p><blockquote><p>Can we amend this to support showing multiple toasts at once?</p></blockquote><blockquote><p>Yes, it is possible to modify the example to support showing multiple toasts at once. Instead of using a single state value for the message and whether the toast is showing, you can use an array to store multiple toast messages and show them all at once. Here is an example of how you might do this:</p></blockquote><pre><code class="language-javascript">import React, { useState, useEffect } from &#x27;react&#x27;;

function useToast() {
  const [toasts, setToasts] = useState([]);

  function showToast(msg) {
    setToasts(prevToasts =&gt; [...prevToasts, msg]);
  }

  function hideToast(index) {
    setToasts(prevToasts =&gt; {
      prevToasts.splice(index, 1);
      return [...prevToasts];
    });
  }

  useEffect(() =&gt; {
    let timeoutIds = [];
    toasts.forEach((_, index) =&gt; {
      timeoutIds[index] = setTimeout(() =&gt; hideToast(index), 3000);
    });

    return () =&gt; timeoutIds.forEach(timeoutId =&gt; clearTimeout(timeoutId));
  }, [toasts]);

  return {
    toasts,
    showToast,
    hideToast
  };
}

function App() {
  const { toasts, showToast, hideToast } = useToast();

  return (
    &lt;div&gt;
      {toasts.map((toast, index) =&gt; (
        &lt;div className=&quot;toast&quot; key={index}&gt;
          &lt;p&gt;{toast}&lt;/p&gt;
          &lt;button onClick={() =&gt; hideToast(index)}&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      ))}
      &lt;button onClick={() =&gt; showToast(&#x27;This is a toast message!&#x27;)}&gt;
        Show Toast
      &lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre><blockquote><p>In this example, the <code>useToast</code> hook uses an array to store multiple toast messages, and the <code>App</code> component displays all of the toasts in the array. The <code>useEffect</code> hook is used to set a timeout for each toast to automatically hide it after a certain amount of time. You can modify this example further to suit your specific needs, such as setting different timeouts for each toast or adding additional methods for managing the toasts.</p></blockquote><p>Great,  although I noticed an unused <code>_</code> variable in <code>forEach</code> - not sure if perhaps this is based on something that used Lodash, perhaps.</p><p>Next, our toasts need to show different styles based on the type of alert, so I asked this:</p><blockquote><p>Can we amend this to allow the toasts to use different styles based on the type of alert?</p></blockquote><blockquote><p>Yes, it is possible to modify the example to allow the toasts to use different styles based on the type of alert. You can do this by storing the type of each toast along with the message in the state, and then using this type to determine the style for the toast. Here is an example of how you might do this:</p></blockquote><pre><code class="language-javascript">import React, { useState, useEffect } from &#x27;react&#x27;;

function useToast() {
  const [toasts, setToasts] = useState([]);

  function showToast(msg, type) {
    setToasts(prevToasts =&gt; [...prevToasts, { msg, type }]);
  }

  function hideToast(index) {
    setToasts(prevToasts =&gt; {
      prevToasts.splice(index, 1);
      return [...prevToasts];
    });
  }

  useEffect(() =&gt; {
    let timeoutIds = [];
    toasts.forEach((_, index) =&gt; {
      timeoutIds[index] = setTimeout(() =&gt; hideToast(index), 3000);
    });

    return () =&gt; timeoutIds.forEach(timeoutId =&gt; clearTimeout(timeoutId));
  }, [toasts]);

  return {
    toasts,
    showToast,
    hideToast
  };
}

function App() {
  const { toasts, showToast, hideToast } = useToast();

  return (
    &lt;div&gt;
      {toasts.map((toast, index) =&gt; (
        &lt;div
          className={`toast toast-${toast.type}`}
          key={index}
        &gt;
          &lt;p&gt;{toast.msg}&lt;/p&gt;
          &lt;button onClick={() =&gt; hideToast(index)}&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      ))}
      &lt;button onClick={() =&gt; showToast(&#x27;This is a success toast!&#x27;, &#x27;success&#x27;)}&gt;
        Show Success Toast
      &lt;/button&gt;
      &lt;button onClick={() =&gt; showToast(&#x27;This is an error toast!&#x27;, &#x27;error&#x27;)}&gt;
        Show Error Toast
      &lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre><blockquote><p>In this example, the <code>useToast</code> hook stores the message and type of each toast in the state, and the <code>App</code> component uses the type to determine the class name for the toast. This allows you to define different styles for each type of toast, such as a <code>toast-success</code> class for success toasts and a <code>toast-error</code> class for error toasts. You can modify this example further to suit your specific needs, such as defining additional types of toasts or changing the way that the styles are applied.</p></blockquote><p>Great, but a reducer may make more sense than regular state for this use case. Let&#x27;s ask it to update the code:</p><blockquote><p>Can we amend this code to use a reducer instead of state?</p></blockquote><blockquote><p>Yes, it is possible to modify the example to use a reducer instead of state. A reducer is a function that takes the current state and an action as arguments, and returns a new state based on the action. This allows you to manage the state for your toast in a more modular and scalable way. Here is an example of how you might do this:</p></blockquote><pre><code class="language-javascript">import React, { useReducer, useEffect } from &#x27;react&#x27;;

const initialState = {
  toasts: []
};

function reducer(state, action) {
  switch (action.type) {
    case &#x27;SHOW_TOAST&#x27;:
      return {
        ...state,
        toasts: [...state.toasts, action.payload]
      };
    case &#x27;HIDE_TOAST&#x27;:
      const newToasts = [...state.toasts];
      newToasts.splice(action.payload, 1);
      return {
        ...state,
        toasts: newToasts
      };
    default:
      return state;
  }
}

function useToast() {
  const [state, dispatch] = useReducer(reducer, initialState);

  function showToast(msg, type) {
    dispatch({
      type: &#x27;SHOW_TOAST&#x27;,
      payload: { msg, type }
    });
  }

  function hideToast(index) {
    dispatch({
      type: &#x27;HIDE_TOAST&#x27;,
      payload: index
    });
  }

  useEffect(() =&gt; {
    let timeoutIds = [];
    state.toasts.forEach((_, index) =&gt; {
      timeoutIds[index] = setTimeout(() =&gt; hideToast(index), 3000);
    });

    return () =&gt; timeoutIds.forEach(timeoutId =&gt; clearTimeout(timeoutId));
  }, [state.toasts]);

  return {
    toasts: state.toasts,
    showToast,
    hideToast
  };
}

function App() {
  const { toasts, showToast, hideToast } = useToast();

  return (
    &lt;div&gt;
      {toasts.map((toast, index) =&gt; (
        &lt;div
          className={`toast toast-${toast.type}`}
          key={index}
        &gt;
          &lt;p&gt;{toast.msg}&lt;/p&gt;
          &lt;button onClick={() =&gt; hideToast(index)}&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      ))}
      &lt;button onClick={() =&gt; showToast(&#x27;This is a success toast!&#x27;, &#x27;success&#x27;)}&gt;
        Show Success Toast
      &lt;/button&gt;
      &lt;button onClick={() =&gt; showToast(&#x27;This is an error toast!&#x27;, &#x27;error&#x27;)}&gt;
        Show Error Toast
      &lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre><blockquote><p>In this example, the <code>useToast</code> hook uses the <code>useReducer</code> hook to manage the state for the toast. The reducer function takes the current state and an action as arguments, and returns a new state based on the action. The <code>App</code> component dispatches actions to show and hide the toast, and the <code>useEffect</code> hook is used to set a timeout for each toast to automatically hide it after a certain amount of time</p></blockquote><p>OK, that&#x27;s done. Now we decide we need this in Typescript:</p><blockquote><p>Please convert this to Typescript</p></blockquote><blockquote><p>Sure, here is an example of how you might convert the code to TypeScript:</p></blockquote><pre><code class="language-typescript">import React, { useReducer, useEffect } from &#x27;react&#x27;;

interface ToastState {
  toasts: {
    msg: string;
    type: string;
  }[];
}

const initialState: ToastState = {
  toasts: []
};

function reducer(state: ToastState, action: { type: string; payload: any }) {
  switch (action.type) {
    case &#x27;SHOW_TOAST&#x27;:
      return {
        ...state,
        toasts: [...state.toasts, action.payload]
      };
    case &#x27;HIDE_TOAST&#x27;:
      const newToasts = [...state.toasts];
      newToasts.splice(action.payload, 1);
      return {
        ...state,
        toasts: newToasts
      };
    default:
      return state;
  }
}

function useToast() {
  const [state, dispatch] = useReducer(reducer, initialState);

  function showToast(msg: string, type: string) {
    dispatch({
      type: &#x27;SHOW_TOAST&#x27;,
      payload: { msg, type }
    });
  }

  function hideToast(index: number) {
    dispatch({
      type: &#x27;HIDE_TOAST&#x27;,
      payload: index
    });
  }

  useEffect(() =&gt; {
    let timeoutIds = [];
    state.toasts.forEach((_, index) =&gt; {
      timeoutIds[index] = setTimeout(() =&gt; hideToast(index), 3000);
    });

    return () =&gt; timeoutIds.forEach(timeoutId =&gt; clearTimeout(timeoutId));
  }, [state.toasts]);

  return {
    toasts: state.toasts,
    showToast,
    hideToast
  };
}

function App() {
  const { toasts, showToast, hideToast } = useToast();

  return (
    &lt;div&gt;
      {toasts.map((toast, index) =&gt; (
        &lt;div
          className={`toast toast-${toast.type}`}
          key={index}
        &gt;
          &lt;p&gt;{toast.msg}&lt;/p&gt;
          &lt;button onClick={() =&gt; hideToast(index)}&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      ))}
      &lt;button onClick={() =&gt; showToast(&#x27;This is a success toast!&#x27;, &#x27;success&#x27;)}&gt;
        Show Success Toast
      &lt;/button&gt;
      &lt;button onClick={() =&gt; showToast(&#x27;This is an error toast!&#x27;, &#x27;error&#x27;)}&gt;
        Show Error Toast
      &lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre><blockquote><p>In this example, the code is written in TypeScript, and type annotations have been added to the functions and variables to specify the types of their arguments and return values. This allows the TypeScript compiler to check the code for type errors, and provides additional type information to other tools and libraries that can make use of it. You can modify this example further to suit your specific needs, such as adding additional types or using more advanced type features.</p></blockquote><p>Next, can it refactor this?</p><blockquote><p>Could we refactor this?</p></blockquote><blockquote><p>Yes, it is possible to refactor the code to make it more concise and modular. Here is an example of how you might do this:</p></blockquote><pre><code class="language-typescript">import React, { useReducer, useEffect } from &#x27;react&#x27;;

interface Toast {
  msg: string;
  type: string;
}

type State = Toast[];

type Action =
  | { type: &#x27;SHOW_TOAST&#x27;; payload: Toast }
  | { type: &#x27;HIDE_TOAST&#x27;; payload: number };

const initialState: State = [];

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case &#x27;SHOW_TOAST&#x27;:
      return [...state, action.payload];
    case &#x27;HIDE_TOAST&#x27;:
      const newToasts = [...state];
      newToasts.splice(action.payload, 1);
      return newToasts;
    default:
      return state;
  }
}

function useToast() {
  const [toasts, dispatch] = useReducer(reducer, initialState);

  useEffect(() =&gt; {
    const timeoutIds = toasts.map((_, index) =&gt;
      setTimeout(() =&gt; dispatch({ type: &#x27;HIDE_TOAST&#x27;, payload: index }), 3000)
    );
    return () =&gt; timeoutIds.forEach(clearTimeout);
  }, [toasts]);

  return {
    toasts,
    showToast: (msg: string, type: string) =&gt;
      dispatch({ type: &#x27;SHOW_TOAST&#x27;, payload: { msg, type } }),
    hideToast: (index: number) =&gt;
      dispatch({ type: &#x27;HIDE_TOAST&#x27;, payload: index })
  };
}

function App() {
  const { toasts, showToast, hideToast } = useToast();

  return (
    &lt;div&gt;
      {toasts.map((toast, index) =&gt; (
        &lt;div
          className={`toast toast-${toast.type}`}
          key={index}
        &gt;
          &lt;p&gt;{toast.msg}&lt;/p&gt;
          &lt;button onClick={() =&gt; hideToast(index)}&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      ))}
      &lt;button onClick={() =&gt; showToast(&#x27;This is a success toast!&#x27;, &#x27;success&#x27;)}&gt;
        Show Success Toast
      &lt;/button&gt;
      &lt;button onClick={() =&gt; showToast(&#x27;This is an error toast!&#x27;, &#x27;error&#x27;)}&gt;
        Show Error Toast
      &lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre><blockquote><p>In this example, the code has been refactored to use more concise and modular functions and types. The reducer function has been simplified and made more type-safe by using a union type for the <code>Action</code> type, and the <code>useToast</code> hook has been refactored to use the useReducer hook more effectively and efficiently. Additionally, the code has been cleaned up and made more readable by using modern JavaScript features and conventions. You can modify this example further to suit your specific</p></blockquote><p>Great. Now, we should really write a test for this. Let&#x27;s see if ChatGPT can do that for us:</p><blockquote><p>How might we test this hook with Jest?</p></blockquote><blockquote><p>To test the <code>useToast</code> hook with Jest, you can write a test that uses the act function from the <code>@testing-library/react</code> library to simulate user interactions with the component and verify that the hook behaves as expected. Here is an example of how you might write a test for the <code>useToast</code> hook:</p></blockquote><pre><code class="language-typescript">import React from &#x27;react&#x27;;
import { act, renderHook } from &#x27;@testing-library/react-hooks&#x27;;
import { useToast } from &#x27;./useToast&#x27;;

describe(&#x27;useToast&#x27;, () =&gt; {
  it(&#x27;should show and hide toasts&#x27;, () =&gt; {
    const { result } = renderHook(() =&gt; useToast());
    const { toasts, showToast, hideToast } = result.current;

    // Initially, there should be no toasts
    expect(toasts).toEqual([]);

    // Show a toast and verify that it appears in the state
    act(() =&gt; showToast(&#x27;This is a test toast&#x27;, &#x27;success&#x27;));
    expect(toasts).toEqual([{ msg: &#x27;This is a test toast&#x27;, type: &#x27;success&#x27; }]);

    // Hide the toast and verify that it disappears from the state
    act(() =&gt; hideToast(0));
    expect(toasts).toEqual([]);
  });
});
</code></pre><blockquote><p>In this test, the <code>renderHook</code> function from the <code>@testing-library/react-hooks</code> library is used to render the <code>useToast</code> hook in a test environment. The test then simulates user interactions with the hook by calling the <code>showToast</code> and <code>hideToast</code> functions, and verifies that the toasts are shown and hidden as expected. This test can be further extended to cover additional scenarios and edge cases, such as showing multiple toasts at once or verifying the behavior of the hook when an error occurs.</p></blockquote><p>Overall, this looks pretty good! I&#x27;d need to spend a lot more time than I can spare now to try to find if there are any issues with it, and it wouldn&#x27;t surprise me if there were a few bugs, but it looks fairly sounds as an example.</p><h2>Getting examples of the use of a technique</h2><p>Another thing that ChatGPT seems useful for is creating examples. For instance, I&#x27;ve never had the occasion to use render props in React, so I asked ChatGPT the following question:</p><blockquote><p>Please demonstrate the use of render props with functional React components</p></blockquote><blockquote><p>Sure! In React, a &quot;render prop&quot; is a technique for sharing code between React components using a prop whose value is a function. This function is used to render the content of the component. Using a render prop with a functional component is no different than using it with a class-based component. Here&#x27;s an example:</p></blockquote><pre><code class="language-javascript">function MyComponent(props) {
  return (
    &lt;div&gt;
      {props.render(props.value)}
    &lt;/div&gt;
  );
}
</code></pre><blockquote><p>In the above example, MyComponent is a functional component that has a render prop, which is a function that is used to render the content of the component. The render prop takes a value prop as an argument, which can be used in the rendering of the content.</p></blockquote><blockquote><p>Here&#x27;s an example of how you might use this component:</p></blockquote><pre><code class="language-javascript">&lt;MyComponent
  value={5}
  render={value =&gt; (
    &lt;div&gt;
      The value is {value}.
    &lt;/div&gt;
  )}
/&gt;
</code></pre><blockquote><p>In this example, the value passed to the value prop is 5, and the render prop is a function that returns a div element with the text &quot;The value is 5&quot;.</p></blockquote><blockquote><p>In summary, using a render prop with a functional component is just a matter of using a prop whose value is a function, and using that function to render the content of the component.</p></blockquote><p>I personally find this is a better, more concise example than the one in the React documentation, so I&#x27;m quite pleased with that as an example. Now let&#x27;s ask for them in Typescript:</p><blockquote><p>Please convert these examples to Typescript</p></blockquote><blockquote><p>Sure, here are the examples written in TypeScript:</p></blockquote><pre><code class="language-typescript">function MyComponent(props: { value: any; render: (value: any) =&gt; React.ReactNode }) {
  return (
    &lt;div&gt;
      {props.render(props.value)}
    &lt;/div&gt;
  );
}
</code></pre><pre><code class="language-typescript">&lt;MyComponent
  value={5}
  render={(value: any) =&gt; (
    &lt;div&gt;
      The value is {value}.
    &lt;/div&gt;
  )}
/&gt;
</code></pre><blockquote><p>In the first example, the MyComponent function is defined to take an object with two properties: value and render. The value property is of type any, which means it can be any value. The render property is a function that takes a value of type any and returns a React.ReactNode, which is the type of value that can be rendered by a React component.</p></blockquote><blockquote><p>In the second example, the value prop is passed the value 5, which is a number. The render prop is passed a function that takes a value of type any and returns a div element.</p></blockquote><blockquote><p>I hope this helps! Let me know if you have any other questions.</p></blockquote><p>Nice one!</p><h2>Refactoring from a legacy framework</h2><p>I thought I&#x27;d try another example that was more immediately useful to me. I work on a large legacy Zend 1 framework which I&#x27;m slowly trying to modernize, and a big chunk of the models have been migrated to Eloquent, but the controllers are the biggest blocker by far to migrating to a newer framework, and as long as they&#x27;re in use we can&#x27;t migrate easily migrate some other parts, such as the forms. I wrote an example Zend 1 controller and asked ChatGPT the following question:</p><blockquote><p>Given the following Zend 1 controller:</p></blockquote><pre><code class="language-php">&lt;?php

use App\Forms\CategoryForm;
use App\Models\Category;

final class CategoriesController extends Zend_Controller_Action
{
    public function indexAction(): void
    {
        $this-&gt;view-&gt;categories = Category::all();
    }

    public function addAction(): void
    {
        $request = $this-&gt;getRequest();
        assert($request instanceof Zend_Http_Request_Http);
        if (!$request-&gt;isPost()) {
            throw new Zend_Controller_Action_Exception(&quot;Unsupported method&quot;, 405);
        }
        $form = new CategoryForm();
        if (!$form-&gt;isValid($request-&gt;getPost())) {
            throw new Zend_Controller_Action_Exception(&quot;Invalid data&quot;, 422);
        }
        $category = Category::create([
            &#x27;name&#x27; =&gt; $form-&gt;name-&gt;getValue(),
        ]);
        $this-&gt;view-&gt;category = $category;
    }
}
</code></pre><blockquote><p>Please convert it to a Laravel controller</p></blockquote><p>It came back with:</p><blockquote><p>Here is a possible conversion of the given Zend 1 controller to a Laravel controller:</p></blockquote><pre><code class="language-php">&lt;?php

use App\Http\Controllers\Controller;
use App\Forms\CategoryForm;
use App\Models\Category;
use Illuminate\Http\Request;

class CategoriesController extends Controller
{
    public function index(): void
    {
        $categories = Category::all();
        return view(&#x27;categories.index&#x27;, compact(&#x27;categories&#x27;));
    }

    public function add(Request $request): void
    {
        if (!$request-&gt;isMethod(&#x27;post&#x27;)) {
            abort(405, &#x27;Unsupported method&#x27;);
        }
        $form = new CategoryForm();
        if (!$form-&gt;isValid($request-&gt;all())) {
            abort(422, &#x27;Invalid data&#x27;);
        }
        $category = Category::create([
            &#x27;name&#x27; =&gt; $form-&gt;name-&gt;getValue(),
        ]);
        return view(&#x27;categories.add&#x27;, compact(&#x27;category&#x27;));
    }
}
</code></pre><blockquote><p>Note that this is just one possible way to convert the given code, and there may be other ways to accomplish the same thing using Laravel&#x27;s features and conventions.</p></blockquote><p>This looks pretty good to me. It does still depend on the Zend form classes, but once the controller has been rewritten for Laravel, it would be easy to replace them with form request classes. While this is a very minimal example, it shows the potential power of ChatGPT in terms of migrating legacy code to more modern frameworks. I&#x27;m sure it&#x27;s not always going to be 100% accurate, but other tools like Psalm, which I use anyway, will help find potential problems with method names or arguments being wrong, as will peer reviews of the code, and it&#x27;d certainly be less laborious than doing it all manually.</p><h2>Writing website copy</h2><p>I asked it the following question:</p><blockquote><p>Write the homepage copy for a website proving tips and tricks with performance improvements for web applications built with Laravel</p></blockquote><p>And it came back with:</p><blockquote><p>Welcome to Tips and Tricks for Laravel Performance!</p></blockquote><blockquote><p>Are you looking to improve the performance of your web application built with Laravel? You&#x27;ve come to the right place!</p></blockquote><blockquote><p>Our website provides a wealth of information and tips on how to optimize your Laravel application for maximum performance. From caching and database optimization, to code refactoring and route optimization, we&#x27;ve got you covered.</p></blockquote><blockquote><p>We also offer in-depth tutorials and guides on how to implement these performance improvements in your own Laravel application.</p></blockquote><blockquote><p>Don&#x27;t let slow performance hold your web application back. Take control and improve your Laravel application&#x27;s performance today with the help of Tips and Tricks for Laravel Performance.</p></blockquote><p>Not bad, I&#x27;ve certainly seen a lot worse than that from human writers. Next, I asked it to write a blog post for the site:</p><blockquote><p>Now write a blog post for this site on how to improve the performance of the site by setting appropriate HTTP headers, with code samples</p></blockquote><blockquote><p>Improving the performance of your Laravel application starts with understanding the role of HTTP headers. HTTP headers are key-value pairs that are sent in the header of an HTTP request or response, and provide important information about the request or response.</p></blockquote><blockquote><p>One of the ways to improve the performance of your Laravel application is to set appropriate HTTP headers. This allows the client, such as a web browser, to make more informed decisions about how to handle the request or response.</p></blockquote><blockquote><p>For example, setting the Cache-Control header can improve performance by allowing the client to cache the response, so that it doesn&#x27;t have to be fetched again on subsequent requests. This can be done in Laravel using the Response facade:</p></blockquote><pre><code class="language-php">use Illuminate\Support\Facades\Response;

// Set the Cache-Control header to cache the response for 1 hour
Response::header(&#x27;Cache-Control&#x27;, &#x27;max-age=3600&#x27;);
</code></pre><blockquote><p>Another important header for improving performance is the Expires header. This header specifies a date and time at which the response will no longer be considered fresh. This allows the client to make an informed decision about whether to use a cached version of the response or fetch a new one.</p></blockquote><blockquote><p>In Laravel, the Expires header can be set using the Response facade:</p></blockquote><pre><code class="language-php">use Carbon\Carbon;
use Illuminate\Support\Facades\Response;

// Set the Expires header to one hour from now
$expires = Carbon::now()-&gt;addHour();
Response::header(&#x27;Expires&#x27;, $expires-&gt;toRfc2822String());
</code></pre><blockquote><p>By setting these headers, you can improve the performance of your Laravel application by allowing the client to make more efficient use of caching. This can reduce the number of requests that need to be made to the server, resulting in faster load times and a better user experience.</p></blockquote><blockquote><p>Of course, there are many other HTTP headers that can be used to improve the performance of your Laravel application. For more information, check out the official Laravel documentation on HTTP headers.</p></blockquote><p>Not hugely comprehensive, but a reasonably good starting point. Using this to get you started seems like a good idea, and there&#x27;s nothing more intimidating than a blank page when you want to write a blog post.</p><h3>Overall impressions</h3><p>Even in its current state as a tech preview, ChatGPT is <em>hugely</em> impressive. It&#x27;s extraordinary how good it is at generating basic code samples for almost any use case I can think of. However, the distinct impression I get is that it&#x27;s not really capable of original thought. Most of the above is basically just taking stuff that&#x27;s already out there and essentially remixing it. There&#x27;s plenty of tutorials on writing all of the above and it looks to me like it&#x27;s just taking those and converting those according to the provided specifications.</p><p>However, don&#x27;t get the impression that doesn&#x27;t make it useful. I&#x27;ve used Github Copilot for a while and that offers dramatic improvements in productivity, and this has the potential to be much more significant. As shown above, it can migrate a simple controller from Zend 1 to Laravel, with the result looking perfectly acceptable, and the value of that should be clear to anyone who has to work on a large legacy project. Similarly you can ask it to rewrite something to use a specific design pattern and the end result is perfectly acceptable. It&#x27;s a fantastic learning tool too since you can ask it to provide an example specific to your use case rather than trawling through blog posts, where most of them might have different requirements to you. As such it&#x27;s going to hugely improve developer productivity.</p><p>To a large extent, I think something like this is going change the developer&#x27;s role by shifting the emphasis of it somewhat from the productive to the executive, with our job being more akin to editors than authors. Coding will become less about solving the problem and more about defining the problem in the first place and letting the system solve it. However, I don&#x27;t think it will automate our jobs away entirely - the quality of the code it produces is variable, to say the least, and there will definitely be a need to be able to debug it, and solve more unusual problems.</p><p>However, if my job involved writing spammy blog posts for ad money, I&#x27;d be <em>very</em> worried about my future prospects. I think tools like this will probably be writing most of the spammier sort of blog posts that just exist to get clicks on the web in a year at most. I&#x27;ve actually just asked it to write a blog post I&#x27;ve wanted to write for a while now for me, and the end result looks pretty solid right now - I&#x27;d anticipate it saved me about 90% of the work, with the remaining 10% just a case of cleaning it up.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Why I no longer use the repository pattern]]></title>
        <id>https://matthewdaly.co.uk/blog/2022/10/26/why-i-no-longer-use-the-repository-pattern/</id>
        <link href="https://matthewdaly.co.uk/blog/2022/10/26/why-i-no-longer-use-the-repository-pattern/"/>
        <updated>2022-10-26T17:30:00.000Z</updated>
        <content type="html"><![CDATA[<p>In September 2016, I started a new job after my previous employer went into liquidation. I expected a certain learning curve because I was going from an environment where I&#x27;d been the main driver of establishing coding standards and TDD (and which often felt like pushing a boulder up a hill) to one where there was a large-ish team of ten developers, and so there would be established standards in order to try to help keep things consistent between projects. One of the biggest changes for me was adopting the repository pattern - it was used routinely on every project. The lead developer was very keen on it as it offered the following benefits:</p><ul><li>A high-level abstraction over Eloquent, allowing for relatively easy replacement of Eloquent with raw database queries, Doctrine, MongoDB, CouchDB etc</li><li>Easy caching by wrapping the repository class in a caching decorator</li></ul><p>I quite quickly embraced this concept, and began routinely using the repository pattern as a matter of course on new projects. Yet nowadays, I&#x27;ve largely stopped using the repository pattern, because experience has taught me that it&#x27;s really not all it&#x27;s cracked up to be. It often adds very little value for a lot of effort, and I really don&#x27;t think it&#x27;s often worthwhile. Here I&#x27;ll break down the reasons I no longer use it.</p><h2>Eloquent is already an abstraction</h2><p>Out of the box, Eloquent supports SQLite, MySQL/MariaDB, PostgreSQL and MSSQL. It <em>is</em> a somewhat leaky abstraction, but that can&#x27;t be helped, and as <a href="https://www.martinfowler.com/bliki/OrmHate.html">Martin Fowler said</a>, that isn&#x27;t a reason to avoid them. Mapping relational data to object oriented code is <em>hard</em>, and if you expect your ORM to completely abstract away the difference between relational databases, then your expectations are unreasonable. ORMs cover the 90% use cases very well, which makes a lot of stuff significantly easier, and offer escape hatches for when you need them. Unless you have a really good reason not to, you should be using the default ORM provided by your framework, and the onus is on you to justify not doing so if you feel it makes sense.</p><p>Furthermore, it&#x27;s possible to extend Eloquent to support various non-relational data backends such as:</p><ul><li>Markdown, YAML and JSON files, through <a href="https://github.com/ryangjchandler/orbit">Ryan Chandler&#x27;s Orbit package</a></li><li>MongoDB, through <a href="https://github.com/jenssegers/laravel-mongodb">Jens Seger&#x27;s laravel-mongodb package</a></li></ul><p>If you <em>really</em> need to rewrite an existing application to support a whole new database backend that isn&#x27;t supported out of the box by Eloquent, or by an off-the-shelf package, then ultimately you could consider writing your own Eloquent extension to facilitate this. But I&#x27;d be very surprised if that happens often.</p><h2>You <em>probably</em> won&#x27;t ever need to switch database backends to something Eloquent doesn&#x27;t support</h2><p>If you&#x27;re building an application that uses a relational database, then it&#x27;s likely that most of the data you are storing is fairly well-suited to a relational data model (if it wasn&#x27;t, why would you be using a relational model now?). As such, it&#x27;s decidedly unlikely that you&#x27;re ever going to need to migrate it to a non-relational database store, unless something fairly fundamental changes. Building out repositories on the offchance you <em>might</em> one day need to migrate to a database backend not supported by Eloquent, or to a database interface other than Eloquent, is probably excessive, and unless you have a very specific use case, a violation of the <a href="https://www.martinfowler.com/bliki/Yagni.html">YAGNI principle</a>.</p><p>I&#x27;m not going to pretend my own experience is necessarily representative of <em>every</em> possible experience (nor should you insinuate the same), but I&#x27;ve been in the industry since 2011, and the only time I&#x27;ve <em>ever</em> had to migrate a website from one database engine to another was with a legacy Zend 1 application that takes up a lot of my time at work. That had been on the same server since around 2010, despite a rather shaky rewrite in 2015 before I got there, and was still using MySQL 5.0, and PHP 5.4. It became necessary to move it to a new server, and it wasn&#x27;t possible (or desirable) to install a version of MySQL that old on the new server. As such I took the decision that we needed to bite the bullet and migrate to a currently supported database, despite the potential issues it could cause. Given there were inevitably going to be teething troubles when migrating a large, <em>very</em> legacy application with no tests, but that most of the existing queries were not very sophisticated, then migrating to MariaDB 10.2 would be no harder than migrating to MySQL 5.7, so I opted for the former. While this did cause some grief (particularly with respect to boolean fields), it used the same Zend 1 database layer, built on top of PDO, despite migrating to a different version of a different database (albeit a fork of the original).</p><p>And if the problem is that the amount of data means that queries are taking too long, it could easily be simply that there aren&#x27;t appropriate indexes set up, as <a href="https://www.commitstrip.com/en/2014/06/03/the-problem-is-not-the-tool-itself/">memorably demonstrated in Commitstrip</a>.</p><h2>You <em>probably</em> won&#x27;t ever need to switch away from Eloquent to another database interface</h2><p>This is an edge case that&#x27;s probably not worth even thinking about. The only circumstances under which you might be confronted with an explicit need to migrate away from Eloquent are the following:</p><ul><li>Laravel drops Eloquent in favour of a new ORM, in which case there will be a clear migration path to the new ORM</li><li>A site built in another framework, or without a framework, but using Eloquent, can no longer use it and must be migrated to an alternative database interface</li><li>Laravel development ceases, or you have to move an existing site away from it without doing a full rewrite for some other reason</li></ul><p>I&#x27;ve been in the situation on the aforementioned legacy project of migrating from Zend 1 DB to Eloquent, and it really isn&#x27;t that big a deal to do so because all these query builders and database interfaces do largely the same thing - there are some implementation details that differ, but they&#x27;re never all that different, and where you&#x27;re using database-specific functionality then you&#x27;re likely using one of the escape hatches to write raw SQL anyway. The only problems I&#x27;ve encountered are down to the original developer rolling their own crappy legacy models, not to the underlying queries.</p><p>And if you&#x27;re planning on migrating away from Eloquent to raw database queries, just because someone told you it&#x27;s faster, <a href="/blog/2022/06/05/the-orm-delusion/">don&#x27;t</a>.</p><h2>If you <em>do</em> need to switch to an unsupported backend, you probably won&#x27;t need to switch <em>every</em> table, and if you do, it won&#x27;t all be at once</h2><p>If you do determine that you need to switch part of your application to a different database engine, it&#x27;s very unlikely that the whole database needs to be replaced lock, stock and barrel. Most likely, it&#x27;ll be a handful of tables that are a better fit for a different data store. Under these circumstances, why would you want to move other tables, which <em>are</em> a good fit for the relational model, to a different database, and potentially degrade performance?</p><p>Most likely, what you&#x27;ll end up with is a hybrid model where most of your data is relational and is stored in something Eloquent can work with, while the other data which is a better fit for a different data store is handled by an alternative backend. That limits the scope of any changes you need to make to just those queries that touch on the table you plan to migrate. And as stated above, implementing that on the offchance you may need it in future is a violation of YAGNI.</p><p>And if the reason for switching is due to the sheer size of the data, different tables will likely reach that point at different times, so you can migrate each one to the new store at the point it starts to become an issue.</p><h2>The availability of JSON fields in relational databases reduce the necessity for non-relational databases</h2><p>It used to be the case that storing arbitrary keys and values in a relational database was tricky, and you had to resort to sub-optimal solutions such as <a href="https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model">Entity-Attribute-Value</a>, as used by, for example, the WordPress <code>wp_postmeta</code> table. At that time, a relational database such as MongoDB offered a significant advantages in terms of being able to store arbitrary data.</p><p>Since then, most relational databases have introduced new field types such as HStoreField or JSON field types, which allow for easily storing arbitrary keys and values within a row of a relational database, and ORMs such as Eloquent allow for casting that data to a convenient form. As such, that particular use case for a non-relational database over a relational one is now largely redundant. It&#x27;s also possible to enforce a JSON schema so that you can exercise as much or as little control over the data as necessary.</p><p>There are other use cases for non-relational databases, but most of those only really come into play when you have truly colossal amounts of data, and to be honest it takes a <em>long</em> time to get to that point. If you get to the point where you need to worry about those kind of issues, you can probably afford to deal with it.</p><h2>Using the repository pattern for every query involves writing a <em>lot</em> of boilerplate code</h2><p>Writing a repository class for all the models you plan to use in an application is something not to be taken lightly. You have to collect every query you&#x27;re ever going to make against a specific table and place it in one class, and for a large application that will be a lot of work. Yes, there will be some common methods that can live in a base class, such as ones for all items, items by ID, paginated list etc, but there will still be a lot of work involved, and it will likely be quite repetitive, with some differing only slightly.</p><p>And if you&#x27;re also planning to decorate the repositories to be able to cache them, the burden increases significantly. For each model, you need an interface for the repository, a class for the repository implementation, and a class for the decorator, as well as all the boilerplate to resolve the interface correctly.</p><h2>Returning arrays sacrifices type safety</h2><p>Honestly, this is probably the biggest issue for me these days. I routinely use Psalm on my projects these days, and it&#x27;s been hugely beneficial to those projects to have that kind of feedback about how well-typed my code is. Abstracting away the difference between queries when using different repository implementations means we can&#x27;t return ORM-specific objects, leaving us with two alternatives:</p><ul><li>Return arrays, which can&#x27;t be so easily type-hinted - we can annotate those arrays to tell tools like Psalm what shape we expect back, but it&#x27;s harder to enforce that, and the annotations can get out of sync easily.</li><li>Return a more generic data transfer object (or a collection or array thereof) containing the data, in which case we have to write yet more boilerplate code - a DTO for each model, plus the logic to convert the data from an Eloquent model to an instance of the DTO.</li></ul><p>Neither of these options are great. The first one reduces the type safety of the application substantially, and the second will cause you an awful lot of work for very little benefit. I would definitely struggle to justify this to my bosses or clients.</p><h2>The supposed improvements in testability don&#x27;t really pan out in practice</h2><p>A big part of the promise of the repository pattern is being able to run unit tests without hitting the database. The trouble is that a database is an integral part of your application, and replacing it with mocks often isn&#x27;t very useful. Mocks are only as good as the data they provide, and if your mock data diverges from what the database actually provides, it&#x27;s easy for issues to slip through without being caught by your tests.</p><p>As long as you have migrations that can recreate the structure of your database accurately (if not the content), then you can happily use an in-memory SQLite database as an alternative to your production database for most functionality that isn&#x27;t database-specific. That&#x27;s not to say it&#x27;s always a drop-in replacement for your production database, and you should be aware of the possibility of differences in behaviour between databases if you&#x27;re using something else in production, but it&#x27;s a damn sight closer to MySQL in behaviour than mocking out the query. Often, a good compromise is to use an in-memory SQLite database for testing locally, where it&#x27;s more important to be able to run tests quickly, but use your production database engine in continuous integration where it&#x27;s more important for everything to be correct. If you&#x27;re building a generic package where it needs to support every database engine supported by Eloquent, then your continuous integration solution should of course actively test against every supported database engine.</p><p>If there are use cases where you need to use functionality from MySQL or PostgreSQL that doesn&#x27;t exist in SQLite in tests, James Bannister <a href="https://bannister.me/blog/using-mysql-and-postgres-functions-in-sqlite">suggested a way to patch missing functions that can help</a>.</p><h2>It&#x27;s not a good fit for an ActiveRecord-style ORM</h2><p>Repositories are generally a better fit for a DataMapper-style ORM than ActiveRecord, and many actually include a repository implementation by default, eg Doctrine. This isn&#x27;t a criticism of ActiveRecord, which is a simple, intuitive way of building an ORM, and is implemented by many other frameworks too (Django is a good example), but sometimes it&#x27;s just not a good fit for your application.</p><p>If you really <em>need</em> the specific advantages of the repository pattern, then trying to retrofit it to an ActiveRecord-style ORM like Eloquent from the outset is an awful lot of work. There&#x27;s a <a href="http://laraveldoctrine.org/">Doctrine integration for Laravel</a> and you&#x27;re far better off just using that, rather than trying to wrap your own implementation around Eloquent. Almost invariably, your own implementation will be crappier than that, and involve a lot more work, so why waste time and effort on it?</p><h2>What I do nowadays</h2><p>I haven&#x27;t <em>completely</em> stopped using the repository pattern. What I tend to do nowadays is as follows:</p><ul><li>For simple or one-off queries, I use Eloquent directly. There&#x27;s not much value in abstracting away something simple like <code>Page::find($id)</code>, or a <em>slightly</em> more complex query that&#x27;s used only in one place.</li><li>For repetitive parts of queries, local scopes offer a convenient and consistent way to abstract away that functionality. For instance, on the aforementioned legacy project, which now uses Eloquent, the various content types have a scope called <code>scopeIsInDate()</code> to retrieve only items which are in date.</li><li>For a small number of queries that relate to a specific model instance, I define them as methods on the model class itself. These tend to be things to do with a relation of the model.</li><li>For more complex queries, or those which are used in multiple places, I do use repository classes of a sort, but these are just convenient containers for those queries in order to avoid duplication.</li><li>For <em>really</em> complex queries, such as those for reports across multiple tables, I use dedicated query classes. These break the subqueries for different tables out into different private methods and perform a <code>UNION</code> across those subqueries, so they require a lot of repetitive queries. Long-term the solution would be to refactor those tables down to a single table for the various content types, but that&#x27;s not going to be practical any time soon.</li></ul><p>That said, the work I do now is different - I used to build APIs for mobile apps where the endpoints were generally generic endpoints that exposed CRUD functionality for different types of resources. It&#x27;s been a while since I&#x27;ve done that, and the repository pattern would arguably provide more benefit for that kind of functionality where most of the queries were things like &quot;get this resource by ID&quot;, &quot;get paginated list of these resources&quot; etc.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Everything's (potentially) a callable]]></title>
        <id>https://matthewdaly.co.uk/blog/2022/10/02/everythings-potentially-a-callable/</id>
        <link href="https://matthewdaly.co.uk/blog/2022/10/02/everythings-potentially-a-callable/"/>
        <updated>2022-10-02T19:30:00.000Z</updated>
        <content type="html"><![CDATA[<p>I&#x27;m a big fan of callables in PHP in general. They&#x27;re an extremely powerful way to build applications out of many different reusable components, in a way that combines the best aspects of object-oriented and functional programming.</p><p>If you&#x27;re not familiar with the idea, consider this class:</p><pre><code class="language-php">&lt;?php

declare(strict_types=1);

namespace App\Jobs;

use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Benchmark;

final class Printer
{
    public function __invoke(string $value): void
    {
        echo $value;
    }
}
</code></pre><p>Note the use of the <code>__invoke()</code> magic method. This gets called if you try to call the object as a function, eg:</p><pre><code class="language-php">&lt;?php

// Will echo &quot;Hello, World!&quot;
$printer = new Printer();
$printer(&quot;Hello, World!&quot;);
</code></pre><p>Now, this may not seem like a terribly big deal, but it&#x27;s only once you start putting them together that their real power becomes apparent. They&#x27;re essentially &quot;closures on steroids&quot; in that they can do basically anything a closure can, and a lot of stuff they can&#x27;t:</p><ul><li>An invokable class passes the <code>callable</code> type hint, so you can generally use it in most of the same places you would a closure. As such, if you have a closure whose functionality needs to be reused elsewhere, it may make sense to refactor it into an invokable class.</li><li>Because they&#x27;re classes, if they get large enough for it to be worthwhile, you can refactor part of the functionality into private methods. You can also pull in additional functionality through inheritance or traits if need be, but as this approach makes composition more achievable, you may find you don&#x27;t often need to do so.</li><li>You can use constructor injection to pull in any dependencies the class has in a way you can&#x27;t with closures.</li></ul><p>As such, invokables let you chain functionality in the same way you would with closures, but with more capabilities and a higher level of abstraction. For instance, imagine you work on an e-commerce application, where each order is represented by an ORM model called <code>Order</code>, and the job to process an order is implemented in an invokable class called <code>ProcessOrder</code>, which accepts an instance of <code>Order</code>. Now, imagine a third party want to place multiple orders by sending a CSV file over FTP. Because you implemented <code>ProcessOrder</code> as an invokable, all you need to do is get the CSV data, generate an instance of <code>Order</code> from each row, and pass it into <code>ProcessOrder</code>, without changing a single existing line of code. You might do something like this:</p><pre><code class="language-php">&lt;?php

$data = file_get_contents($remote_url);
$result = Collection::make($data)
    -&gt;map(App::make(ConvertToOrder::class))
    -&gt;each(App::make(ProcessOrder::class));
</code></pre><p>All <code>ConvertToOrder</code> has to do is take the array data and create the model instance, then pass it on. Orders are processed consistently between those on the e-commerce site and those received via FTP, and the amount of new code required is minimal, limited to the <code>ConvertToOrder</code> class and whatever command class is being triggered (in this case, it might be an Artisan command). As long as you&#x27;ve picked an appropriate name for each class, it&#x27;s really obvious how this pipeline works and what each step does, without the developer having to even open the class in question.</p><p>Using <code>__invoke()</code> as the defined method for doing something when the class only carries out a single action also makes sense as a general convention. If the class name, by itself, defines what the class is meant to do, then a method name is largely superfluous, and you end up making your method something like <code>process()</code>, <code>execute()</code> or <code>handle()</code>. Using <code>__invoke()</code> instead is both more concise and more consistent, because it allows you to use the shorter syntax, without the need to either choose or remember an actual method name.</p><p>Assuming you&#x27;re working with a framework like Laravel, then as long as you&#x27;re working on a class that&#x27;s not one of the class types explicitly required by the framework, then you should be fine to use invokables however you like. For instance, if you have something like the <code>ProcessOrder</code> service class above, then its only real dependency on Laravel itself would be that it takes in an ORM instance, plus whatever is pulled in via constructor injection. However, classes generated by the framework itself are more dependent on a particular, predefined structure. That said, there are some parts of the framework that are amenable to using invokables.</p><h2>Controllers</h2><p>For a while now, Laravel has supported <a href="https://laravel.com/docs/9.x/controllers#single-action-controllers">single action controllers</a>, which implement a single <code>__invoke()</code> method, as in this example:</p><pre><code class="language-php">&lt;?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\User;

final class FooController extends Controller
{
    /**
     * Return a view
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        return view(&#x27;foo&#x27;);
    }
}
</code></pre><p>This has the following advantages:</p><ul><li>Injecting dependencies into a controller&#x27;s constructor adds to the time taken to process the request, and if you have a controller which handles multiple actions, then you may often be injecting dependencies for a route which aren&#x27;t required for that route, which can have a noticeable performance impact. By breaking larger controllers down into single action controllers, you can prevent that from happening.</li><li>Setting up routing for the controller is simpler - it just needs to accept the class name, not the method name.</li></ul><p>Using callables as controllers doesn&#x27;t make sense for every use case. For instance, if you&#x27;re building an API that exposes CRUD functionality for multiple resource types, it probably makes more sense to use a resource controller which defines all the actions for a given resource type, particularly if they&#x27;re similar enough that you&#x27;re extending a base resource controller with common functionality. But for any reasonably complex route, it may make sense to use a single action controller.</p><h2>Middleware</h2><p>Middleware is something else that only really has one public method and could therefore be implemented as an invokable, at least in theory. Some frameworks, such as Laminas, explicitly support it. The Laravel documentation doesn&#x27;t appear to mention it, but after some experimentation I&#x27;ve discovered that it&#x27;s possible to use callables as middleware in Laravel. For instance, take this callable middleware class I wrote:</p><pre><code class="language-php">&lt;?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Illuminate\Http\Request;
use Illuminate\Http\Response;

final class CallableDemo
{
    public function __invoke(Request $request, $next): Response
    {
        $response = $next($request);
        $response-&gt;header(&#x27;X-Clacks-Overhead&#x27;, &#x27;GNU Terry Pratchett&#x27;);
        return $response;
    }
}
</code></pre><p>This is a relatively simple middleware class which adds the <a href="http://www.gnuterrypratchett.com/">X-Clacks-Overhead header</a> to the response. At least in a recent version of Laravel 9, the following method of adding middleware in the router works:</p><pre><code class="language-php">&lt;?php

...
use App\Http\Middleware\CallableDemo;

...

Route::resource(&#x27;foo&#x27;, FooController::class)
-&gt;middleware(CallableDemo::class);
</code></pre><p>As does declaring it as global middleware in <code>app\Http\Kernel.php</code>:</p><pre><code class="language-php">&lt;?php

namespace App\Http;
...

class Kernel extends HttpKernel
{
    protected $middleware = [
        ...
        \App\Http\Middleware\CallableDemo::class,
    ];
</code></pre><p>Or in the <code>web</code> group:</p><pre><code class="language-php">&lt;?php

...
    /**
     * The application&#x27;s route middleware groups.
     *
     * @var array&lt;string, array&lt;int, class-string|string&gt;&gt;
     */
    protected $middlewareGroups = [
        &#x27;web&#x27; =&gt; [
            ...
            \App\Http\Middleware\CallableDemo::class,
        ],
</code></pre><p>Or as route middleware:</p><pre><code class="language-php">&lt;?php
    protected $routeMiddleware = [
        ...
        &#x27;gnu&#x27;   =&gt; \App\Http\Middleware\CallableDemo::class,
    ];
</code></pre><p>This example doesn&#x27;t cover middleware that accepts dependencies from the container, however. So what if we amend our middleware class to accept a raw database connection as a constructor dependency and use that in the middleware body to add a header giving the total number of users, as in this example?</p><pre><code class="language-php">&lt;?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Illuminate\Database\ConnectionInterface;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

final class CallableDemo
{
    public function __construct(private ConnectionInterface $db)
    {
    }

    public function __invoke(Request $request, $next): Response
    {
        $response = $next($request);
        $response-&gt;header(&#x27;X-Clacks-Overhead&#x27;, &#x27;GNU Terry Pratchett&#x27;);
        $response-&gt;header(&#x27;X-Total-Users&#x27;, $this-&gt;db-&gt;table(&#x27;users&#x27;)-&gt;count());
        return $response;
    }
}
</code></pre><p>Yes, looks like this works fine too.</p><h2>Queue jobs</h2><p>Job classes are something else that do only one thing, and thus it potentially makes sense to use an invokable class for them. Consider this job class which uses the Benchmark helper to benchmark a query and dump the results to the screen:</p><pre><code class="language-php">&lt;?php

declare(strict_types=1);

namespace App\Jobs;

use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Benchmark;

final class ThingDoer
{
    public function __construct(private ConnectionInterface $db)
    {
    }

    public function __invoke()
    {
        Benchmark::dd(fn() =&gt; $this-&gt;db-&gt;table(&#x27;users&#x27;)-&gt;get());
    }
}
</code></pre><div>This example will work if you&#x27;re using the sync queue connection type, but likely not with any others, because the intent is to run a query and dump it out. Obviously, that isn&#x27;t really the main use case of job classes, but it&#x27;s fine for demonstrating the principle of using invokable classes for tasks that do one thing only.</div><p>If we try the following in a route closure:</p><pre><code class="language-php">Route::get(&#x27;/&#x27;, function () {
    dispatch(ThingDoer::class);
</code></pre><p>We see the error <code>get_class(): Argument #1 ($object) must be of type object, string given</code>. So instead, we need to fetch <code>ThingDoer</code> from the container and pass it to <code>dispatch()</code>:</p><pre><code class="language-php">Route::get(&#x27;/&#x27;, function (ThingDoer $doer) {
    dispatch($doer);
</code></pre><p>In a controller, it may well make more sense to do this via method injection.</p><h2>Event listeners</h2><p>Event listeners are yet another example of something that only really does one thing. This invokable listener is based on the one used to send notifications in <a href="https://bootcamp.laravel.com/inertia/notifications-and-events">Laravel Bootcamp</a>:</p><pre><code class="language-php">&lt;?php

namespace App\Listeners;

use App\Events\ChirpCreated;
use App\Models\User;
use App\Notifications\NewChirp;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SendChirpCreatedNotifications implements ShouldQueue
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  \App\Events\ChirpCreated  $event
     * @return void
     */
    public function __invoke(ChirpCreated $event)
    {
        foreach (User::cursor() as $user) {
            $user-&gt;notify(new NewChirp($event-&gt;chirp));
        }
    }
}
</code></pre><p>This works in exactly the same way as a standard listener class. If you map it to an event class in the usual way, it works entirely as expected. However, as with some of the other examples, it&#x27;s not clear if it supports constructor injection, so it&#x27;s best to check. If we amend the listener as follows:</p><pre><code class="language-php">&lt;?php

namespace App\Listeners;

use App\Events\ChirpCreated;
use App\Models\User;
use App\Notifications\NewChirp;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Queue\InteractsWithQueue;

class SendChirpCreatedNotifications implements ShouldQueue
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct(private ConnectionInterface $db)
    {
    }

    /**
     * Handle the event.
     *
     * @param  \App\Events\ChirpCreated  $event
     * @return void
     */
    public function __invoke(ChirpCreated $event)
    {
        foreach ($this-&gt;db-&gt;table(&#x27;users&#x27;)-&gt;cursor() as $user) {
            dd($user);
        }
    }
}
</code></pre><p>Now, if we trigger the <code>ChirpCreated</code> event, it breaks at the right point and spits out the user data as expected, thus demonstrating that it works.</p><h2>Limitations</h2><p>There are some limitations of using invokable classes which you should bear in mind when deciding whether to make a class an invokable or not. For instance, accessing an invokable as as property of another class can be awkward - take this controller class:</p><pre><code class="language-php">&lt;?php

namespace AppServiceProvider

use App\Jobs\ThingDoer;

final class FooController extends Controller
{
    public function __construct(private ThingDoer $thingDoer)
    {
    }

    /**
     * Return a view
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        // Call $this-&gt;thingDoer...
        return view(&#x27;foo&#x27;);
    }
}
</code></pre><p>We can&#x27;t call <code>$this-&gt;thingDoer()</code> because <code>$this</code> refers to the instance of <code>FooController</code>, and so we&#x27;re referring to a non-existing method of <code>FooController</code> called <code>thingDoer</code> rather than the property <code>$this-&gt;thingDoer</code>. There are a couple of ways to do it. You can call <code>__invoke()</code> explicitly, which isn&#x27;t very elegant:</p><pre><code class="language-php">&lt;?php

final class FooController extends Controller
{
    ...
    /**
     * Return a view
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        $this-&gt;thingDoer-&gt;__invoke();
        return view(&#x27;foo&#x27;);
    }
}
</code></pre><p>Or you can use <code>call_user_func()</code>:</p><pre><code class="language-php">&lt;?php

final class FooController extends Controller
{
    ...
    /**
     * Return a view
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        call_user_func($this-&gt;thingDoer);
        return view(&#x27;foo&#x27;);
    }
}
</code></pre><p>Or, my personal favourite approach:</p><pre><code class="language-php">&lt;?php

final class FooController extends Controller
{
    ...
    /**
     * Return a view
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        ($this-&gt;thingDoer)();
        return view(&#x27;foo&#x27;);
    }
}
</code></pre><p>In the context of Laravel controllers, you also have the option to use method injection:</p><pre><code class="language-php">&lt;?php

final class FooController extends Controller
{
    ...
    /**
     * Return a view
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke(ThingDoer $thingDoer)
    {
        $thingDoer();
        return view(&#x27;foo&#x27;);
    }
}
</code></pre><h2>Summary</h2><p>Using invokable classes for any part of your application that does one thing only, and could potentially be reused, makes a lot of sense. It allows for more elegant code, giving you the advantages of functional programming without losing the benefits of OOP, and allows you to break your application down into a selection of easily reusable parts. While I&#x27;ve not been in a position to try it before, I also suspect that it makes decorating components simpler, to the point that certain tasks like logging and caching can be done with a single closure or invokable. Next time you write a class to do something, give serious thought to the idea of whether it should be an invokable - the answer may be &quot;yes&quot; more often than you think, and it&#x27;ll often help make your code simpler and more reusable.</p>]]></content>
    </entry>
</feed>