PHP CS Fixer workflow automatisation for git commits

We all use the PHP Code Style Fixer. We all love it! But, we don't like to click "composer fix" button each time before we push our changes. I promise, you will love the Lefthook utility, because it automates one of the most frequent action in PHP projects.

PHP CS fixer visualisation
Уявлення PHP CS Fixer у поєднанні з LeftHook з точки зору ШІ

Sooner or later, every developer in his life will know the joy of automatic code fixing tools. This saves us time and improves the quality of the code. However, over time, every developer faces the problem of automating such processes. We don't like to manually trigger code fixer workflows wasting our time and focus on such a basic things.

My journey through

I tried a different tools. From direct .git/hooks directory commits to Husky. I was looking for a perfect solution for code fixes automatisation in my projects. One of the most popular tool for such purposes is Husky.

Why I do not like Husky?

  • Complex Setup. Husky configuration goes through too much steps and does not have out-of-box rich functions to simplify the configuration.

  • Node.js Environment. Such a simple tool requires NodeJS installation. It causes performance overhead during installation and usage.

  • Dependency Management. To install Husky you should have one of NPM/PNPM/Bun package manager. Any of them pollute your desktop with unnecessary things and make tool setup more complex.

I found the perfect solution for myself

Scrolling through the GitHub repository list I've discovered the ultimate developer tool named Lefthook. So, why I've liked it?

  • Compiled language used

    • Excellent performance

    • No package managers or runtime required

    • Can be integrated with any environment without headache

    • Delivered as a single binary

  • YAML syntax used for configuration files. YAML is well-know markup for config files in CI workflows for most projects. Github Actions, as an example. It's used in most of open-source projects.

  • Most setup can be configured with built-in utils. Lefthook has reach set of config options. No need to know git internals to configure basic task such as automatic code fix or code lint.

  • Nice monorepo support

Lefthook configuration with PHP CS Fixer

Too much introduction to such a short action. At the time of writing this article, the latest version of Lefthook is 1.6.4. Let's go step by step.

  • Install and configure PHP Code Style Fixer as described in their Readme.

  • Install Lefthook through any desired way listed in installation guide. On MacOS I do it through the brew package manager: brew install lefthook.

  • Create a config file named lefthook.yml at the root of your project. Heads up! It should be the located in the root of git repository even if you use the monorepo.

  • Put the following contents to lefthook.yml file.

pre-commit: 
  commands: 
    web-cs-fixer: 
    tags: style fixer 
    glob: "*.php" 
    stage_fixed: true 
    run: vendor/bin/php-cs-fixer --config=.php-cs-fixer.dist.php --allow-risky=yes fix {staged_files}

Run lefthook install command to apply the changes. Heads up! Lefthook uses git hooks under the hood, so after any update of configuration file you should run lefthook install again.

That's all. Enjoy coding!

Explanation of properties

  • {staged_files} template is built-in variable used to provide list of changed files.

  • glob property used to filter file on which you want to run command.

  • *.php means PHP CS Fixer will run only on php files avoiding conflicts with other extensions.

  • stage_fixed is my favourite part. It cares about adding changed files back to git (no need to run git add command).

  • run contains command you want to run before each commit.

Monorepo setup

In one of my project I use docker mono repository design. One of the container is PHP Symfony application. There are simple solution for such case.

To run PHP CS Fixer in monorepo there is root property in config. Update your lefthook.yml in the root of the project with the following config.

pre-commit: 
	commands: 
		web-cs-fixer: 
			tags: style fixer 
			root: "path/to/docker_containers/php_web_app/" 
			glob: "*.php" 
			stage_fixed: true 
			run: vendor/bin/php-cs-fixer --config=.php-cs-fixer.dist.php --allow-risky=yes fix {staged_files}

Replace path/to/docker_containers/php_web_app/ with path to your php project directory. Heads up! Path you should end with the trailing slash '/'.