<?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>2024-05-27T14:52:15.434Z</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 2024</rights>
    <contributor>
        <name>Matthew Daly</name>
        <email>matthew@matthewdaly.co.uk</email>
        <uri>https://matthewdaly.co.uk</uri>
    </contributor>
    <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>
    <entry>
        <title type="html"><![CDATA[The ORM Delusion]]></title>
        <id>https://matthewdaly.co.uk/blog/2022/06/05/the-orm-delusion/</id>
        <link href="https://matthewdaly.co.uk/blog/2022/06/05/the-orm-delusion/"/>
        <updated>2022-06-05T18:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>I&#x27;ve used some low-level database interfaces like PDO, and the database interfaces from several frameworks, including Codeigniter, Zend 1, Django, and Laravel, and I&#x27;ve been in the web development industry for over a decade at this point, so I&#x27;ve had a reasonable amount of experience working with various database interfaces. Based on this experience, I agree wholly with <a href="https://twitter.com/erikaheidi/status/1510347907819524105?s=20&amp;t=0IjKFyO3O-EctVq43hRkVw">this tweet</a> about the advantages of using an ORM on your project. I routinely use an ORM for the overwhelming majority of projects I work on and rarely need to drop down to writing raw SQL. Unfortunately, there seems to be an <em>awful</em> lot of misinformation and misconceptions about the advantages and disadvantages of choosing to use an ORM, and when to do so.</p><p>A lot of people seem to think that using an ORM inherently makes your application perform badly. However, this just isn&#x27;t true, <em>as long as you&#x27;re using the ORM the right way</em>. Using an ORM not only allows you to solve certain classes of performance problems more easily than by writing SQL statements, but they generally make it easier to reason about how your application works. However, there are some things you need to bear in mind when using one, to prevent you from introducing potential performance problems. In this post, I&#x27;ll give you the reasons why you should consider using an ORM on your projects, at least by default, and warn you about some of the things that can cause trouble when using one.</p><div title="Fair warning"><p>If you&#x27;re going to patronize me, or other commenters, by mansplaining <a href="https://www.culttt.com/2014/06/18/whats-difference-active-record-data-mapper">ActiveRecord vs DataMapper</a>, you can get in the damned sea. I know the difference and I&#x27;ve chosen to use ActiveRecord. I&#x27;m categorically not interested in rehashing that argument, let alone being condescended to, and I will delete <strong>any comments</strong> that I think do either. If you <em>do</em> have <em>legitimate, specific gripes</em> about Eloquent, or any other implementation of ActiveRecord, or indeed ORMs in general, and can moan about them without being unpleasant to other people, I&#x27;m happy to accept those comments. No tool is perfect, and there are always some cases where it will cause problems, but I will not tolerate anyone being disrespectful. Using Laravel, Eloquent, or any ActiveRecord implementation, does not make someone Nooby McNoobface, and if you&#x27;re going to claim it does, you&#x27;re not welcome here.</p></div><p>Please note, that while I&#x27;m referring to Eloquent throughout this post, the overwhelming majority of what I&#x27;m talking about is also applicable to other ORMs, particularly other Active Record-style ORMs such as the Django ORM. I&#x27;m using Eloquent as the primary example here because it&#x27;s the one I&#x27;ve used most often in the last few years.</p><h2>Reasons to use an ORM</h2><p>Below I&#x27;ve listed the reasons I can think of for using an ORM. I don&#x27;t think this is necessarily an exhaustive list, and others may be able to think of others or express these reasons more elegantly than I can. If you can think of other good reasons, feel free to add them to the comments.</p><h3>Resolving N+1 queries</h3><p>In my experience, N+1 queries are <em>far and away</em> the most common performance problem I&#x27;ve encountered when dealing with legacy applications that don&#x27;t use an ORM. They&#x27;re typically somewhat less obvious than a single slow query would be when profiling your code because the problem comes from multiple small queries, rather than from single large ones, but they can have a crippling effect on the performance of your application.</p><p>It <em>is</em> possible to use JOINs to pull in another table and get the related data in a single query, but that <em>really</em> starts to get hairy if you have to pull in multiple levels of tables, and it can be <em>very</em> difficult to write a query that does so while remaining easy to understand.</p><p>Fortunately, most ORMs have simple methods for efficiently fetching related data via eager loading. For instance, Eloquent has the <code>with()</code> and <code>load()</code> methods. By making good use of these methods, you can write efficient queries that are still straightforward to understand. In addition, you can also use methods such as <code>has()</code> and <code>whereHas()</code> to query relationship existence, which is generally a lot more elegant than the underlying <code>WHERE EXISTS</code> statement.</p><p>Eloquent also carries out a degree of caching, particularly when dealing with relations. This can sometimes eliminate queries that would be made by a more naive ORM, but in the event you <em>do</em> need it, you can call the <code>refresh()</code> method on the model to ensure it&#x27;s up to date.</p><h3>Type safety</h3><p>Using an ORM, as opposed to a query builder or writing raw SQL, offers significant advantages in terms of the type safety of the code base.</p><p>For instance, say you have the below method in a Laravel project which returns an array of data from a query:</p><pre><code class="language-php">&lt;?php

