My Upgrades to CakePHP 4.5.0

A few months back I upgraded docket and this site to CakePHP 4.5 from an earlier 4.x release. I wanted to share my notes from the upgrade process so that if you’re considering an upgrade you have a better idea of what to expect.

Disclaimers

I think it is important to be transparent about the complexity of the applications I upgraded. Both my personal site and docket are relatively simple applications, with good test coverage. Having good test coverage is invaluable when performing upgrades as you can quickly validate that the functionality covered by tests still works correclty. If you don’t already have a good test suite, now is a great time to investing in automated testing.

Getting ready

Before attempting the 4.5 upgrade, I first made sure that I had all the deprecations for earlier 4.4 releases resolved and that my application’s tests passed with the most recent 4.4 release, and latest plugin releases. The CakePHP plugins often fix deprecation issues well before a new minor release ships to make upgrading easier, and I wanted to have as few deprecations as possible to resolve during the 4.5 upgrade.

Use the Upgrade Tool

For both docket and my personal blog, I started off the upgrade by using the CakePHP Upgrade Tool . To get the upgrade tool installed I ran:

Show Plain Text
  1. # Clone the repository
  2. git clone git://github.com/cakephp/upgrade
  3.  
  4. # Check out the 4.x branch
  5. cd upgrade
  6. git checkout 4.x
  7.  
  8. # Install dependencies
  9. php composer.phar install --no-dev

With the upgrade tool installed, it was time to run the rector refactorings:

pre(bash)..
cd upgrade
bin/cake upgrade rector —rules cakephp45 ../docket-app/src
bin/cake upgrade rector —rules cakephp45 ../docket-app/tests

After running rector on the application code and tests, I didn’t have any failing tests, so it was onto manual fixes for the remaining deprecations.

Manual Changes

While rector is able to take care of many of the typing related fixes, there were a few things that I needed to resolve manually.

Dynamic Properties

I had several deprecations under PHP 8.2 related to dynamic properties. Fixing these was a simple but tedious change of adding property declarations to each class that needed them. The diffs for these changes generally look like:

Show Plain Text
  1. + use App\Model\Table\ProjectsTable
  2. ...
  3. +   public ProjectsTable $Projects;

I chose to include types on the properties I was adding so that I would get better code completion in my editor, and better results from psalm.

Query Separation

In CakePHP 5.0, the Database and ORM packages contain operation specific query classes. In 4.5.0 the Table::query() method emits a deprecation telling you to use one of insertQuery(), selectQuery(), updateQuery or deleteQuery. These methods return operation specific query objects, that emit deprecations on non-sensical operations like calling set() on a SelectQuery.

For my 4.5.0 upgrade, I had a handful of query operations that needed to be update. Making these changes requires understanding the surrounding context and choosing the correct query class. An example of one of these changes is:

Show Plain Text
  1. -       $query = $this->table->query()
  2. -           ->update()
  3. -           ->where($scopeConditions);
  4. +       $query = $this->table->updateQuery()->where($scopeConditions);

Recommendations for larger applications

As mentioned before, my upgrades were both on small applications, and I was able to complete the upgrade in a single pull request. For larger applications, this may not be possible and you’ll need to upgrade in multiple changesets. My gameplan for a larger application would be:

  1. Use the upgrade tool to get as many mechanical changes done as possible.
  2. Upgrade CakePHP to 4.5.0
  3. Use the Error.ignoredDeprecations configuration value to disable deprecations for all paths still emitting deprecations.
  4. Get the basic upgrade tested and merged.
  5. Incrementally fix deprecations in reasonably sized batches. Once you’re done a batch remove those paths from the deprecation ignore list.
  6. Repeat this process until you have no more deprecations.

This process will let you incrementally complete your upgrade and resolve all the deprecations without disrupting your ability to ship new features and bugfixes that your customers care about. I’m interested to hear how this process plays out for folks in the community. If your team has a rough time upgrading to 4.5.0, please open a GitHub Issue as we’d like the upgrade process to be as smooth as possible.

Comments

There are no comments, be the first!

Have your say: