Laravel Sailで作成したプロジェクトにPHP CS Fixerで自動整形できるようにする

PHP CS Fixerを利用するとPSR-1、PSR-2などで定義されているPHPコーディング規約に沿って自動整形することができます。

FriendsOfPHP/PHP-CS-Fixer: A tool to automatically fix PHP Coding Standards issues
https://github.com/FriendsOfPHP/PHP-CS-Fixer


これをLaravel Sailで作成したプロジェクトで利用できるようにパッケージのインストール、定義の作成、VSCodeの拡張機能を利用して自動整形できるようにしてみました。

## 前提

[こちら](https://qiita.com/kai_kou/items/bfea0281689b3d376812)の手順で手元にLaravel Sailで作成したプロジェクトがクローンされており、Dockerコンテナが実行されている環境となります。

今回の手順は[GitHubリポジトリ](https://github.com/kai-kou/laravel-sail-sample-projects/tree/use-php-cs-fixer)でも確認できます。

## 手順

### 設定ファイルを用意する

今回はLaravelのコーディング規約に合わせたいので公式ドキュメントを確認します。

Contribution Guide - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/8.x/contributions#coding-style

>Laravel follows the PSR-2 coding standard and the PSR-4 autoloading standard.
>(日本語翻訳)LaravelはPSR-2コーディング標準とPSR-4自動読み込み標準に準拠しています。

PHP CS FixerにはLaravelのルールセットは含まれていません。

PHP-CS-Fixer/index.rst at 2.18 · FriendsOfPHP/PHP-CS-Fixer
https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/2.18/doc/ruleSets/index.rst

自前でLaravelのコーディング規約に沿って設定を用意することができますが、なかなかに設定が多くなるのと、メンテナンスが大変そうです。

Laravel PHP-CS-Fixer のルール設定 - Qiita
https://qiita.com/ucan-lab/items/7d4180462347a42009d5

今回は下記パッケージがLaravel用のルールセットを用意してくれていたので利用します。
こちらのパッケージをインストールするとPHP-CS-Fixerも合わせてインストールされます。

```console
> cd <プロジェクトのディレクトリ>
> ./vendor/bin/sail composer require matt-allan/laravel-code-style --dev
```

パッケージがインストールできたらパッケージに含まれるPHP-CS-Fixerの設定ファイル`.php_cs.dist` をプロジェクトのディレクトリにコピーします。

```console
> cp ./vendor/matt-allan/laravel-code-style/.php_cs.dist .
```

設定ファイル`.php_cs.dist`を一部変更します。
`@Laravel:risky` は副作用のあるルールとなりますので、必要に応じて外してください。

```php:.php_cs.dist
<?php

// 下記を削除(コメントアウト)する
// require __DIR__ . '/vendor/autoload.php';

$finder = PhpCsFixer\Finder::create()
    ->in(__DIR__);

// フィルターを追加する
return (new MattAllan\LaravelCodeStyle\Config())
        ->setFinder($finder
            ->exclude('bootstrap/cache')
            ->exclude('storage/framework')
        )

        ->setRules([
            '@Laravel' => true,
            '@Laravel:risky' => true,
        ])
        ->setRiskyAllowed(true);
```

PHP-CS-Fixerを実行すると`.php_cs.cache`が作成されますが、Gitリポジトリにコミットする必要はないので、`.gitignore`に設定を追加します。

```console
> echo '.php_cs.cache' >> .gitignore
```


### VSCodeの拡張機能のインストール

下記の拡張機能を利用して、VSCodeでソース保存またはコマンド実行で自動整形されるようにします。

PHP-CS-Fixer - Visual Studio Marketplace
https://marketplace.visualstudio.com/items?itemName=higoka.php-cs-fixer

プロジェクト直下に`.vscode/settings.json`ファイルを作成することでワークスペースごとにVSCodeの設定が切り替えできるので、そのファイルに拡張機能の設定を追加します。

```json:.vscode/settings.json
{
    "php-cs-fixer.executable": "vendor/bin/sail exec -T laravel.test vendor/bin/php-cs-fixer",
    "php-cs-fixer.allowRisky": true
}
```

VSCodeでプロジェクト単位の拡張機能を設定する - Qiita
https://qiita.com/k_bobchin/items/717c216ddc29e5fbcd43

### `docker-compose.yml` の編集とコンテナ再起動

VSCodeの拡張機能から自動整形する場合、対象となるソースファイルを絶対パスでパラメータ指定されます。そのため、コンテナ内でPHP-CS-Fixerが絶対パスが参照できないと実行できないので、`docker-compose.yml`を編集します。

```yaml:docker-compose.yml(一部)
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.0
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.0/app
        ports:
            - '${APP_PORT:-80}:80'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
        volumes:
            - '.:/var/www/html'
+           - '$PWD:$PWD'
(略)
```

`laravel.test`コンテナの`volumes`に`'$PWD:$PWD'` を追加して、絶対パスが参照できるようにしました。

`docker-compose.yml`を編集したらコンテナを再起動します。`sail restart`コマンドだと追加した設定が反映されないので`stop`してから`up -d`します。

```console
> ./vendor/bin/sail stop
> ./vendor/bin/sail up -d
```

## 動作確認

インストールや設定ができたら実際に自動整形されるか確認してみます。



### コマンドで自動整形

コマンドでPHP-CS-Fixerを実行します。ここでは`--dry-run`オプションを付けて自動整形の対象をリストするだけにします。

```console
> ./vendor/bin/sail exec laravel.test vendor/bin/php-cs-fixer fix --dry-run

Loaded config Laravel from "/var/www/html/.php_cs.dist".
Using cache file ".php_cs.cache".
   1) app/Models/User.php
   2) app/Providers/AuthServiceProvider.php
   3) server.php
   4) tests/Feature/ExampleTest.php

Checked all files in 2.434 seconds, 14.000 MB memory used
```

自動整形される内容を`--diff`オプションを付けて確認しています。

```console
> ./vendor/bin/sail exec laravel.test vendor/bin/php-cs-fixer fix --dry-run --diff --diff-format udiff app/Models/User.php

Loaded config Laravel from "/var/www/html/.php_cs.dist".
Using cache file ".php_cs.cache".
Paths from configuration file have been overridden by paths provided as command arguments.
   1) app/Models/User.php
      ---------- begin diff ----------
--- Original
+++ New
@@ -2,7 +2,6 @@

 namespace App\Models;

-use Illuminate\Contracts\Auth\MustVerifyEmail;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Notifications\Notifiable;

      ----------- end diff -----------


Checked all files in 0.053 seconds, 14.000 MB memory used
```

コマンドで実行できることが確認できました。

### VSCodeで自動整形

自動整形対象となったソースファイルをVSCodeで自動整形できるか確認します。
VSCodeでプロジェクトのディレクトリを開きます。それ以外のディレクトリだと`./vendor/bin/sail`コマンドのパスが拡張機能から参照できず実行できないので注意が必要です。

```console
> code <プロジェクトのディレクトリ>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48549/9ee916c7-b0b1-3f66-d956-8891d44bfe4c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48549/8f299888-7342-a21a-e7cc-10daa6287b19.png)
VSCodeでも自動整形できることが確認できました。

#### 注意点

自動整形されない(エラーになる)ケースとして、1.Dockerコンテナが起動していない、2.`vendor/bin/sail`がみつからないなどの原因があります。
エラー内容はVSCodeの「表示→出力」メニューから「ログ(ウィンドウ)」を表示するとエラー内容が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48549/310c742c-8ca4-4c26-daa9-d87a19fa9820.png)

2.`vendor/bin/sail`がみつからない場合、VSCodeアプリを再起動すると解消することは確認できています。


## まとめ

せっかくLaravel SailでDockerの開発環境が構築できたので、できるだけDockerを活用したくて試してみたら条件付きですが、いい感じにできました。


## 参考

FriendsOfPHP/PHP-CS-Fixer: A tool to automatically fix PHP Coding Standards issues  
https://github.com/FriendsOfPHP/PHP-CS-Fixer

Contribution Guide - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/8.x/contributions#coding-style

PHP-CS-Fixer/index.rst at 2.18 · FriendsOfPHP/PHP-CS-Fixer
https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/2.18/doc/ruleSets/index.rst

Laravel PHP-CS-Fixer のルール設定 - Qiita
https://qiita.com/ucan-lab/items/7d4180462347a42009d5

PHP-CS-Fixer - Visual Studio Marketplace
https://marketplace.visualstudio.com/items?itemName=higoka.php-cs-fixer

コード 整形 PHP CS Fixer インストール - しすろぐ
https://syslog.life/2020/07/15/%E3%82%B3%E3%83%BC%E3%83%89-%E6%95%B4%E5%BD%A2-php-cs-fixer-%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/

VSCodeでプロジェクト単位の拡張機能を設定する - Qiita
https://qiita.com/k_bobchin/items/717c216ddc29e5fbcd43