use DB;

final class ProductRepository {
    // Rest of class...

    public function getFirstProductBelow(float $price): array
    {
        return DB::table(&#x27;products&#x27;)-&gt;where(&#x27;price&#x27;, &#x27;&lt;&#x27;, $price)-&gt;first();
    }
}
</code></pre><p>While having a return type at all is better than none, it isn&#x27;t very useful for static analysis tools. Just telling Psalm that the response is an array doesn&#x27;t tell it what fields to expect in that array.</p><p>You <em>can</em> use annotations to specify a more meaningful response...</p><pre><code class="language-php">&lt;?php

use DB;

final class ProductRepository {
    // Rest of class...

    /*
     * @psalm-return array{id: int, name: string, price: float}
     */
    public function getFirstProductBelow(float $price): array
    {
        return DB::table(&#x27;products&#x27;)-&gt;where(&#x27;price&#x27;, &#x27;&lt;&#x27;, $price)-&gt;first();
    }
}
</code></pre><p>And that <em>would</em> tell Psalm that it returns an array with the denoted keys. However, it&#x27;s not the best solution:</p><ul><li>You&#x27;d need to either duplicate that <code>@psalm-return</code> docblock to any other method that returns a list of those items, in which case adding a new field becomes problematic, or you&#x27;d have to use a predefined template annotation</li><li>Those annotations need to be maintained, and if they got out of sync with your database structure, Psalm might get confused</li><li>The native PHP return type can only validate that the response is an array. The actual response could <em>theoretically</em> look very different and short of adding some potentially long-winded <code>assert()</code> calls about the shape of the array, we can&#x27;t validate that the right values exist.</li></ul><p>But suppose we instead use Eloquent. Our method might then look like this:</p><pre><code class="language-php">&lt;?php

use App\Models\Product;

final class ProductRepository {
    // Rest of class...

    public function getFirstProductBelow(float $price): Product
    {
        return Product::where(&#x27;price&#x27;, &#x27;&lt;&#x27;, $price)-&gt;first();
    }
}
</code></pre><p>We now know with absolute certainty that the response from this method is an instance of <code>App\Models\Product</code> because we&#x27;ve been able to declare a return type, and if it wasn&#x27;t, the method would throw an exception.</p><p>By itself, that doesn&#x27;t tell us what fields to expect on an instance of <code>App\Models\Product</code>, but Laravel IDE Helper can easily generate suitable <code>@property</code> annotations for us, based on the current database structure. If we run the following command:</p><pre><code class="language-bash">$ php artisan ide-helper:models -W
</code></pre><p>Then our model might end up looking something like this:</p><pre><code class="language-php">&lt;?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

/*
 * @property integer $id
 * @property string $name
 * @property float price
 */
final class Product extends Model
{
    // class body here
}
</code></pre><p>And that gives Psalm a single, canonical description of the structure of this class. Even if you couldn&#x27;t use Laravel IDE Helper for some reason, it&#x27;s not exactly onerous to manually define the properties on a given model in one place - it&#x27;s the work of a few minutes if you do it at the same time you define your models and migrations.</p><p>For even better type safety on your models, you can add the <code>@psalm-seal-properties</code> annotation, which will ensure that if you try to use an undocumented property on the model, Psalm will flag it as an issue. And having comprehensive type information isn&#x27;t just a matter of finding type issues, it also affects how good your autocompletion will be - with better type hints, you&#x27;ll have more effective and accurate completion options.</p><h3>Refraining from reinventing the wheel, probably badly</h3><p>I maintain a large legacy Zend 1 application where the original developer decided they didn&#x27;t want to use an existing ORM. Instead, they wrote their own model classes which looked something like this:</p><pre><code class="language-php" metastring="title=application/models/Page.php" title="application/models/Page.php">&lt;?php

class Application_Model_Page
{
    protected $id;
    protected $name;
    protected $price;

    public function __construct()
    {
        $this-&gt;id = null;
        $this-&gt;name = null;
        $this-&gt;price = null;
    }

    public function getId()
    {
        return $this-&gt;id;
    }

    public function setId($val)
    {
        $this-&gt;id = $val;
        return $this;
    }

    public function getName()
    {
        return $this-&gt;name;
    }

    public function setName($val)
    {
        $this-&gt;name = $val;
        return $this;
    }

    public function getPrice()
    {
        return $this-&gt;price;
    }

    public function setPrice($val)
    {
        $this-&gt;price = $val;
        return $this;
    }

    public function toArray()
    {
        return [
            &#x27;id&#x27; =&gt; $this-&gt;id,
            &#x27;name&#x27; =&gt; $this-&gt;name,
            &#x27;price&#x27; =&gt; $this-&gt;price,
        ];
    }

