【メモ】Laravel バリデーションエラー関連

## 見る前の注意書き
フォームのバリデーションエラーメッセージを扱う際に
その都度よく検索している気がするので自分用にまとめたものです

そんなの知ってるよ！という人はブラウザバックのお土産にクッキーをどうぞ:cookie:

:::note warn
Laravel 10・11にて動作確認しました
バージョンが異なる場合は
実装方法に変更の可能性がありますのでご留意ください
:::

## requestファイルを作る
Controllerにてバリデーションルールを処理することは可能だが、管理しやすくするため
バリデーションルール用のクラスを用意する

#### `app\Http\Requests`フォルダ下にRequestクラスのファイルを作成する

```php:ターミナルで以下実行
php artisan make:request クラス名
```
requestクラスは以下例のようにルールをまとめて書けるのでとても便利


```php: requestファイル 記載例
class クラス名 extends FormRequest
{
    public function authorize(): bool
    {
        return true; // falseからtrueに変更する
    }
        
    public function rules(): array
    {
    // リクエストデータ内容を参照したい場合
    $data = $this->all();

        // バリデーションルール設定
        $rule = [
            'name' => [
                'required',
                'max: 255'
            ],
            'name.*' => [ // 同じnameが複数あり、まとめて指定する場合 .*を付ける
                'required'
            ],
        ];

        return $rule;
    }
}
```
ちなみにtrueを返却している`authorize`メソッドではバリデーション前処理（例えば認証）が実装可能
前処理が必要無ければ`authorize`メソッド自体を削除してもtrueに書き換えた場合と同じ結果になる

:::note warn
複数formでバリデーションを分けたい場合
type=sbmitにnameを指定して、valueの値でif分岐させる
:::
```php:rulesメソッド記載例
public function rules(): array
{
    $rule =[];
    $request = $this->all();
    $submit = isset($request['submit_name']) ? $request['submit_name'] : 'デフォルト';

    if ($submit == '検索') {
        // 検索フォームでのルールを記載
    } else {
        // 検索以外でのルールを記載
    }
    return $rule;
}
```



