You probably all know PHPStorm. Just a quick reminder to start this article: PHPStorm is an IDE (Integrated Development Environment) engineered by JetBrains for web developers. This full-featured web development IDE has become increasingly popular over the last couple of years.

Recently, I began to use it myself.

I used Emacs before. But over time PHPStorm integrated such wonderful features that I decided to give it a try.

I used to have a fully customized version of Emacs for PHP:

  • PHPCS, PHPStan and PHPMD linting
  • Integrated Symfony console
  • PHP-CS-Fixer fixes on buffer save
  • PHPUnit integration
  • Xdebug debugging

If you want to retrieve these configurations have a look at here.

After switching to PHPStorm, I was quite satisfied. Indeed, almost all of these features were natively integrated with very few configurations.

But one wasn’t integrated as I wanted: PHP-CS-Fixer fixes on demand.

If you never heard about PHP-CS-Fixer, you really should have a look at this useful tool.
In the official documentation, PHP-CS-Fixer is described as the following:

The PHP Coding Standards Fixer (PHP CS Fixer) tool fixes your code to follow standards; whether you want to follow PHP coding standards as defined in the PSR-1, PSR-2, etc, or other community-driven ones like the Symfony one. You can also define your (team’s) style through configuration.

As I’m writing this article, PHPStorm still doesn’t handle external formatters. Therefore PHP-CS-Fixer fixes could only be triggered using the intentions menu (Alt+Enter or the light bulb).

I didn’t want to wait for PHPStorm’s intentions guessings. Indeed, PHPStorm is taking time to guess theses intentions, and sometimes even doesn’t guess it. Fortunately, I came up with a tiny solution that I’m going to explain.

 

Cookbook

This kind of solution has already been described in a lot of articles over the internet.

But I wanted to go further and get my PHP-CS-Fixer using relevant configuration files.

For example, if I’m in a project that’s holding a configuration file (eg: .php_cs or .php_cs.dist), I want fixes to be done using that configuration. On the other hand, if none of these files are present in the project, I want my default configuration file to be used.

In that way, I’ll be compliant with each project’s code style and I'll have my coding style on every other PHP files.

1. Install PHP-CS-Fixer

I’m not going to detail this step as it’s already done very well on the official documentation.

2. Write the wrapper PHP script

The trick in this solution is to write a custom PHP script that will act as a wrapper of PHP-CS-Fixer and will execute some custom logic.

Thanks to that script, we’ll be free to execute any custom logic we want.

Below is the content of my own script /home/user/.mtarld/phpcsfixer/phpcsfixer:

#!/usr/bin/php
<?php

// Path to php-cs-fixer executable
const PHP_CS_FIXER_EXECUTABLE = '/home/user/.composer/vendor/bin/php-cs-fixer';

// Default config paths (your own configuration)
const DEFAULT_PATHS = [
    '/home/user/.mtarld/phpcsfixer/.php_cs',
];

// Expected project's php-cs-fixer config filenames
const PHP_CS_PROJECT_CONFIG_FILENAMES = [
    '.php_cs',
    '.php_cs.dist',
];

function findConfig(?string $projectPath): ?string
{
    // Try to find a config file in current project
    if (null !== $projectPath) {
        foreach (PHP_CS_PROJECT_CONFIG_FILENAMES as $filename) {
            if (file_exists($path = $projectPath.DIRECTORY_SEPARATOR.$filename)) {
                return $path;
            }
        }
    }

    // Try to find a config file in default paths
    foreach (DEFAULT_PATHS as $path) {
        if (file_exists($path)) {
            return $path;
        }
    }

    return null;
}

$config = null !== ($configFile = findConfig($argv[1] ?? null))
    ? sprintf('--config=%s', $configFile) 
    : ''
;

// Execute the real php-cs-fixer
shell_exec(sprintf(
        '%s fix %s --quiet --using-cache=no %s',
        PHP_CS_FIXER_EXECUTABLE,
        $config,
        $argv[2] ?? null
));

return 0;

As you can see, we just dynamically tell PHP-CS-Fixer which configuration to use when it’s executed.

This script could therefore be executed like the following:

$ /home/user/.mtarld/phpcsfixer/phpcsfixer projectPath targetFile

⚠️ Don’t forget to add execution rights to your script!

3. Create a new PHPStorm External tool

The hardest part is done. Now, we just have to bind PHPStorm with our script.

To do that, in the settings popup, navigate to Tools > External Tools and click on the + button to add a new external tool.

Then, configure it like the following:

Important fields are:

  • ProgramThe location of your custom script.
  • ArgumentsArguments given to the script.
    Here we are giving the project root path and the current file path
  • Open console for tool outputIf console should pop on command execution
    As we don’t wanna be bothered on each fix, we’ll leave it unchecked

4. Add a handy key binding

Last but not least, specify a key binding that will be used to trigger our custom PHP-CS-Fixer.

To do that, in the settings popup, navigate to Keymap, unfold External Tools twice, and double click on PHPCS Fixer (or whatever the name you gave it). Finally, bind your favorite keys.

 

And voilà!

As a result, you’ll just have to press your favorite keybinding, and the file will be fixed.

Moreover, following this very same cookbook, you’ll be able to easily extend PHPStorm integrating other external tools into it. Therefore, feel free to customize it as you like!