Installation et utilisation de php-cs-fixer

Publié le 15/01/2024 • Actualisé le 15/01/2024

Dans cet article, nous voyons différentes méthodes pour installer et utiliser php-cs-fixer. Ce n'est peut-être pas aussi évident que ça en a l'air. C'est parti ! 😎


English language detected! 🇬🇧

  We noticed that your browser is using English. Do you want to read this post in this language?

Read the english version 🇬🇧 Close

Prérequis

Je présumerai que vous avez les connaissances élémentaires de PHP, Symfony et Composer.

Introduction

Php-cs-fixer est un excellent outil qui permet d'automatiquement contrôler le style votre code PHP. Il est très populaire parmi la communauté PHP et est devenu l'un des outils favoris de beaucoup de développeurs PHP. Cependant, son installation peut poser des questions et engendrer quelques problèmes, comme nous allons le voir dans les chapitres suivants.

But

Nous allons passer en revue différentes manières d'installer php-cs-fixer dans un projet, avec leurs avantages et inconvénients.

Le problème

Quoi ? Un article de blog sur l'installation de php-cs-fixer ? C'est une plaisanterie ? N'est-ce pas aussi simple que de lancer ?

composer require --dev friendsofphp/php-cs-fixer

Hé bien, vérifions.

Symfony 7.0 beta était sorti depuis quelques jours (j'ai commencé cet article à ce moment-là). Essayons ; on peut créer un nouveau projet Symfony 7 avec le binaire Symfony :

symfony new my_project_directory --version=7.0.x-dev

Maintenant, installons php-cs-fixer :

cd my_project_directory
composer require --dev friendsofphp/php-cs-fixer
./composer.json has been updated
Running composer update friendsofphp/php-cs-fixer
Loading composer repositories with package information
Restricting packages listed in "symfony/symfony" to "7.0.*"
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

Problem 1
- friendsofphp/php-cs-fixer v0.1.0 requires symfony/console 2.1.* -> found symfony/console[v2.1.0, ..., 2.1.x-dev] but it conflicts with your root composer.json require (7.0.*).
- ...
- friendsofphp/php-cs-fixer v3.4.0 requires symfony/console ^4.4.20 || ^5.1.3 || ^6.0 -> found symfony/console[v4.4.20, ..., 4.4.x-dev, v5.1.3, ..., 5.4.x-dev, v6.0.0-BETA1, ..., 6.4.x-dev] but it conflicts with your root composer.json require (7.0.*).
- friendsofphp/php-cs-fixer[dev-release_notes_template, dev-master, v3.5.0, ..., v3.37.1] require symfony/console ^5.4 || ^6.0 -> found symfony/console[v5.4.0-BETA1, ..., 5.4.x-dev, v6.0.0-BETA1, ..., 6.4.x-dev] but it conflicts with your root composer.json require (7.0.*).
- Root composer.json requires friendsofphp/php-cs-fixer * -> satisfiable by friendsofphp/php-cs-fixer[dev-release_notes_template, dev-master, v0.1.0, ..., v0.5.7, v1.0, ..., v1.13.3, v2.0.0-alpha, ..., v2.19.3, v3.0.0-beta.1, ..., v3.37.1, 9999999-dev].

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
You can also try re-running composer require with an explicit version constraint, e.g. "composer require friendsofphp/php-cs-fixer:*" to figure out if any version is installable, or "composer require friendsofphp/php-cs-fixer:^2.1" if you know which you need.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Boom 💥 ! Ça ne fonctionne pas ; Composer ne peut pas résoudre les dépendances, car php-cs-fixer utilise "symfony/console": "^5.4 || ^6.0", ce qui ne peut donc pas fonctionner avec Symfony 7.0 BETA.

Je sais ce que vous vous dites : 🤔

“C'est une version BETA de Symfony ; c'est pour cela que ça ne fonctionne pas. ”

Ça semble une explication valide, mais qui est toutefois incorrecte : le problème vient de php-cs-fixer, pas de Symfony. Nous n'avons pas de garantie qu'une correction sera effectuée, ni de sa date. Ça pourrait rapidement l'être, ou pas. Ou même pire, devoir forker la librairie.
PS : C'est maintenant corrigé ! 🎉

C'est un rappel que php-cs-fixer est une librairie PHP et a ses propres dépendances. Regardons de plus près son fichier composer.json :

"require": {
    "php": "^7.4 || ^8.0",
    "ext-json": "*",
    "ext-tokenizer": "*",
    "composer/semver": "^3.3",
    "composer/xdebug-handler": "^3.0.3",
    "sebastian/diff": "^4.0 || ^5.0",
    "symfony/console": "^5.4 || ^6.0",
    "symfony/event-dispatcher": "^5.4 || ^6.0",
    "symfony/filesystem": "^5.4 || ^6.0",
    "symfony/finder": "^5.4 || ^6.0",
    "symfony/options-resolver": "^5.4 || ^6.0",
    "symfony/polyfill-mbstring": "^1.27",
    "symfony/polyfill-php80": "^1.27",
    "symfony/polyfill-php81": "^1.27",
    "symfony/process": "^5.4 || ^6.0",
    "symfony/stopwatch": "^5.4 || ^6.0"
},
"require-dev": {
    "facile-it/paraunit": "^1.3 || ^2.0",
    "justinrainbow/json-schema": "^5.2",
    "keradus/cli-executor": "^2.0",
    "mikey179/vfsstream": "^1.6.11",
    "php-coveralls/php-coveralls": "^2.5.3",
    "php-cs-fixer/accessible-object": "^1.1",
    "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
    "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1",
    "phpspec/prophecy": "^1.16",
    "phpspec/prophecy-phpunit": "^2.0",
    "phpunit/phpunit": "^9.5",
    "symfony/phpunit-bridge": "^6.2.3",
    "symfony/yaml": "^5.4 || ^6.0"
},

On voit le composant Symfony posant problème (symfony/console), qui empêche l'installation. On réalise aussi que php-cs-fixer inclut pas mal d'autres librairies, particulièrement dans la section -dev, comme c'est un outil.
Donc, oui, il se peut qu'il y ait des conflits avec votre projet. Le plus de dépendances, le plus de chances, vous avez d'avoir ce genre de problèmes quand on installe une nouvelle librairie. Mais, bien sûr, ceci n'est pas spécifique à php-cs-fixer ; ce problème existe avec n'importe quelle autre librairie PHP.

Donc, cette méthode ne fonctionne pas pour ce nouveau projet Symfony 7 BETA ; voyons les autres méthodes et comment on peut corriger ce souci. Mais, quid de la communauté Symfony ?

Que font les autres développeurs ?

J'étais curieux de savoir ce que les autres développeurs Symfony faisaient. J'ai créé un petit sondage sur le Slack Symfony . Même s'il n'y a pas énormément de réponses (30), ça donne quand une tendance générale. Voici, ce que j'ai posté :

Hello everyone, quick poll: how do you install the wonderful php-cs-fixer library?

  • 1. In the `require-dev` section of the composer file of my project —> composer require --dev friendsofphp/php-cs-fixer
  • 2. In a dedicated composer.json file —> composer require --working-dir=tools/php-cs-fixer friendsofphp/php-cs-fixer
  • 3. With a global composer installation composer global require friendsofphp/php-cs-fixer
  • 4. With docker —> docker run --rm -v $(PWD):/data cytopia/php-cs-fixer fix --dry-run --diff --allow-risky=yes` ($PWD with fishshell)

Les résultats ont été les suivants :


sondage des méthodes d'installation de php-cs-fixer
Generated with maxtables.com

Donc, l'installation de php-cs-fixer dans la section require-dev des projets semble être la méthode préférée de la plupart des développeurs Symfony. Essayons les autres.

Méthode 2 : utiliser un fichier composer dédié dans le projet

Je dois avouer que je n'avais pas encore utilisé cette méthode (jusqu'à aujourd'hui). Quelle est la différence avec la méthode require-dev ? Cette fois, on n'installe pas les dépendances avec celles du projet, mais dans un sous-répertoire. Si on regarde la documentation , c'est même considéré comme la meilleure pratique. Essayons :

mkdir -p tools/php-cs-fixer
composer require --working-dir=tools/php-cs-fixer friendsofphp/php-cs-fixer
/composer.json has been created
Running composer update friendsofphp/php-cs-fixer
Loading composer repositories with package information
Updating dependencies
Lock file operations: 25 installs, 0 updates, 0 removals
  - Locking composer/pcre (3.1.1)
  ...
  - Installing friendsofphp/php-cs-fixer (v3.38.0): Extracting archive
Generating autoload files
22 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.
Using version ^3.38 for friendsofphp/php-cs-fixer

Comme l'outil est installé dans son propre répertoire, il n'y a pas de conflit possible. Nous pouvons l'utiliser comme ceci :

tools/php-cs-fixer/vendor/bin/php-cs-fixer fix src
Loaded config default.
Fixed 0 of 1 files in 0.007 seconds, 14.000 MB memory used

Le fichier de configuration MicroSymfony est un bon début quand on veut créer un nouvel ensemble de règles pour son projet. Il est assez concis et je n'ai mis que l'essentiel. N'hésitez pas à l'utiliser et à l'adapter à votre projet. OK, nous avons désormais une configuration fonctionnelle pour notre projet. Voyons les méthodes restantes.

Méthode 3 : avec une installation globale de composer

composer global require friendsofphp/php-cs-fixer

Cette méthode permet aussi d'éviter les conflits puisque php-cs-fixer n'est pas du tout intégré dans le projet. Au lieu d'utiliser un chemin relatif, on peut ajouter php-cs-fixer dans le path et appeler :

php-cs-fixer fix src

Je ne suis pas réellement fan de cette méthode, car php-cs-fixer est totalement déconnecté du projet, mais ça fonctionne.

Méthode 4 : avec Docker

Comme nous l'avons vu dans le sondage, ce n'est pas la méthode la plus populaire, mais c'est une approche très pragmatique. Le but est d'utiliser une image Docker contenant tout ce qui est nécessaire pour lancer php-cs-fixer. On peut utiliser, par exemple, le dépôt cytopia/docker-php-cs-fixer . On peut lancer la tâche de correction avec la commande Docker suivante :

docker run --rm -v ./:/data cytopia/php-cs-fixer fix --allow-risky=yes

Ça utilise la dernière image disponible (actuellement 3 pour PHP 8.1). Comme ce projet contient de multiples images, on peut aussi exécuter php-cs-fixer sur du code legacy utilisant PHP 7.4 ; dans ce cas, on peut lancer :

docker run --rm -v ./:/data cytopia/php-cs-fixer:3-php7.4 fix --allow-risky=yes

L'avantage, c'est que l'on n'a rien à installer ; on a juste besoin de Docker. Le désavantage est que l'on ne contrôle pas le contenu de l'image ; comme on peut le voir, la dernière version disponible n'est pas dernière de php-cs-fixer disponible (actuellement 3.42).

docker run --rm -v ./:/data cytopia/php-cs-fixer:latest-php8.1 --version
PHP CS Fixer 3.17.0 (3f0ed86) Brazilian Kangaroo by Fabien Potencier and Dariusz Ruminski.
PHP runtime: 8.1.20

Méthode 5 : avec le plugin composer bin

Une chose que j'apprécie beaucoup quand j'écris, c'est qu'en plus de partager ses connaissances, on apprend aussi. Quand j'ai posté mon article sur le Slack Symfony, tarlepp m'a dit qu'il existait un plugin composer à ce sujet : bamarni/composer-bin-plugin . Il prend en charge exactement le problème que nous rencontrons ici. Voyons comment il fonctionne. D'abord, on doit installer le plugin composer :

composer require --dev bamarni/composer-bin-plugin

Puis, on appelle php-cs-fixer avec le nouvel argument bin de composer pour installer php-cs-fixer :

composer bin php-cs-fixer require --dev friendsofphp/php-cs-fixer

Ça installe automatiquement php-cs-fixer dans le répertoire vendor-bin. Il y a plusieurs options pour ce plugin :

    "extra": {
        "bamarni-bin": {
            "bin-links": true,
            "target-directory": "vendor-bin",
            "forward-command": true
        }
    },

Grâce à l'option bin-links, le point d'entrée php-cs-fixer vit toujours dans le répertoire vendor/bin, cela veut dire que l'outil reste au même endroit qu'avec la méthode n°1 et nous n'avons rien à changer dans nos scripts / Makefile. Il y a une configuration additionnelle dans la section post-install-cmd de composer pour qu'il installe aussi les dépendances de php-cs-fixer après celles du projet principal (l'option forward semble ne pas fonctionner, je dois regarder pourquoi).

"post-install-cmd": [
    "@auto-scripts",
    "@composer bin php-cs-fixer install --ansi"
],

C'est tout. Ça correspond en fait à la deuxième méthode néanmoins le plugin bin de composer gère tout pour nous ! J'ai fait une PR sur MicroSymfony pour essayer, et ça fonctionne bien, la CI est passée ✅ du 1ᵉʳ coup.

Résumé

On peut résumer les différents avantages et inconvénients dans le tableau suivant.

\ Méthode 1 : Dans la section `require-dev` du fichier composer du projet Méthode 2 (et 5) : Dans un fichier composer.json dédié Méthode 3 : Avec une installation globale de composer Méthode 4 : Avec Docker
N'entre pas en conflit avec les dépendances du projet
Analyse rapide ❌ (1)
Contrôle fin de la version de php-cs-fixer
Toujours connecté au projet
Aucune installation locale requise

(1) L'utilisation de Docker a un petit impact de performances au lancement. Cependant le temps d'analyse n'a pas l'air si affecté que ça, je vais refaire quelques tests plus précis sur un plus gros projet. Le problème c'est que cette version de php-cs-fixer est un peu obsolète (24 versions mineures de retard !), c'est donc difficile de comparer.

Conclusion

Nous avons vu différentes méthodes pour installer php-cs-fixer. J'ai changé d'avis ; avant, il était évident pour moi que cet outil devait être installé avec les autres dépendances du projet. Maintenant, je pense que l'installation dans un répertoire dédié avec son propre fichier composer.json est plus sûr et élégant (méthodes 2 et 5). Avec la méthode 5 on a même pas à modifier le chemin d'appel de php-cs-fixer. On garde les dépendances du projet aussi succinctes que possible. Mais, l'outil vit toujours dans le répertoire du projet principal, il reste donc rapide, simple à mettre à jour et à utiliser : on a le meilleur des deux mondes.

Et voilà ! J'espère que vous avez aimé. Découvrez d'autres informations en rapport à cet article avec les liens ci-dessous. Comme toujours, retours, likes et retweets sont les bienvenus. (voir la boîte ci-dessous) À tantôt ! COil. 😊

  Lire la doc  Plus sur le web

Ils m'ont donné leurs retours et m'ont aidé à corriger des erreurs et typos dans cet article, un grand merci à : tarlepp and jmsche . 👍

  Travaillez avec moi !


A vous de jouer !

Ces articles vous ont été utiles ? Vous pouvez m'aider à votre tour de plusieurs manières : (cf le tweet à droite pour me contacter )

  • Me remonter des erreurs ou typos.
  • Me remonter des choses qui pourraient être améliorées.
  • Aimez et retweetez !
  • Suivez moi sur Twitter
  • Inscrivez-vous au flux RSS.
  • Cliquez sur les boutons Plus sur Stackoverflow pour me faire gagner des badges "annonceur" 🏅.

Merci d'avoir tenu jusque ici et à très bientôt sur Strangebuzz ! 😉

COil