## よく使ってる気がするルール一覧
詳細は[公式ドキュメント](https://readouble.com/laravel/10.x/ja/validation.html)の「使用可能なバリデーションルール」で確認
メッセージはデフォルトが英語なので、日本語化した際に任意で変更する:muscle:

### ◆ 必須
```php:
'required'
```
メッセージ例：
`'required' => ':attributeは必ず指定してください。'`

### ◆ 正規表現
```php
'nullable', // 必須入力以外の場合、空文字時にエラーを回避できる
'regex:/\A[0-9]{4}\z/' // スラッシュ間に任意のルールを記載する
```
メッセージ例：
`'regex' => ':attributeに正しい形式を指定してください。'`

:::note warn
正規表現でよく見る^と$では、PHPの場合不具合が出るのでAとzで記載しています
:::

### ◆ 他の要素に特定の入力があるとき必須にする
```php
'required_if:name,value'
```
メッセージ例：
`'required_if' => ':otherが:valueの場合、:attributeも指定してください。'`

### ◆ inputの内容を指定する場合
ラジオボタンやチェックボックス、セレクトボックスといった入力値に制限を設ける場合
別の値が送信されないようチェックする際に利用する
例えば以下のルールを記載した場合、config > test.phpファイルの`variable_name`内で指定していないキーを送信するとエラーになる

```php
use Illuminate\Validation\Rule;

'Rule::in(config('test.variable_name'))'
```
```php:指定する値のconfigファイル記載例
// ファイルの場所：config>test.php
<?php
    return [
        'variable_name' => [
            '1' => 'お問い合わせ',
            '2' => 'その他',
        ],

    ];
```
メッセージ例：
`'in' => '選択された:attributeは正しくありません。'`

### ◆メールアドレス

```php
'email:strict,dns,spoof'
```
メッセージ例：
`'email' => 'メールアドレスの入力形式に誤りがあります。'`

`email`のみ指定した場合、存在しないドメインやなりすましメールアドレスが通ってしまうため、必要に応じてstrictやdnsといったバリデーションスタイルを適応する

バリデーションスタイルは以下６種類
[コード](https://github.com/laravel/framework/blob/11.x/src/Illuminate/Validation/Concerns/ValidatesAttributes.php#L903)を見る限り`filter`と`filter_unicode`以外のバリデーションスタイルは[EmailValidatorライブラリ](https://github.com/egulias/EmailValidator)を利用している模様
チェック内容？はドキュメントに詳細が無くいため、ざっくりで書いてます
間違っていたらすいません
※デフォルトでは`rfc: RFCValidation`が適応されている
| バリデーションスタイル| チェック内容？ |
|:-:|:-:|
| rfc: RFCValidation | RFC（5321,5322,6530,6531,6532,1035）に準拠しているか |
| strict: NoRFCWarningsValidation | rfcの厳格バージョン、RFCエラーだけではなく警告も含める  |
| dns: DNSCheckValidation | DNSにメールアドレスのドメインが存在するか  |
| spoof: SpoofCheckValidation | なりすましメールでないか  |
| filter: FilterEmailValidation | PHPの関数filter_var()によるチェック  |
| filter_unicode: FilterEmailValidation::unicode() | PHPの関数filter_var()によるチェック　※ Unicode 文字を許可 |

### ◆パスワード
```php
Password::min(X) // 最低X文字以上
         ->letters() // 最低１文字の入力必須
         ->mixedCase() // 大文字小文字が１文字ずつ必要
         ->numbers() // １文字以上の数字入力が必要
         ->symbols() // １文字以上の記号が必要
         ->uncompromised() // 漏洩パスワードでないかチェックする
```
メッセージ例：
```php
'password' => [
    'letters' => ':attributeは1文字以上入力してください。',
    'mixed' => ':attributeには大文字と小文字をそれぞれ1文字以上含めてください。',
    'numbers' => ':attributeには数字を1文字以上含めてください。',
    'symbols' => ':attributeには記号を1文字以上含めてください。',
    'uncompromised' => '別の:attributeを入力してください。',
]
```

`uncompromised()`は個人情報が漏洩していないかを照会できるウェブサイト[Have I Been Pwned?](https://haveibeenpwned.com)に掲載されたメールアドレス＆パスワードであるかを確認しているらしい
ちなみに引数に数値を入力すると、チェック時エラーにする閾値を上げることが出来る

また、デフォルトルールの設定も可能
（複数ページで同じパスワードルールを利用したい場合に便利）
```php
Password::defaults()
```
設定は以下例のようにサービスプロバイダのbootメソッドに記載する
```php:Providers/AppServiceProvider.php
use Illuminate\Validation\Rules\Password;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Password::default(function () {
            return Password::min(8)->mixedCase()->numbers()->symbols()->uncompromised();
        });
    }
}
```
### ◆入力一致
確認用メールアドレス入力といった、別のエリアの入力値と比較したい場合に便利
```php:
'same:other' // otherは一致にしたい入力エリアのname値
```
メッセージ例：
`'same' => ':attributeが:otherと一致していません。'`

## エラーメッセージ日本語化
#### ① langファイルを用意する
デフォルトではlangディレクトリが無いので、まずは以下コマンドでインストールする
```:ターミナルで以下実行
php artisan lang:publish
```
#### ② langファイル直下のenフォルダをコピーし、名前をjaに変更する
#### ③ configの言語設定を書き換える
```php:config/app.php
'locale' => 'ja',
'fallback_locale' => 'ja',
```
#### ④ jaファイルを利用するように.envファイルのLOCALEを書き換える
```:.env
APP_LOCALE=ja
```

#### ⑤ validation.phpファイルの英文を日本語に書き換える
利用する予定のバリデーションエラーメッセージのみ書き換えればokです
```php:lang/ja/validation.php
return [
    'required' => ':attributeを入力してください',
    'attributes' => [ // :attributeに入るnameに紐づく文字列を指定する
        'name' => '名前',
        'name.*' => ':position番目の名前', // 同じnameが複数あり、何番目かを指定したい場合
    ]
];
```



対応する日本語は以下URLに一覧があったのですが、ページが404になってしまった...悲しい...:cry:
~~https://readouble.com/laravel/8.x/ja/validation-php.html~~




## Controllerクラスの設定
#### ① バリデーションルール参照のため、requestクラスを読み込む
```php:フォームのリクエストを受け取るコントロールクラスに記載
use App\Http\Requests\クラス名;
```
#### ② 対象メソッドの引数$requestの型に作成したクラス名を指定する
```php
public function メソッド名 (requestのクラス名 $request){
    // controllerでrequestの内容からエラーメッセージを返却したい場合の記載例
    // withErrorsの引数は配列で複数メッセージを送信可能
    if (!isset($request['name'])) {
        return back()->withErrors(['request_error' => 'エラーメッセージ'])->withInput();
    }
}
```
設定後post時にバリデーションチェックでエラーが発生した際に
自動でget画面へリダイレクトされる

## Viewでエラーメッセージを表示
#### ・全部まとめて表示したい場合
```php: bladeファイル
@if($errors->any())
    @foreach ($errors->all() as $error)
        {{ $error }}
    @endforeach
@endif
```
#### ・指定して表示したい場合
```php: bladeファイル
@error('name')
    {{ $message }}
@enderror
```

## おまけ
#### :paperclip: 自動リダイレクトを止める
バリデーションエラー時の自動リダイレクトに割り込みたいそんな時のため（？）のメモです
```php:requestクラス記載例
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class requestクラス名 extends FormRequest
{
    // バリデーションエラー時のリダイレクト処理をごり押しオーバーライド
    protected function failedValidation(Validator $validator){}

    // controllerでバリデーションデータ取得用の処理
    public function getValidator()
    {
        return $this->validator;
    }
}
```
返却されるValidatorオブジェクトについては以下サイトを参照していたんですが、
Laravel12リリース後あたりから404になってしまった...悲しい...:cry:
~~https://laravel.com/api/10.x/Illuminate/Validation/Validator.html~~
※例えばエラー有無判定はfails()、inputデータが欲しい場合はgetData()

```php:controllerクラス記載例
public function メソッド名(requestクラス名 $request) {
    // バリデーションデータ取得
    $error_message = $request->getValidator();

    // バリデーションAfterフック処理
    $error_message->after(function($error_message) {
    $get_data = $error_message->getData();
        // 実行したいチェックを記載
        if (!isset($get_data['name'])) {
            // エラーを返却
            $error_message->errors()->merge(['name' => ['message']]);
        }
    });
}
```
afterについては以下公式ドキュメントの「追加バリデーションの実行」を参照
https://readouble.com/laravel/10.x/ja/validation.html

## あとがき
ここまで閲覧してくれて感謝です！！
最初にまとめていた時期がLaravel10の段階だったので、ドキュメント関連は10のリンク置いている箇所があります:bow:

今後、新しいバージョンで書いた際に気づきがあれば追記するかもしれない...
なおリダイレクト割り込みは特殊枠だと思うんで多分あんま使わない...多分...