LaravelのFormatter(Pint)の導入

## 1. はじめに

PHPのFormatterで有名な`PHP-CS-Fixer`がありますが、Laravelでは`Pint`というFormatterがv9.3から標準搭載されました。

https://github.com/laravel/laravel/releases/tag/v9.3.0

本記事では`Pint`の使い方とプリセットの解説をしたいと思います。

## 2. 対象読者

- Laravel開発者
- コードの品質を向上させたいと考えている方
- チーム開発で一貫性を保つための方法を探している方

## 3. 目次
- [1. はじめに](#1-はじめに)
- [2. 対象読者](#2-対象読者)
- [3. 目次](#3-目次)
- [4. インストール方法](#4-インストール方法)
- [5. プリセット`laravel`](#5-プリセットlaravel)
  - [5-1. **フォーマットとインデントに関する設定**](#5-1-フォーマットとインデントに関する設定)
  - [5-2. **クラス、関数、制御構造に関する設定**](#5-2-クラス関数制御構造に関する設定)
  - [5-3. **構文と命名に関する設定**](#5-3-構文と命名に関する設定)
  - [5-4. **コメントとドキュメンテーションに関する設定**](#5-4-コメントとドキュメンテーションに関する設定)
  - [5-5. **Laravelに関する設定**](#5-5-laravelに関する設定)
- [6. Pint実行](#6-pint実行)
- [7. さいごに](#7-さいごに)
- [8. 参考サイト](#8-参考サイト)

## 4. インストール方法

Laravel v9.3以降の場合は`Pint`は標準搭載されていますが、それより以前のバージョンではPintをインストールする必要があります。
インストールは以下のComposerコマンドを実行します。

```bash
$ composer require --dev laravel/pint
```

次に、Pintの設定ファイル `pint.json` をプロジェクトのルートディレクトリに作成します。
Pintでは現在下記の３つのプリセットが用意されています。

- laravel
- psr12
- symfony

例えば、`laravel`のプリセットを利用する場合、`pint.json`は以下のようにします。

```json
{
    "preset": "laravel"
}
```

## 5. プリセット`laravel`

プリセット`laravel`のルールは[こちらのリポジトリ](https://github.com/laravel/pint/blob/main/resources/presets/laravel.php)に記載があります。
設定されているルールが何を表しているのかを簡単にまとめました。

### 5-1. **フォーマットとインデントに関する設定**

|設定キー|説明|
|---|---|
|'array_indentation' => true|配列の各行をインデントします|
|'binary_operator_spaces' => ['default' => 'single_space']|二項演算子の前後にスペースを1つ挿入します|
|'blank_line_after_namespace' => true|名前空間宣言の後に空行を挿入します|
|'blank_line_after_opening_tag' => true|開始タグの後に空行を挿入します|
|'blank_line_before_statement' => ['statements' => ['continue','return']]|'continue'と'return'の前に空行を挿入します|
|'blank_lines_before_namespace' => true|名前空間宣言の前に空行を挿入します|
|'cast_spaces' => true|型キャストの前後にスペースを挿入します|
|'concat_space' => ['spacing' => 'none']|文字列結合演算子の前後にスペースを挿入しません|
|'declare_equal_normalize' => true|declareステートメントの等号前後のスペースを正規化します|
|'declare_parentheses' => true|declareステートメントの丸括弧の前後のスペースを正規化します|
|'indentation_type' => true|インデントのタイプを統一します（タブまたはスペース）|
|'linebreak_after_opening_tag' => true|開始タグの後で改行します|
|'line_ending' => true|ファイルの終わりの改行を統一します|
|'method_argument_space' => ['on_multiline' => 'ignore']|メソッドの引数間のスペースを無視します（マルチライン）|
|'method_chaining_indentation' => true|メソッドチェーンのインデントを統一します|
|'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line']|セミコロンの前のマルチライン空白を禁止します|
|'no_extra_blank_lines' => ['tokens' => ['extra','throw','use']]|余分な空行、'throw'または'use'の後の空行を削除します|
|'no_leading_import_slash' => true|インポートの先頭のスラッシュを削除します|
|'no_leading_namespace_whitespace' => true|名前空間の前にある空白を削除します|
|'no_multiline_whitespace_around_double_arrow' => true|マルチラインのダブルアローの周りの空白を削除します|
|'no_singleline_whitespace_before_semicolons' => true|セミコロンの前の単一行空白を削除します|
|'no_trailing_comma_in_singleline' => true|単一行配列の最後の要素の後のカンマを削除します|
|'no_trailing_whitespace' => true|行の終わりの空白を削除します|
|'no_trailing_whitespace_in_comment' => true|コメントの終わりの空白を削除します|
|'no_whitespace_before_comma_in_array' => true|配列内のカンマの前の空白を削除します|
|'no_whitespace_in_blank_line' => true|空行内の空白を削除します|
|'space_after_semicolon' => true|セミコロンの後にスペースを挿入します|
|'trailing_comma_in_multiline' => ['elements' => ['arrays']]|マルチライン配列の最後の要素の後にカンマを挿入します|
|'trim_array_spaces' => true|配列内の空白を削除します|
|'whitespace_after_comma_in_array' => true|配列のカンマの後に空白を挿入します|

### 5-2. **クラス、関数、制御構造に関する設定**

|設定キー|説明|
|---|---|
|'class_attributes_separation' => ['elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none']]|クラス属性（const、method、property、trait_import）間の区切り行数を設定します|
|'class_definition' => ['multi_line_extends_each_single_line' => true, 'single_item_single_line' => true, 'single_line' => true]|クラス定義の形式を制御します|
|'control_structure_braces' => true|制御構造の中括弧の位置を調整します|
|'control_structure_continuation_position' => ['position' => 'same_line']|制御構造の続行位置を同じ行にします|
|'elseif' => true|elseとifを組み合わせたelseifを使用します|
|'function_declaration' => true|関数宣言のスペースや改行を調整します|
|'include' => true|includeとinclude_onceを正しい形にします|
|'no_unneeded_control_parentheses' => ['statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield']]|不要な制御構造の括弧を削除します|
|'no_unneeded_curly_braces' => true|不要な中括弧を削除します|
|'return_type_declaration' => ['space_before' => 'none']|戻り値の型宣言の前にスペースを挿入しません|
|'single_class_element_per_statement' => ['elements' => ['const', 'property']]|一つのステートメントに一つのクラス要素（const、property）を持たせます|
|'single_import_per_statement' => true|一つのステートメントに一つのimportを持たせます|
|'visibility_required' => ['elements' => ['method', 'property']]|メソッドとプロパティの可視性を必須にします|

### 5-3. **構文と命名に関する設定**

|設定キー|説明|
|---|---|
|'array_syntax' => ['syntax' => 'short']|配列のシンタックスを短い（short）形式にします（例：[1, 2, 3]）|
|'clean_namespace' => true|名前空間をクリーンアップします|
|'compact_nullable_typehint' => true|nullable型ヒントをコンパクトにします|
|'constant_case' => ['case' => 'lower']|定数を小文字にします|
|'encoding' => true|ファイルエンコーディングを検証し、UTF-8に設定します|
|'full_opening_tag' => true|短い形式のPHP開始タグ（<?）をフルの形式（<?php）に変更します|
|'fully_qualified_strict_types' => true|厳密な型で完全修飾名を使います|
|'general_phpdoc_tag_rename' => true|一部のPHPDocタグを他のものにリネームします|
|'heredoc_to_nowdoc' => true|可能な場合、heredocをnowdocに変換します|
|'increment_style' => ['style' => 'post']|インクリメント/デクリメントのスタイルを後置にします|
|'integer_literal_case' => true|整数リテラルのケースを小文字にします|
|'lambda_not_used_import' => true|使用されていないlambda関数のインポートを削除します|
|'list_syntax' => true|配列の分割代入のシンタックスを短い形にします|
|'lowercase_cast' => true|キャストを小文字にします|
|'lowercase_keywords' => true|PHPキーワードを小文字にします|
|'lowercase_static_reference' => true|静的参照の'static'キーワードを小文字にします|
|'magic_method_casing' => true|マジックメソッドの名前を小文字にします|
|'magic_constant_casing' => true|マジック定数を小文字にします|
|'no_alias_functions' => true|関数のエイリアスを元の名前に戻します|
|'no_alias_language_construct_call' => true|言語構造のエイリアスを元の名前に戻します|
|'no_alternative_syntax' => true|代替構文（例えば "endif;"）を使用しないようにします|
|'no_binary_string' => true|バイナリ文字列を禁止します|
|'no_mixed_echo_print' => ['use' => 'echo']|echoとprintの混在を禁止し、echoのみを使用します|
|'normalize_index_brace' => true|配列と文字列の添字に一貫した中括弧スタイルを使用します|
|'not_operator_with_successor_space' => true|否定演算子の後のスペースを追加します|
|'nullable_type_declaration' => true|NULL可能な型の宣言を許可します|
|'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false]|デフォルト値がnullの場合のNULL可能な型の宣言を使用しません|
|'object_operator_without_whitespace' => true|オブジェクト演算子の前後の空白を削除します|
|'ordered_imports' => ['sort_algorithm' => 'alpha']|importをアルファベット順に並べ替えます|
|'psr_autoloading' => false|PSRオートローディング規格に従います（falseなら適用しない）|

### 5-4. **コメントとドキュメンテーションに関する設定**

|設定キー|説明|
|---|---|
|'general_phpdoc_tag_rename' => true|一部のPHPDocタグを他のものにリネームします|
|'no_blank_lines_after_phpdoc' => true|PHPDocの後の空行を削除します|
|'no_empty_phpdoc' => true|内容のないPHP|
|'no_superfluous_phpdoc_tags' => ['allow_mixed' => true, 'allow_unused_params' => true]|不要なPHPDocタグを削除しますが、mixedと未使用のパラメータは許可します|
|'phpdoc_indent' => true|PHPDocのインデントを修正します|
|'phpdoc_inline_tag_normalizer' => true|PHPDocのインラインタグを正規化します|
|'phpdoc_no_access' => true|@accessタグの使用を禁止します|
|'phpdoc_no_package' => true|@packageタグの使用を禁止します|
|'phpdoc_no_useless_inheritdoc' => true|無用な@inheritdocタグの使用を禁止します|
|'phpdoc_order' => ['order' => ['param', 'return', 'throws']]|PHPDocタグを特定の順序で並べ替えます|
|'phpdoc_scalar' => true|非複合スカラータイプの修飾を削除します|
|'phpdoc_single_line_var_spacing' => true|単一行の@var PHPDocアノテーションのスペーシングを修正します|
|'phpdoc_summary' => false|PHPDocの要約が必要な場合があります（falseなら要求しない）|
|'phpdoc_to_comment' => false|PHPDocを通常のコメントに変換します（falseなら変換しない）|
|'phpdoc_tag_type' => ['tags' => ['inheritdoc' => 'inline']]|@inheritdocタグをインラインで使用します|
|'phpdoc_trim' => true|PHPDocの前後の不要な空白を削除します|
|'phpdoc_types' => true|PHPDocのタイプを小文字にします|
|'phpdoc_var_without_name' => true|@varタグから変数名を削除します|
|'single_line_comment_style' => ['comment_types' => ['hash']]|一行コメントのスタイルを変更します（#を使用）|

### 5-5. **Laravelに関する設定**

|設定キー|説明|
|---|---|
|'Laravel/laravel_phpdoc_alignment' => true|LaravelのPHPDocのアライメントを調整します|

## 6. Pint実行

設定ファイル作成後、下記のコマンドで実行できます。

```bash
$ ./vendor/bin/pint
```

また、特定のファイルやディレクトリを対象に実行することも可能です！

```bash
$ ./vendor/bin/pint app/Models
$ ./vendor/bin/pint app/Models/User.php
```

## 7. さいごに

他のプリセットも用意されているため、是非どういうルールが設定されているか確認してみてください。
私はPintのルールベースはプリセットを利用し、特定のルールのみを上書きする使い方を検討してみたいと思います。

## 8. 参考サイト

- [Laravel Pint 9.x Laravel](https://readouble.com/laravel/9.x/ja/pint.html)
- [PHP-CS-Fixer Configurator](https://mlocati.github.io/php-cs-fixer-configurator/#version:3.22)
- [pint](https://github.com/laravel/pint)