CakePHP 3.6 is coming

The first betas have landed already. Make your plugins and apps 3.6-ready now.
It is actually rather easy – better to be proactive now and have a small migration path than a big fallout and some surprises in a few weeks or months.

Prepare your Application

First read the 3.6 migration guide to get a grasp of the upcoming changes.
Deprecations ignored (easy ones, more later), there are not too many changes – especially no heavy ones. All in all this should be a very smooth upgrade from previous 3.x versions.

Now for the actual upgrade we have a few important issues to talk about:

Regressions

3.6 might introduce accidental regressions or issues that your app can not deal with. Those should be either fixed or outlined in the documentation and migration guide.
You can spend a few minutes here to find out early on how compatible your app is to a new minor version. Execute

composer require cakephp/cakephp:"dev-3.next as 3.5.14"

if you want to check the latest 3.6 version faked as 3.5 (due to the constraints). You can of course try 3.6 here as aliases, as well (as long as no constraints locks it down to ~3.5.x).

Note: For some plugins there might be already a 3.next branch (or even tags), as well.

Report or PR any issues you find and help to make the 3.6 release as smooth and BC as possible.

Migration path

Always keep up with minors in the framework. So at this point I expect everyone to be already running on CakePHP 3.5 for a while.

You can already have fully removed any deprecation of 3.4 or 3.5, which will further make the migration path smaller and easier to review.
Since 3.6 will trigger actual deprecation notices, this is really advised to do early on.
Once you actually switch to 3.6 you can actually silence the deprecations for the first run to verify functional compatibility by setting the error level in your app.php configs:

    'errorLevel' => E_ALL & ~E_USER_DEPRECATED,

Read the 3.6 migration guide for any functional upgrade that might be necessary, those should be applied first.

Once you established functional BC, you can start replacing all deprecations and afterwards again all tests should pass.

Tip: Try not use the above silence as a production default if possible. Instead try to remove those asap. But if not all plugins are updated yet, or do you don’t have the time to fix all of them right now, it is acceptable to just keep the deprecations silenced for the time being.

Migration tooling

Until now there was the CakePHP Upgrade tool which really helped a lot for the migration.
And it still does for a small subset, e.g. upgrade skeleton syncs the skeleton files from the latest cakephp/app repo into your app.
So it might not be completely dead just yet. If you are even below 3.5, definitely check it out.

But regex can only do so much. For more complex issues and especially all the deprecations there are now more modern and less error prone solutions available.
There is a very useful PHP tool that can help with deprecation replacement called rector.
It introspects the code and can very reliably identify and replace code pieces.

I tried it and using

composer require --dev bamarni/composer-bin-plugin
composer bin rector require --dev rector/rector
// lets dry-run for src/ directory
vendor/bin/rector process src/ --level cakephp36 --dry-run

it will show you what it would change as diff. Without --dry-run it will then actually run the upgrade. Make sure you committed all files or made a backup.

Tip: If it takes too long, just run it on each subfolder, e.g. src/Model, …

You can take a look at its CakePHP config. If there is anything missing, you can PR (pull request) your additions.

Plugins/Ecosystem

If you encounter issues with plugins or alike, open a ticket or better yet a pull request to get these things fixed ASAP.
This should ideally also be done pro-actively before you actually start upgrading your code-base, so that there is no time-bottleneck.

In case there really is something stuck, you can make a fork and use a tmp branch of master on your side for the upgrade.
Your composer.json would then point to dev-master of your repository fork and contain a repositories link so that composer knows to look there:

  "repositories": [
    {
      "type": "git",
      "url": "[email protected]:your-name/plugin-name.git"
    }
  ],

Once there is a tag with the fixed code in that original repository, you can remove and use the tagged release again.

Prepare your Plugins

This actually brings us the next point – if you are maintainer of a plugin yourself.

Having so many deprecations throughout 3.x it becomes more and more difficult to keep track of when methods were added and since what version you can use them, or not use others anymore.
With 3.6 this is more important than ever since this now adds deprecation warnings emitted for deprecated usage.
So make sure that if you start supporting 3.6 for your plugins, that your composer.json constraint towards cakephp/cakephp reads ^3.6. Users need to know if they can pull your version without the application breaking.

First of all: Make sure you support 7.2 in your Travis test matrix. There are quite some changes hidden in count() usage that can easily break your code or at least emit warnings.

Secondly, make sure you got also older PHP and CakePHP versions properly regression tested.
I started to actually add the following trick into my plugins:

matrix:
  include:
    ...

    - php: 5.6
      env: PREFER_LOWEST=1

Then exchange the first before_script line composer install with

before_script:
  - if [[ $PREFER_LOWEST != 1 ]]; then composer install --prefer-source --no-interaction ; fi
  - if [[ $PREFER_LOWEST == 1 ]]; then composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable ; fi

This will make sure, composer uses the lowest possible versions everywhere.
You will now spot any wrong usage of methods right in your tests in Travis – if those are covered by tests, that it.
That’s why I think it is more valuable that the tests execute the code than having good asserts. Sure, the latter is also needed in some cases. But the mere fact that the code executes fine means already a lot, from syntax issues (based on the PHP changes even in minor versions) and interface issues to other more runtime issues.

A full working version can be seen e.g. in TinyAuth .travis.yml.

Try to support 3.5 and 3.6

It is usually best to not always jump right to the latest minor as minimum requirement. This makes it harder for folks on the previous minor to get patches and bugfixes.
Thus, with the new deprecation warnings, you might have to do the following if you use any deprecated functionality because of this:

Add <ini name="error_reporting" value="16383"/> into your phpunit.xml.dist file (see here for example).

Similar things can be required for tooling like PHPStan. The linked IdeHelper plugins also shows a solution for this using a shim.php file that contains

error_reporting(E_ALL & ~E_USER_DEPRECATED);

Icing on the cake

You want to go even a step further and get alerted early on if your plugin or app breaks with new minors or patches?

Most of the time I encountered CI fails and BC issues months after when I applied a new change to a plugin and suddenly tests that should have passed didn’t pass anymore.
In this case you can see that the core way of building a query has been changed and now has less () brackets in 3.5+. Notified about this I can just make the tests conditional on the CakePHP version and all is good again.

It is rather easy to enable a cronjob in CI (e.g. Travis) that runs nightly or weekly and alerts you of any failures of new releases.
This is an example of how to enable for Open Source plugins in Travis:

5.00 avg. rating (97% score) - 4 votes

1 Comment

  1. Thanks for the Rector mention! It came a long way since the post release and can handle refactoring much better.

    Let me know at the Github issues if you need any help or to complete it with new rules.

    I’d be happy to help

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.