Don’t stiff clients, upgrade your stuff

Image shows a click with the text "Time to upgrade"

A client recently asked me to setup a Silverstripe site on their server. They were in the process of getting the files and database extract to me and then I would be good to go. I hadn’t used Silverstripe since 2008 but figured, why not? Setting it up on a new server shouldn’t be too much of an issue…oh boy, was I wrong!

After a while, I received the files and a database dump. Everything seemed ok although I was surprised to see an included vendor folder. I checked the composer.json file to see what I was working with and well, I was a little concerned. PHP was set to 5.6 and all but two requirements were set to dev-master and silverstripe/recipe-cms was set as 4.2.*, released sometime in 2018.

Get it working

OK, so the developers had installed Silverstripe in 2018 and never felt the need to upgrade it, not even once. So I thought, I’ll set up a dev environment and get going.
I created a Docker container with PHP5.6, MySQL 5.7, and a few extensions. I copied everything in, including the vendor folder and managed to get a half working website running. It wasn’t quite as easy as described as I needed to work out what extensions I needed and fix a couple of minor bugs, but the site was working.

I thought cool, now I can start upgrading the site. It was at this point I recalled every dependency was set to dev-master. So the first step was to set the correct version for each dependency. Well, the version as of 2018 and get a composer install to work.
I checked the installed.json inside vendor/composer and found the commit hash for each dependency. I then found the related version on GitHub and updated the composer.json. This was tedious work; however, I figured I was working towards getting a working composer.json. When done, I discovered this wasn’t going to work; the provided composer.json did not create the included vendor directory and there was too much stuff missing.

I decided to go back to basics and create a brand-new composer.json including every package listed in vendor/composer/installed.json. Eventually I got to the point where I could run composer install with no vendor directory or composer.lock file and get a working vendor directory. Awesome!

Although this worked, I couldn’t yet start upgrading as there was too much listed in my composer.json. I started checking each package to see if it was a core requirement or a dependency of something else and pruned the composer.json file down to the bare minimum. Several hours later, I again had a working composer.json file.

Upgrade it

A day in and I had a working Silverstripe site, running on PHP5.6 and MySQL 5.7. I was also confident I could clear the “vendor” directory and recreate it. As joyous as I was, I was no further along. I couldn’t put this online as I needed it to be running PHP8.0 at a minimum and MySQL8. Additionally, I was having to use composer 1.10.26 – that also had to change.

I started the upgrade process; I went step by step starting at 4.2.0 all the way up to version 4.10.0. At each release, I would trash the vendor directory and composer.lock file and see if I ended up with a working site. It was slow as I kept needing to tweak things. Every time Silverstripe added support for an updated version of PHP, I would rebuild my Docker container and test again, slowly fixing bugs and correcting dependencies as I went. As soon I was running PHP8, I switched to MySQL 8 and manually updated the database schema.

Stable & Supportable

The site is now sitting on a staging server for the client. There are a few small issues here and there that I need to fix, and I need to continue upgrading to the latest version of Silverstripe, however, for now, this client is happy.

The moral of the story – upgrade your stuff. If you are selling a website to a client, at least have the decency to upgrade it. Handing them a hot mess four years later is disgusting and the “development house” in question should be ashamed of themselves.

I’m not going to name the “development house” as I don’t know if this was a one off. I expect not but it isn’t for me say as I never dealt with them directly, I just had to pick up the mess.

Invokable Controllers

Action class usage in my Laravel Apps

For several years I have been a fan of invokable classes, typically to act as action classes for forms and to create jobs for queues etc.

Simple Forms

With regards to simple forms, this works well. The validation and creation code are all contained in one class keeping the code out of the controller. If all you need is validation and a little logic before saving/updating, this model works well. The model breaks down when the complexity of the request goes up.

Invokable Controllers

On a recent freelance project, I needed to validate the request, convert the data and then generate lots of additional values. This Apps calculates the viability of pumps based on the request so there are a lot of fluid dynamic calculations. Once the calculations have been processed, I can again calculate the viability. Only once I have calculated the viability do I save the request.


My action classes have simple names – createGame, saveUser, – you get the idea. When you read the name of the action, you know what it does and when you look inside, you have an idea about what you will see. This doesn’t work when there are five or six steps that must happen before the “quote” is created.

We get this benefit with invokable controllers as well but rather than the class names telling you what is happening, the method names in the controller describe what is happening. We get all the benefits of invokable action classes without the negative of a giant action class which is doing more than its name suggests.

I rarely need to use invokable controllers but when I do, they are a life saver.

I’ve a detailed post on how I use action classes and how the specific use changes on the structure of the App. If you are a fan of invokable action classes, please give it a read.