CakePHP Tips 2017 Part 1

Whoops as ErrorHandler

I recently switched to Whoops in my apps.
It provides a better exception rendering for development mode for most cases.

Just load the plugin (dereuromark/cakephp-whoops) and modify the bootstrap line:

//(new ErrorHandler(Configure::consume('Error')))->register();
(new \CakephpWhoops\Error\WhoopsHandler(Configure::consume('Error')))->register();

If you already have a src/Application.php and run a middleware setup, you also want to make sure you either remove the ErrorHandlerMiddleware there, or provide a custom one for Whoops.

You can test it for example with my sandbox app.
Check it out locally, set it up in minutes and give it a test run.

Jump from browser to IDE

With the Whoops error handler the probably nicest feature is the "click to IDE" one.
It allows to click on the class inside the displayed code piece and jump right into the IDE into the exact line of that file displayed in the browser stack trace.

Be more productive leveraging your IDE

Using the new IdeHelper plugin you can now not only bake annotations into new code, but also adjust
your existing code all the time.
The plugin provides a shell to quickly sync the existing annotations with your code.

This way you can maximize IDE compatibility and with that prevent obvious issues and mistakes.
The IDE will usually mark problematic code yellow (missing, wrong method etc).

It can also enable you to click through the classes and object chains which otherwise would just be plain text and have no typehinting.
Finally autocomplete will be available for all the "magically" provided classes and methods this way.

screenshot

This plugin is supposed to work with ANY IDE that supports annotations.
The plugin wiki contains even details and tips/settings for each of those IDEs – collected by the community.

Enable PHPStan in your app and plugins

PHPStan is a super useful static code analysis tool.
It will help you to find issues with your code way beyond what the test suite or IDE syntax checks can do.

For example, if you have two many different return types and only respect one of them, it will mark this as issue.
It will also tell you about interface mismatch or other similar code smells.

Adjust Travis

Add a new matrix row and a script call for that matrix entry:

...

matrix:
  include:
    ...

    - php: 7.0
      env: PHPSTAN=1 DEFAULT=0

...

script:
  ...
  - if [[ $PHPSTAN == 1 ]]; then composer require --dev phpstan/phpstan && vendor/bin/phpstan analyse -l 1 src; fi

...

Level 1 (-l 1) is the lowest level, once everything passes you can go up to level 5 currently. I recommend trying level 3, if possible.

If you need to ignore certain errors, you can use a custom phpstan.neon file in your /tests directory and then append -c tests/phpstan.neon into the command for travis.

vendor/bin/phpstan analyse -c tests/phpstan.neon -l 1 src

For me such a file looked like this, for example:

parameters:
    autoload_files:
        	- %rootDir%/../../../tests/bootstrap.php
    excludes_analyse:
        - %rootDir%/../../../src/TestSuite/*
    ignoreErrors:
        - '#Call to an undefined method Cake\\Datasource\\EntityInterface\:\:source\(\)#'

Don’t try to ignore too much, though – only "false positives" are recommended to be added here.

You can also write custom PHPStan extensions, see the current CakePHP core /tests/PHPStan folder for details.

Using it locally

I added this to my plugins’s composer.json files:

"scripts": {
    ...,
    "phpstan": "phpstan analyse -l 1 src",
    "phpstan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan && mv composer.backup composer.json"
}

This will allow local testing without messing up your composer file 🙂
For app instead of plugin development you also want to backup-restore the lock file.

Now just run

composer phpstan-setup
composer phpstan

I bet you will find a few useful issues to resolve right on the first run of this tool.

3 Comments

  1. Hi Mark

    Thanks for your introduction to PHPStan. Ive tried to get rid of all errors, but there is one which I can’t:

    use of CakePHP constants…e.g.:

    "Constant ROOT not found."

    Of course, these constants are defined elsewhere (in the Cake core).

    Is there any trick to get this valid or should I just exclude this test?

    Thanks,
    Frank

  2. Make sure either define those, or include the bootstrap file (as done e.g. in CakePHP core).

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.