2023 Laravel tip roundup – an incomplete list

Dozens of miscellaneous tips: https://laraveldaily.com/tips

Tighten’s Technical Debt Self-Assessment for Developers

Use Laravel Pint or Tighten Duster – they’re so easy to use (versus doing lots of manual PhpStorm configuration, for example) and you can add them as git pre-commit hooks which will only scan files that have changed, so they’ll be fast.

Pint is also useful for cleaning up things that used to be best practice, such as adding parameters to function DocBlocks, but which should now only be written directly in the code of the method itself.

The new Laravel Prompts are great. They are prettier (nice colours, borders and icons) and they neatly handle all the edge cases, including keeping the screen tidy if input validation fails and you need the user to enter an answer again, or if the script is aborted. There are placeholders and default options, and single and multi-select which support Vim keybindings. Each component is a namespaced function that is easy to insert.

If your app has no tests at all, start by doing some “smoke” tests to check all your main routes are functioning. These can be quite brittle.

Turn preventAccessingMissingAttributes on for your Eloquent models. (In dev only.)

Move from Laravel Collective to spatie/laravel-html if you haven’t already (in my experience you can convert <form> tags to plain HTML but you’ll probably still want the package for the convenience of coding select dropdowns and certain radio buttons and checkboxes.

In particular, check that you have @csrf on all your forms and directives like @method('PATCH') where you need them. If you can, write tests that your forms can be submitted. Use this automated Laravel Shift, it’ll save a lot of time but it definitely won’t do everything. You do need to test every form, unfortunately.

When writing tests in general, prioritise Feature tests over Unit tests. Save yourself time and increase accuracy by examining the view data you get back rather than using assertSee (which blindly scrapes the output). Laravel Dusk is handy for things you can only really check in a browser.

Using old hardware: if a Mac is no longer receiving software updates and consequently Homebrew is unreliable or takes ages to compile, consider using Macports instead, which, for example, still has the very latest PHP versions. (I found those were very quick to install and only MariaDB took 20 minutes+ to build from source.) You can also use artisan serve or even just PHP’s built in server (php -S). And for editing you have Nvim. I certainly wouldn’t do “serious development” an old machine, but it makes a great backup.

A short verbatim quote I enjoyed from Matt Stauffer’s “Laravel and in the enterprise” talk at this year’s Laracon (there’s plenty of other good stuff in the full thing):

“People imagine that if they do “API-first” they’ll build an API, they’ll build an SPA in front of the API, and later they’ll get a free mobile app API out of it and they’ll build the mobile app and it won’t be any work.

What happens in reality is it takes three times as long to build your web app as it would if you’d just used native technologies, you have to learn SPAs, you end up building an API that’s super, super super tightly integrated with your SPA and then one day if you do eventually maybe have a mobile app it turns out it doesn’t need the same API resources and routes that you built because you didn’t really build a true REST API you built one that served that SPA, and you just have a second API now.

So your web app took longer to build, it’s more complicated and you have two APIs.”

Matt Stauffer (Tighten)

(you can do a nice, simple SPA, including persisting elements like an audio player, with Livewire 3)

PhpStorm gotcha: all PHP errors missing – “No errors found in this file”

If all your PHP errors and warnings suddenly disappear from your IDE editor window, despite you having the language level configured correctly etc., double check you haven’t turned on Reader Mode by accident, as by default it hides “error and warning highlighting and the inspection widget”.

Therefore you’ll see the message “No errors found in this file” when pressing F2, even though there are some.

Also by default, it turns on font ligatures (the fancier versions of =>, != etc.) so if you’re seeing those and wondering why, even though you have the boxes unticked in Preferences Editor > Font, or Editor > Color Scheme > Color Scheme Font / Console Font – again, check it’s not activated.

All this is configurable in Preferences > Editor > Reader Mode.

Note that Reader Mode is toggled on and off for individual files.

Jetbrains official docs

Troubleshooting custom WordPress WP-CLI commands running on WP Engine’s SSH Gateway

This is a one line fix if you have missing string/array output from a custom WP-CLI command when using the WP Engine “SSH Gateway”.


    • WP Engine is a WordPress hosting company*.
    • They have an SSH Gateway – where you login to a separate machine and it will pass a limited range of useful commands to your actual server (basic file management, a MySQL console client, WP-CLI)
    • WP-CLI is a timesaving WordPress command line utility.

The problem is the unorthodox way the gateway works suppresses ordinary output from certain commands – e.g. print_r or echo.  Symptom: you run a  WP-CLI command of your own through the SSH gateway and lines of text you’re expecting are missing.

First, you should switch from WP_CLI::line() (deprecated now anyway) to WP_CLI::log() – the line() method doesn’t work because, if you dig into the source code, you’ll see it just echos the output, however log() uses the proper wp-cli Logger class.

That’s fine if you want to output strings. Unfortunately, it doesn’t work if you need to print an array.

This does though:

fwrite( STDOUT, print_r($foo, TRUE) );

To unpack that, we’re using print_r to neatly print the array. The second argument for print_r returns its value as a string.   You need not fopen STDOUT first, as you would for another file handle.

And that’s it.

* Would I recommend WP Engine? No, given I have hosting knowledge myself, and when I asked for their assistance with this particular problem, their support agent told me it was out of scope and I should look at StackOverflow, for which they have earned this mildly passive aggressive paragraph in a blog post that will sink without trace.   However, many people do like them, and if you’re a WordPress developer, you may well inherit a client with a site hosted there one day.

Fixing invalid public key for packages.sury.org

Update 21 March 2021: there’s been a recent uptick in traffic to this page – the current problem everyone is having is due to an expired key.  Read more in this deb.sury.org github issue.

Solution (Debian 10.8 Buster):

(comments in various places suggest removing the old key is crucial)

sudo apt-key del B188E2B695BD4743
sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg

Useful command worth noting:

apt-key list

Original April 2019 blog post:

If you’re running Debian and using:

deb https://packages.sury.org/php/ stretch main

(it might be in /etc/apt/sources.list.d/php.list rather than the usual sources.list)

… you may see this error:

Err:5 https://packages.sury.org/php stretch InRelease
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B188E2B695BD4743
Reading package lists... Done
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.sury.org/php stretch InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B188E2B695BD4743
W: Failed to fetch https://packages.sury.org/php/dists/stretch/InRelease The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B188E2B695BD4743
W: Some index files failed to download. They have been ignored, or old ones used instead.

This isn’t widely blogged yet, however the best source of info is the Issue queue for the deb.sury.org GitHub repository – it turns out that in mid-March, the key for each repository on sury.org was regenerated due to a compromised server.

Here’s the command to download the new one, after which apt will work as expected.

sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg


Drupal 6 – troubleshooting ‘Site off-line’ db error

A straightforward problem, but one I’ve wasted time on when setting up a D6 LTS site.


The site is currently not available due to technical problems. Please try again later. Thank you for your understanding.

If you are the maintainer of this site, please check your database settings in the settings.php file and ensure that your hosting provider’s database server is running. For more help, see the handbook, or contact your hosting provider.

The uncommented example line in default.settings.php is:

$db_url = ‘mysql://username:password@localhost/databasename’;

I spent some time verifying usernames/passwords and adjusting ansible scripts, what I hadn’t noticed was I need mysqli (Mysql Improved – which has been around since way with mysql v4.1.3), not mysql.

So remember to check the connection protocol as well as the credentials.


Drupal – troubleshooting PHP files downloading rather than executing

A fairly straightforward problem that won’t be unique to Drupal, but you may run into when migrating PHP applications from other hosts.

I was reviving an old D6 site that had been hosted on another ISP (Hostgator, as it happens) and on setting it up on Acquia DevDesktop (which is a local MAMP stack) found PHP wouldn’t execute as normal.

First, isolate the problem:

  • i.e. do other sites besides this one, running on the same computer (typically you’ll get this problem on a local dev setup) work correctly?
  • create a test PHP file (e.g. containing  <?php echo "Hello, world!";  or <?php phpinfo(); and load it

Solution in my case:

  • check the .htaccess – it had the following, which was redirecting all PHP requests to a PHP  binary that didn’t exist.  Once commented it out PHP could run correctly.
# $Id$
# Use PHP56 as default
AddHandler application/x-httpd-php56 .php
<IfModule mod_suphp.c>
 suPHP_ConfigPath /opt/php56/lib

Of course any .htaccess files become irrelevant if you move your dev or production sites to Nginx, but it’s a good idea to read through it anyway.

Memcached and PHP 7.3

Update – Sep 2019: PECL memcached extension v3.1.0 and above support PHP 7.3

Just a note that the PECL memcached extension doesn’t work with PHP 7.3 yet, you need to stay on PHP 7.2.

This is the error I got when trying to running sudo perl install memcached (along with several sasl deprecation warnings):

/private/tmp/pear/install/memcached/php_memcached.c:1284:20: error: expression is not assignable

NB: Also, don’t get memcache and memcached mixed up when searching extensions.

Troubleshooting Drush with Acquia Dev Desktop

Updated Tue 8 Jan 2019

Symptom: drush updb hangs

If drush updb is hanging, first, run it with the --verbose script to see exactly what’s going on – that will show you the MySQL connections. (It turned out in my case Drush was connecting to the wrong database).

Symptom: drush connects to wrong database


  • Try starting the terminal connection via DevDesktop (the icon top right) and see if that makes a difference
  • Double the database connection details in the appropriate loc_ file in ~/.acquia/DevDesktop/DrupalSettings/
  • Check your drush status output
  • Check what happens if you run drush sqlc
  • Try installing the latest Drush (composer require drush/drush) rather than relying on the version that comes with DevDesktop (at time of writing that’s 8.1.7, whereas Drush is now up to 9.5.2)

My situation: I have two MySQL installations running, the 32-bit DevDesktop supplied version, and a 64-bit mariadb (for a very large site where I was experiencing connection timeouts).  They are on different ports. I had a site where ordinary drush commands and drush sqlc connection went to the correct MySQL server but drush updb used the wrong one (confirmed using the --verbose option – in fact it was connecting to a database with a different name entirely.

I couldn’t figure out what was going on, so I upgraded from Drush 8 to 9 and that fixed it immediately.

Symptom: large Drupal 7 site where cache is extremely slow or fails to clear…

drush cc all

…and eventually PHP runs out of memory (“cannot allocate”).

Check Drush is using the correct version of PHP, it may not be – use drush status or, more simply: drush php

To fix:

$ which drush

$ vim /Applications/DevDesktop/tools/drush

# edit the PHP version: [ -z "$PHP_ID" ] && PHP_ID=php7_1

See also: Acquia Dev Desktop known issues page