Laravel PHP-CS-Fixer のインストール

## 関連記事

https://qiita.com/ucan-lab/items/8eab84e37421f907dea0

## PHP-CS-Fixer

https://github.com/FriendsOfPHP/PHP-CS-Fixer

PHPコードを美しく整形してくれる魔法の開発ツールです。

## インストール手順

```shell-session
$ mkdir -p tools/php-cs-fixer
$ composer require --working-dir=tools/php-cs-fixer friendsofphp/php-cs-fixer
```

php-cs-fixer専用のディレクトリを掘ってインストールする方法が推奨されています。
プロジェクトルートのcomposer.jsonを汚さないようにしてます。

```shell-session
$ ./tools/php-cs-fixer/vendor/bin/php-cs-fixer --version
PHP CS Fixer 3.6.0 Roe Deer by Fabien Potencier and Dariusz Ruminski.
PHP runtime: 8.0.15
```

バージョンが表示されればインストールOKです。

### 補足

#### Git Clone したあと

```shell-session
$ composer install --working-dir=tools/php-cs-fixer
```

#### php-cs-fixer をアップデート

```shell-session
$ composer update --working-dir=tools/php-cs-fixer
```

## 設定

### .gitignore 設定

`.gitignore` にキャッシュファイルを追加する

```shell-session
$ echo /vendor >> ./tools/php-cs-fixer/.gitignore
$ echo /.php-cs-fixer.cache >> ./.gitignore
```

### 整形設定ファイルを作る

```shell-session
$ touch .php-cs-fixer.dist.php
```

```php:.php-cs-fixer.dist.php
<?php

declare(strict_types=1);

$finder = PhpCsFixer\Finder::create()
    ->in([
        __DIR__ . '/app',
        __DIR__ . '/config',
        __DIR__ . '/database/factories',
        __DIR__ . '/database/seeders',
        __DIR__ . '/routes',
        __DIR__ . '/tests',
    ]);

$config = new PhpCsFixer\Config();

return $config
    ->setRiskyAllowed(true)
    ->setRules([
        '@PhpCsFixer:risky' => true,
        'blank_line_after_opening_tag' => true,
        'linebreak_after_opening_tag' => true,
        'declare_strict_types' => true,
        'no_superfluous_phpdoc_tags' => false,
        'global_namespace_import' => [
            'import_classes' => true,
            'import_constants' => true,
            'import_functions' => true,
        ],
        'ordered_imports' => [
            'sort_algorithm' => 'alpha',
            'imports_order' => [
                'class',
                'function',
                'const',
            ],
        ],
        'no_unused_imports' => true,
        'phpdoc_types_order' => [
            'null_adjustment' => 'always_last',
            'sort_algorithm' => 'none',
        ],
        'php_unit_test_case_static_method_calls' => [
            'call_type' => 'this'
        ],
        'phpdoc_align' => [
            'align' => 'left',
        ],
        'not_operator_with_successor_space' => true,
        'blank_line_after_namespace' => true,
        'final_class' => true,
        'date_time_immutable' => true,
        'declare_parentheses' => true,
        'final_public_method_for_abstract_class' => true,
        'mb_str_functions' => true,
        'simplified_if_return' => true,
        'simplified_null_return' => true,
    ])
    ->setFinder($finder);
```

※ `->setRiskyAllowed(true)`, `@PhpCsFixer:risky` を設定してます。新規プロジェクトの場合は良いと思いますが、既存プロジェクトに適用する場合は注意してください。
※ PhpStormで書きやすいようにPhpStorm側のスタイルに寄せてます。あとは私の好みで設定してます。

### 補足

`->in([])` で適用するディレクトリを指定できます。
[`@PhpCsFixer:risky`](https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/master/doc/ruleSets/PhpCsFixerRisky.rst) をベースにしてます。

#### PHP CS Fixer Configrator

https://mlocati.github.io/php-cs-fixer-configurator

設定するとどう適応されるかの例を見れる便利なサービスです。

#### declare(strict_types=1);

```
'blank_line_after_opening_tag' => true,
'linebreak_after_opening_tag' => true,
'declare_strict_types' => true,
```

この3つのstrictモードを強制してます。

```php
<?php

declare(strict_types=1);
```

### PHP docの型の並び順

```
'phpdoc_types_order' => [
    'null_adjustment' => 'always_last',
    'sort_algorithm' => 'none',
],
```

型の並び順にこだわりはないので、特にphp-cs-fixer側では指定しません。
`null` に関しては最後に来て欲しいので設定してます。

```
<?php
/**
 * @param string|null $bar
 */
```

### PHP doc タグを削除させない

```
'no_superfluous_phpdoc_tags' => false,
```

あわよくばPHP docを削除しようとするので無効化してます。

## 整形コマンド

```shell-session
# 自動整形しない(差分表示のみ)
$ ./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix -v --diff --dry-run

# 自動整形する
$ ./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix -v --diff
```

## GitHub Actions YAML設定ファイル

CIでチェックすると崩れたコードのマージを防げるので設定しておくと良いです。

```
$ mkdir -p .github/workflows
$ touch .github/workflows/php-cs-fixer.yml
```

```yaml:.github/workflows/php-cs-fixer.yml
name: PHP-CS-Fixer

on:
  pull_request:

jobs:
  php-cs-fixer:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: 8.1

      - name: Install Dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --prefer-dist --working-dir=tools/php-cs-fixer

      - name: PHP-CS-Fixer Version
        run: ./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --version

      - name: PHP-CS-Fixer Dry Run
        run: ./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose --dry-run
```

## Makefile

コマンドが長いので、Makefileでお手軽に実行できるようにします。

```
$ touch Makefile
```

```Makefile
composer-install-tools:
	composer install --working-dir=tools/php-cs-fixer
php-cs-version:
	./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --version
php-cs-dry:
	./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose --dry-run
php-cs-dry-diff:
	./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose --diff --dry-run
php-cs-fix:
	./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose
```

```
$ make php-cs-fix
```

## 参考

- [ソースコードの“赤ペン先生”PHP-CS-Fixerのインストールと設定](https://qiita.com/suin/items/4242aec018d086312fe7)
- [PHP CS Fixer v2 でもっと快適PHPライフ](http://fivestar.hatenablog.com/entry/2017/03/30/233744)
- [php_cs_fixerのオプションをハックする ~ 実行時のdiffつき ~](https://qiita.com/ryoichi-u/items/af10768d6adc5de389e7)
- [Docker X Laravel PHP CS Fixer を導入して、ソースコードを自動整形する](https://qiita.com/ucan-lab/items/b9c41024c3a16830e85f)