    public function populate(array $data)
    {
        $this-&gt;id = $data[&#x27;id&#x27;];
        $this-&gt;name = $data[&#x27;name&#x27;];
        $this-&gt;price = $data[&#x27;price&#x27;];
        return $this;
    }

    public function save()
    {
        $db = Zend_Registry::get(&#x27;db&#x27;);
        $data = [
            &#x27;name&#x27; =&gt; $this-&gt;name,
            &#x27;price&#x27; =&gt; $this-&gt;price,
        ];
        $db-&gt;update(&#x27;products&#x27;, $data, &#x27;id=&#x27; . $this-&gt;id);
    }

    public function find($id)
    {
        $db = Zend_Registry::get(&#x27;db&#x27;);
        $result = $db-&gt;fetchRow(&#x27;SELECT * FROM products WHERE id = &#x27; . $id);
        return $this-&gt;populate($result);
    }
}
</code></pre><p>Honestly, there are so many issues with this it&#x27;s hard to know where to start:</p><ul><li>You can&#x27;t define generic implementations of the various methods because they&#x27;re dependent on a specific structure, so you have to define those methods from scratch for every single model</li><li>The <code>find()</code> method requires that you first create an instance of the object, then call that method to return another instance, eg <code>(new Application_Model_Page())-&gt;find(1)</code>, which is extremely cumbersome</li><li>And if you want to populate multiple instances, you have to do so manually like this:</li></ul><pre><code class="language-php">&lt;?php
$response = [];
foreach ($result as $row) {
    $response[] = (new Application_Model_Page())-&gt;populate($row);
}
return $response;
</code></pre><p>We&#x27;re in the process of migrating off these legacy models to Eloquent, with the intent of eventually migrating the whole application to Laravel, and the contrast between using the two model types could not be greater. The Eloquent models are easy to maintain, easy to work with, highly performant, and require far less boilerplate code when implementing functionality.</p><p>Martin Fowler covered this issue pretty well in <a href="https://martinfowler.com/bliki/OrmHate.html">ORM Hate</a>. To quote:</p><blockquote><p>Listening to some critics, you&#x27;d think that the best thing for a modern software developer to do is roll their own ORM. The implication is that tools like Hibernate and Active Record have just become bloatware, so you should come up with your own lightweight alternative. Now I&#x27;ve spent many an hour griping at bloatware, but ORMs really don&#x27;t fit the bill - and I say this with bitter memory. For much of the 90&#x27;s I saw project after project deal with the object/relational mapping problem by writing their own framework - it was always much tougher than people imagined. Usually you&#x27;d get enough early success to commit deeply to the framework and only after a while did you realize you were in a quagmire - this is where I sympathize greatly with Ted Neward&#x27;s famous quote that object-relational mapping is the Vietnam of Computer Science.</p><p>The widely available open source ORMs (such as iBatis, Hibernate, and Active Record) did a great deal to remove this problem. Certainly they are not trivial tools to use, as I said the underlying problem is hard, but you don&#x27;t have to deal with the full experience of writing that stuff (the horror, the horror). However much you may hate using an ORM, take my word for it - you&#x27;re better off.</p></blockquote><p>And it&#x27;s worth bearing in mind that those words were written a decade ago. We now have over ten years&#x27; more experience finding potential problems with ORMs and finding effective solutions for those problems, and Eloquent has benefited from those changes, as well as improvements in the PHP language. Many issues you might have with an ORM ten years ago may simply no longer be worth worrying about.</p><h3>Consistency</h3><p>Eloquent&#x27;s scopes in particular have been invaluable for me in ensuring consistency. On the Zend 1 project mentioned above, there are still some issues with poor, inconsistent database design that I haven&#x27;t yet been able to get around to resolving. One of these is that different content types are stored in different tables with different field names, but we need to be able to make them work consistently when resolving whether a given item is in date, even though the fields have different names.</p><p>If we had to use the query builder or write SQL, we&#x27;d be stuck writing the same chunk of the query over and over each time we needed to get the in-date items of each type, and it would be all too easy to mess it up and use the wrong field name when doing a union of different content types. But if we define a local scope on each model called <code>scopeIsInDate()</code> with an implementation specific to that model, we can then easily reuse that and ensure consistency.</p><p>We also have a use case where, based on the value of one field, or whether the ID of the model is in a hard-coded list, it needs to be treated as a different object. By using a global scope, we can create two models that extend a common base, and apply one scope to one model, and another to the other model. That way, even though we have only one database table, we can effectively treat it as two separate ones when using the models. Yes, a better database structure would resolve that, but this is a big legacy application and there&#x27;s already lots to do to clean it up, so we can&#x27;t justify it any time soon.</p><h3>Reduces context switching</h3><p>Going from writing PHP to writing SQL and back is <em>hard</em> on the grey matter. It will slow you down because:</p><ul><li>You have to go from one mental model of how to construct a correct statement in terms of grammar and punctuation to another</li><li>You&#x27;re mixing two or more languages up in the same file, which isn&#x27;t great - your editor or IDE may not be able to easily apply proper syntax highlighting to the SQL if it&#x27;s just a string. This may make it harder to spot syntax errors</li></ul><p>If instead you only have to think about PHP&#x27;s rules while writing a query, the mental load is significantly lower and your editor or IDE can help you out a lot more.</p><p>Now, it has to be said, sometimes there <em>are</em> queries where it&#x27;s easier to write it out initially in SQL using something like MySQL Workbench, but I&#x27;d still advocate taking the time to go back and translate those queries into Eloquent if possible, or to the query builder if that&#x27;s more practical. I consider raw SQL in a PHP file to be technical debt because, in addition to the other points above:</p><ul><li>It makes it all too easy to accidentally leave an SQL injection vulnerability in your code</li><li>You can&#x27;t extract a part of the query to a scope for reuse, or make use of existing scopes to handle a part of the query</li></ul><p>As always, sometimes if you&#x27;re in a rush you can justify adding technical debt on a temporary basis, but that should be the exception, not the rule, and has to be justified.</p><h2>Things to bear in mind when using an ORM</h2><p>With the reasons I&#x27;d recommend using an ORM out the way, here are some of the gotchas you should be aware of when making a decision about using one:</p><h3>The ORM is an abstraction for SQL, not a replacement</h3><p>Honestly, the overwhelming majority of performance issues developers have with ORM&#x27;s boil down to this. Again with a quote from Martin Fowler:</p><blockquote><p>I&#x27;ve often felt that much of the frustration with ORMs is about inflated expectations. Many people treat the relational database &quot;like a crazy aunt who&#x27;s shut up in an attic and whom nobody wants to talk about&quot;</p></blockquote><p>If a developer treats an ORM like a black box and just writes queries without thinking about the SQL it generates, it&#x27;s no surprise whatsoever if the generated queries don&#x27;t perform well. It&#x27;s still running queries under the bonnet, it&#x27;s just that some of it is implicit. For instance, take this (relatively simple) example of an Eloquent query:</p><pre><code class="language-php">Post::join(&#x27;user&#x27;, &#x27;posts.user_id&#x27;, &#x27;=&#x27;, &#x27;users.id&#x27;)-&gt;get();
</code></pre><p>If you use something like Clockwork to profile this query, the end result will probably look something like this:</p><pre><code class="language-sql">SELECT * FROM posts
INNER JOIN users ON posts.user_id = users.id
</code></pre><p>And, to be fair, there <em>are</em> a few potential issues with this query.</p><ul><li>If you&#x27;re retrieving all the fields from the <code>posts</code> and <code>users</code> tables, then that could easily include fields that you don&#x27;t explicitly need</li><li>Depending on the use case, returning an arbitrary number of database rows can be potentially problematic, performance-wise, and it may be better to paginate them</li><li>If you haven&#x27;t set an appropriate foreign key on <code>posts.user_id</code>, the join could perform badly</li></ul><p>However, these issues really aren&#x27;t inherent to using an ORM, but are to do with it being used naively. Assuming we do want to paginate these results, and the only field on <code>users</code> that we need is the name, we could achieve what we want by rewriting this query as follows:</p><pre><code class="language-php">Post::join(&#x27;user&#x27;, &#x27;posts.user_id&#x27;, &#x27;=&#x27;, &#x27;users.id&#x27;)-&gt;select(&#x27;posts.*&#x27;, &#x27;users.name&#x27;)-&gt;paginate(20);
</code></pre><div><p>Yes, <a href="https://laravel.com/docs/9.x/pagination#cursor-pagination">cursor pagination</a> is a thing and will perform better than offset-based pagination in most cases, but I&#x27;m deliberately keeping this example as simple as possible.</p></div><p>As for the third issue, that&#x27;s easy enough - just ensure that you&#x27;re setting an appropriate foreign key.</p><h3>An ORM isn&#x27;t training wheels, it&#x27;s a power tool</h3><p>This is nearly the same issue as that above, but it&#x27;s important enough to deserve being mentioned separately.</p><p>Using an ORM effectively requires knowledge of your relational database. To write efficient queries with it, you need the same knowledge that you do to write the underlying query in SQL, AND knowledge of the ORM itself. If you start using it without learning to use a relational database (or let a junior dev who hasn&#x27;t learned SQL properly), or don&#x27;t profile your queries, you&#x27;re going to run into problems.</p><p>I&#x27;ve often heard people suggest that using an ORM means your SQL skills atrophy. Quite frankly, I find that utterly laughable. I make a point of avoiding writing raw SQL when I can use an ORM, and I still often find myself having to write raw SQL, particularly if I&#x27;m prototyping a complex query. It does make it unnecessary to write out simple queries in SQL, but I&#x27;m not going to benefit in the slightest at this point in my career by writing something like <code>SELECT * FROM posts</code> over and over if I can call <code>Post::all()</code> instead.</p><h3>Hydration can become a bottleneck for large datasets</h3><p>It has to be said, there <em>is</em> inevitably some overhead from instantiating an ORM model, which can be quite a complex class, compared to instantiating an array of data, and if you have to work with a response that contains a large number of rows, it may be better to return arrays than model instances.</p><p>Case in point, the Zend 1 project I maintain has a number of reports which the client downloads once a week. This includes a report of all the current users in the system, and although users who leave are cleaned out of the system automatically, there&#x27;s typically around thirty thousand rows returned from this query. That&#x27;s big enough that the time taken to instantiate a model instance for each row can become significant, and you don&#x27;t need a model instance if all you&#x27;re going to do is dump the data out to a CSV file, so the additional overhead of instantiating the ORM models may not be worth it. So in those circumstances, you&#x27;re better off using the query builder and returning an array - it&#x27;ll be quicker and use less memory.</p><p>Fortunately, it&#x27;s easy to convert an Eloquent query to a query builder one by calling the <code>getQuery()</code> method. That way you can write your query using Eloquent as normal, then convert it to a query builder instance, and return the data as an array.</p><h3>You can write nearly any query with an ORM, but it may require more effort</h3><p>Just because there isn&#x27;t a method for a particular SQL statement, or the methods it does have don&#x27;t have the options you need, doesn&#x27;t mean you need to write it the whole thing as a raw query. There&#x27;s still the various raw methods:</p><ul><li><code>selectRaw</code></li><li><code>whereRaw</code>/<code>orWhereRaw</code></li><li><code>havingRaw</code>/<code>orHavingRaw</code></li><li><code>orderByRaw</code></li><li><code>groupByRaw</code></li></ul><p>By making appropriate use of these methods, you can write only those parts of the query that absolutely need to be raw, without losing the advantages of using an ORM. For instance, if you need to use <code>CASE ... WHEN</code> statement to return a true or false value for if an entry is in date, or use <code>GROUP_CONCAT()</code> to concatenate some names from a related field into one field, you can easily do so using something like <code>-&gt;selectRaw(&#x27;CASE WHEN expiry_date &lt; NOW() THEN &#x27;true&#x27; ELSE &#x27;false&#x27;, GROUP_CONCAT(name)&#x27;)</code>.</p><p>Some more advanced parts of SQL can be harder to write using an ORM. For instance, take this query:</p><pre><code class="language-sql">WITH RECURSIVE children(id, name, parent_id, depth) AS
  (SELECT teams.*,
          0 AS depth
   FROM `teams`
   WHERE id = 1
   UNION ALL SELECT teams.*,
                    children.depth + 1
   FROM teams
   INNER JOIN children ON children.parent_id = teams.id)
SELECT *
FROM children
</code></pre><p>The <code>WITH RECURSIVE</code> CTE is a relatively new feature in SQL and not every implementation supports it. In addition, it&#x27;s only useful in certain, quite specific circumstances. As such, support for it is limited in most ORMs, and this is one use case where it <em>might</em> not be worth the bother of rewriting the query to use an ORM. However, it&#x27;s not impossible. The <a href="https://github.com/staudenmeir/laravel-cte">Laravel CTE</a> package extends Eloquent to add support for recursive queries, and even if you can&#x27;t use that for some reason, it might be worth rewriting the inner query alone in Eloquent, then using <code>toSql()</code> to get the SQL from it and insert that into the outer query, something like this:</p><pre><code class="language-php">$teams = Team::where(&#x27;id&#x27;, 1)
    -&gt;unionAll(Team::join(&#x27;children&#x27;, &#x27;children.parent_id&#x27;, &#x27;=&#x27;, &#x27;teams.id&#x27;)
    -&gt;selectRaw(&#x27;teams.*, children.depth + 1&#x27;)
    -&gt;toSql();
$query = &quot;WITH RECURSIVE children(id, name, parent_id, depth) AS ($teams) SELECT * FROM children&quot;;
</code></pre><p>It&#x27;s not perfect, but this at least means some of the query is expressed using Eloquent, making it easier to maintain and debug.</p><h3>You need to profile your queries to ensure they&#x27;re efficient</h3><p>Just because a query isn&#x27;t written manually doesn&#x27;t mean it&#x27;s not inefficient, and sometimes there can be hidden queries you&#x27;re not aware of. Third-party packages can be a source of this, and <a href="/blog/2020/03/11/caching-the-laravel-user-provider-with-a-decorator/">the authentication system can trigger some less-than-obvious queries which can be cached</a>. For this reason, it&#x27;s a really good idea to profile your pages to make sure they&#x27;re performing as expected.</p><p>I favour <a href="https://underground.works/clockwork/">Clockwork</a> as my profiling tool of choice, but <a href="https://laravel.com/docs/9.x/telescope">Laravel Telescope</a> and <a href="https://github.com/barryvdh/laravel-debugbar">Laravel Debugbar</a> are also solid options for this.</p><h3>It&#x27;s unlikely you can swap databases without rewriting at least some queries</h3><p>One of the advantages I&#x27;ve heard claimed for ORMs in the past is being able to migrate from, say, MySQL to PostgreSQL without making any changes to the code base. Honestly, I don&#x27;t think this one is very likely unless your queries are <em>very</em> simple. Any call to any of the <code>*raw()</code> would need to be manually checked and migrated, and I don&#x27;t think any sizeable application would be able to get away without having any of these. It may be you can find a third-party package to add custom methods to support these features directly, or can write your own, but it may not be worth the bother for only a handful of uses of that feature.</p><p>It can be convenient to be able to use an in-memory SQLite database for running your tests locally, but it likely won&#x27;t be practical if you depend on any database-specific functionality, or for all the tables in a large application. As such I only tend to do this when working on packages, where there&#x27;s only a handful of tables to deal with.</p><h2>Summary</h2><p>Hopefully this article has helped dispel some of the appalling myths, misconceptions, and general confusion that seem to be widespread around using an ORM. If there&#x27;s one thing I hope you take away from this article it&#x27;s that the ORM isn&#x27;t a black box, but a layer of abstraction over your relational database, and if you don&#x27;t bear that in mind, it&#x27;s no surprise if you go on to experience performance problems. When used properly, an ORM is an extremely useful tool that is applicable to nearly every query you&#x27;re likely to write, and it will help you make your code more readable, maintainable, performant, type-safe and secure.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dynamic image handling with Glide and GraphQL]]></title>
        <id>https://matthewdaly.co.uk/blog/2021/08/21/dynamic-image-handling-with-glide-and-graphql/</id>
        <link href="https://matthewdaly.co.uk/blog/2021/08/21/dynamic-image-handling-with-glide-and-graphql/"/>
        <updated>2021-08-21T16:20:00.000Z</updated>
        <content type="html"><![CDATA[<p>I&#x27;ve used <a href="https://glide.thephpleague.com/">Glide</a> on several PHP projects in the past. It&#x27;s a great package that makes it really easy to dynamically generate images on the fly. For instance, if you need a particular image at both a thumbnail size and a full-screen size, it means you have the flexibility to request it at the correct size for any one part of the page. This can potentially save bandwidth since you never have to request a larger image than you technically need and scale it down with HTML attributes or CSS, nor do you have to take steps to generate thumbnails separately before they&#x27;re needed. Frontend developers can adjust their code to request exactly the version they need at any one time, and can even apply certain effects dynamically.</p><p>However, by default it&#x27;s a bit too open. A malicious user could request an image at an excessive size as part of a denial of service attack. For that reason, it&#x27;s considered good practice to set a maximum image size, and sign all requests so that you can be sure they&#x27;re authorized by your application. This works fine if your images are being requested somewhere you can sign them easily, such as in a Blade template. However, doing so in the context of a React or Vue application can potentially be much harder because they&#x27;re working on the front end and so can&#x27;t sign requests that are made dynamically in the same way, at least not without you exposing your application&#x27;s key to the front end, which would be <em>really</em> risky. An API endpoint can return URLs for pre-signed specific versions of the image, but that&#x27;s not as flexible as being able to adjust what you get back via query parameters on the fly.</p><p>I&#x27;m currently working on an application that uses GraphQL for the API, and for that I wanted to use Glide to enable <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">responsive images</a> and minimise the size of the payload. Having recently rewritten this blog in Gatsby, I&#x27;d had some exposure to the Sharp plugin, which allows you to query for an image at specific dimensions. It struck me that I could probably do something similar with GraphQL in the context of a Laravel application. Since the GraphQL queries that would return the image URLs and other data were being handled server side, they could in theory accept parameters for the required images, validate that the specified values were acceptable, and return a secure, signed URL for that image for consumption by the front end. Since the frontend was having to make an AJAX request to fetch the items to show anyway, it could request the URLs as part of the same AJAX request as the rest of the items on a page, then render the images along with the rest of the content. Here I&#x27;ll demonstrate how to do this.</p><p>The first thing to do is implement a controller for returning images via Glide. This will differ between frameworks so you&#x27;d need to check the Glide documentation, but a typical Laravel version would look something like this:</p><pre><code class="language-php" metastring="title=app/Http/Controllers/GlideController.php" title="app/Http/Controllers/GlideController.php">&lt;?php

namespace App\Http\Controllers;

use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Http\Request;
use League\Glide\Filesystem\FileNotFoundException;
use League\Glide\Responses\LaravelResponseFactory;
use League\Glide\ServerFactory;
use League\Glide\Signatures\SignatureException;
use League\Glide\Signatures\SignatureFactory;
use Symfony\Component\HttpFoundation\StreamedResponse;

final class GlideController extends Controller
{
    /**
     * Storage
     *
     * @var Filesystem
     */
    private $filesystem;

    public function __construct(Filesystem $filesystem)
    {
        $this-&gt;filesystem = $filesystem;
    }

    public function __invoke(Request $request, string $path): StreamedResponse
    {
        try {
            SignatureFactory::create((string)env(&#x27;APP_KEY&#x27;))-&gt;validateRequest(&quot;/images/&quot; . $path, $request-&gt;all());
            $server = ServerFactory::create([
                &#x27;response&#x27; =&gt; new LaravelResponseFactory($request),
                &#x27;source&#x27; =&gt; $this-&gt;filesystem-&gt;getDriver(),
                &#x27;cache&#x27; =&gt; $this-&gt;filesystem-&gt;getDriver(),
                &#x27;cache_path_prefix&#x27; =&gt; &#x27;.cache&#x27;,
                &#x27;base_url&#x27; =&gt; &#x27;&#x27;,
                &#x27;max_image_size&#x27; =&gt; 1000 * 1000,
            ]);
            return $server-&gt;getImageResponse(&quot;images/&quot; . $path, $request-&gt;all());
        } catch (SignatureException) {
            abort(403);
        } catch (FileNotFoundException) {
            abort(404);
        }
    }
}
</code></pre><p>Note that I&#x27;m using a <a href="https://laravel.com/docs/8.x/controllers#single-action-controllers">single action controller</a> here. I&#x27;ve found myself gravitating more and more towards these for certain use cases, and <a href="https://driesvints.com/blog/the-beauty-of-single-action-controllers/">I&#x27;m not the only one</a>. For me, the biggest benefit of these is probably more concise naming - if a controller does one thing and one thing only, and the class name adequately describes that, you end up naming it something generic, like <code>call()</code>. By making the controller a single callable, you don&#x27;t have to make that decision since it&#x27;s taken out of your hands (it must be <code>__invoke()</code>). I&#x27;m also a big fan of callable classes in general - they&#x27;re essentially closures on steroids since you can still pass dependencies to the constructor.</p><p>The <code>SignatureFactory</code> line is what handles validating the signature. It&#x27;s based on the app key, and checks that the path and all its parameters are correctly signed. If the signature isn&#x27;t valid, it will throw an exception, thus protecting the endpoint from requests that weren&#x27;t already approved. We also specify a cache location, and a maximum image size to help prevent mass-resize attacks.</p><p>You can then register this controller in the usual way:</p><pre><code class="language-php" metastring="title=routes/web.php" title="routes/web.php">    Route::get(&#x27;/images/{path}&#x27;, GlideController::class)-&gt;where(&#x27;path&#x27;, &#x27;.*&#x27;)-&gt;name(&#x27;glide&#x27;);
</code></pre><p>If the images aren&#x27;t going to be accessible to users who aren&#x27;t logged in, it makes sense to apply whatever authentication middleware you&#x27;re using to this route as well.</p><p>Now, depending on which GraphQL package you&#x27;re using, defining the schema may be different. In this case, I&#x27;m using <a href="https://lighthouse-php.com/">Lighthouse</a> and the schema definition for an Eloquent model with an image would look something like this:</p><pre><code class="language-graphql" metastring="title=graphql/schema.graphql" title="graphql/schema.graphql">enum ImageFormat {
    jpg
    pjpg
    webp
}

type Image {
    id: ID!
    caption: String!
    dynamicImage(
        width: Int @rules(apply: [&quot;numeric&quot;, &quot;max:1000&quot;])
        height: Int @rules(apply: [&quot;numeric&quot;, &quot;max:1000&quot;])
        quality: Int @rules(apply: [&quot;numeric&quot;, &quot;max:100&quot;])
        format: ImageFormat
    ): String @method
}
</code></pre><p>Here we&#x27;re specifying what parameters the <code>dynamicImage()</code> field accepts, as well as applying some of Laravel&#x27;s validation rules to the field to ensure it remains within acceptable ranges. We also use an enum to specify the supported image formats - these are actually limited to the options Glide provdes, but by specifying this as an enum, GraphQL tooling like GraphiQL can provide autocompletion for this parameter for a better developer experience when constructing queries. Note that we also use the <code>@method</code> directive to tell Lighthouse that this field maps to a method, not a property. If the method name differs from the field name, you would also need to specify that method name, eg <code>@method(name: &quot;myMethod&quot;)</code>.</p><p>Now, assuming your image was stored on the filesystem and the appropriate model field was called <code>image_path</code>, the method to retrieve the image URL on the model would look something like this:</p><pre><code class="language-php" metastring="title=app/Models/Item.php" title="app/Models/Item.php">use Illuminate\Support\Facades\URL;
use League\Glide\Urls\UrlBuilderFactory;

// Define model class...

    public function dynamicImage(int $width = null, int $height = null, int $quality = null, string $format = null): ?string
    {
        $builder = UrlBuilderFactory::create(&#x27;/images/&#x27;, (string)env(&#x27;APP_KEY&#x27;));
        return URL::to($builder-&gt;getUrl($this-&gt;image_path, [
            &#x27;w&#x27; =&gt; $width,
            &#x27;h&#x27; =&gt; $height,
            &#x27;q&#x27; =&gt; $quality,
            &#x27;fm&#x27; =&gt; $format,
        ]));
    }
</code></pre><p>Note that the parameters on the model must be specified in the same order as they are defined in the GraphQL schema for them to be lined up correctly, and must have the same names. I&#x27;ve only added the most obviously useful parameters here, namely height, width, quality and format, but if you need them there&#x27;s nothing stopping you from adding further parameters - just don&#x27;t forget to update the GraphQL schema to include them too.</p><p>We can then write GraphQL queries to call <code>dynamicImage()</code> with whatever parameters we wish to pass through, and will get back an appropriate URL in response. For instance, consider this query:</p><pre><code class="language-graphql" metastring="{6}">query {
  items {
    data {
      id
      caption
      dynamicImage(width: 400, height:400, quality: 100, format: webp)
    }
  }
}
</code></pre><p>Here we assume a query has been defined called <code>items</code> which returns all instances of the <code>Item</code> GraphQL type. This would return, for each instance of the <code>Item</code> model, the ID, caption and the URL for an image of 100% quality, 400x400 pixels, in WebP format. Please also note that none of these arguments to <code>dynamicImage()</code> are required - if you leave one out, Glide will use the default value.</p><p>By calling <code>dynamicImage()</code> separately with different aliases, we can even fetch multiple versions of the image. In this example, we fetch it at two different sizes:</p><pre><code class="language-graphql" metastring="{6-7}">query {
  items {
    data {
      id
      caption
      large_image: dynamicImage(width: 400, height:400, quality: 100, format: webp)
      small_image: dynamicImage(width: 200, height:200, quality: 100, format: webp)
    }
  }
}
</code></pre><p>Then, when rendering a component, you could use the <code>&lt;picture&gt;</code> and <code>&lt;source&gt;</code> elements to show different versions based on media queries, as in this example of a simple React component used to render individual instances of <code>Item</code>:</p><pre><code class="language-typescript" metastring="title=resources/js/components/Card.tsx {3-5}" title="resources/js/components/Card.tsx">const Card = (item) =&gt; (
  &lt;picture&gt;
    &lt;source media=&quot;{max-width: 768px}&quot; srcSet={item.small_image} /&gt;
    &lt;source media=&quot;{min-width: 769px}&quot; srcSet={item.large_image} /&gt;
    &lt;img src={item.small_image} alt={item.caption} /&gt;
  &lt;/picture&gt;
)
</code></pre><p>This enables us to serve responsive images that are appropriately sized for the current screen resolution. On mobile devices, which may not always have a connection as fast as a desktop or laptop, it also means we aren&#x27;t wasting bandwidth downloading images which are larger than necessary.</p><p>Along similar lines, you could fetch both WebP and JPEG versions of an image:</p><pre><code class="language-graphql" metastring="{6-7}">query {
  items {
    data {
      id
      caption
      jpeg_image: dynamicImage(width: 400, height: 400, quality: 100, format: jpeg)
      webp_image: dynamicImage(width: 400, height: 400, quality: 100, format: webp)
    }
  }
}
</code></pre><p>Then, we can use the WebP version of the image if the web browser supports it, falling back to JPEG if it doesn&#x27;t, by using the <code>&lt;picture&gt;</code> and <code>&lt;source&gt;</code> elements again in our React component:</p><pre><code class="language-typescript" metastring="title=resources/js/components/Card.tsx {3-4}" title="resources/js/components/Card.tsx">const Card = (item) =&gt; (
  &lt;picture&gt;
    &lt;source type=&quot;image/webp&quot; srcSet={item.webp_image} /&gt;
    &lt;img src={item.jpeg_image} alt={item.caption} /&gt;
  &lt;/picture&gt;
)
</code></pre><p>By doing this we aren&#x27;t forced to work with the lowest common denominator in terms of image formats. We can instead offer WebP to users whose browsers support it, without locking out users on older browsers.</p><p>This technique should be easy enough to apply to other PHP frameworks since Glide is fairly framework agnostic and there are GraphQL implementations for most frameworks. It should also be applicable in other languages - for example, while I&#x27;m not aware of a direct equivalent of Glide in Node.js, you could conceivably use <a href="https://sharp.pixelplumbing.com/">Sharp</a> as the basis of your own custom endpoint to serve up dynamic images based on query parameters, and then serve signed URLs for it via GraphQL.</p><p>Responsive images are something that&#x27;s often overlooked when trying to build a modern web app. An approach like this makes it an awful lot easier to serve appropriately-sized images on demand, without locking front-end devs into specific known dimensions that might not fit their use case.</p>]]></content>
    </entry>
</feed>