Laravelで入力値エラーチェック(validate)を実装する

# 目次
Laravelの記事一覧は下記
[PHPフレームワークLaravelの使い方](https://qiita.com/toontoon/items/c4d0371e504c37f6576e)

# Laravelバージョン
動作確認はLaravel Framework 7.19.1で行っています

# 前提条件
[eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)](https://qiita.com/toontoon/items/76fa7f8845b20776077c)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています


# エラーチェッククラスの作成
(1) コマンドラインで 
`cd sample`
`php artisan make:rule SampleRule`
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/app/Rules/SampleRule.phpが現れます

(2) /sample/app/Rules/SampleRule.phpに変数を追加し、コンストラクタ、passesメソッド、messageメソッドを修正します

```SampleRule.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class SampleRule implements Rule
{
    private $word = null;

    public function __construct($word)
    {
        $this->word = $word;
    }

    public function passes($attribute, $value)
    {
        if ($value === $this->word) {
            return true;
        } else {
            return false;
        }
    }

    public function message()
    {
        return trans('validation.SampleRule');
    }
}

```
passesメソッドがエラーチェック処理です
falseを返すとエラーがあったと判定されたことになります
messageメソッドはエラー時のエラーメッセージです。エラーメッセージとして指定したvalidation.SampleRuleはこの後(3)でvalidation.phpに記載します


(3) /sample/resources/lang/en/validation.phpに追記
SampleRule要素を追記
attributes要素配列にsample_input要素、single_array.sample_input要素、multi_array.*.sample_input要素追記

```validation.php
<?php

return [
‥‥
    'SampleRule' => ':attribute does not match the secret word.',
‥‥
    'attributes' => [
        'sample_input'               => 'sample word1',
        'single_array.sample_input'  => 'sample word2',
        'multi_array.*.sample_input' => 'sample word3',
    ],
‥‥
];
```
SampleRule要素が先ほど(2)でエラーメッセージとして指定したメッセージとなります
attributes要素配列のsample_input要素、single_array.sample_input要素、multi_array.\*.sample_input要素はHTMLのname属性値と論理名とのマッピングです。
single_array.sample_inputというのはsingle_array[sample_input]というname属性値
multi_array.\*.sample_inputというのはmulti_array[0][sample_input]、multi_array[1][sample_input]‥‥というname属性値に相当します
SampleRuleエラーメッセージの:attributeを置換します

# フォームリクエストの作成
上記で作成したRuleクラスを使うクラスを作成します
(1) コマンドラインで 
`cd sample`
`php artisan make:request SampleRequest`
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/app/Http/Requests/SampleRequest.phpが現れます

(2) SampleRequest.phpへ追記
`use App\Rules\SampleRule;`

(3) SampleRequest.phpのauthorizeメソッド、rulesメソッドを下記に修正

```SampleRequest.php

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'sample_input'               => [new SampleRule('sample'), 'required'],
            'single_array.sample_input'  => [new SampleRule('sample'), 'required'],
            'multi_array.*.sample_input' => [new SampleRule('sample'), 'required'],
        ];
    }
```

SampleRequestのauthorizeメソッドはこのリクエストを使用する権限があるかどうかチェックです。falseを返すとこのリクエストを使用するURLにはアクセスできなくなります

SampleRequestのrulesメソッドはこのリクエストで使用する入力値チェックを定義します

new SampleRuleというのは先ほど作成した入力値チェッククラスです

'required'というのはLaravelが提供してくれている入力値チェックです
Laravelが提供してくれている入力値チェックは下記を参照してください
[Laravel 7.x バリデーション 使用可能なバリデーションルール](https://readouble.com/laravel/7.x/ja/validation.html#available-validation-rules)

[ここから](https://readouble.com/laravel/7.x/ja/validation.html#rule-accepted)
[ここまで](https://readouble.com/laravel/7.x/ja/validation.html#rule-uuid)
書かれている英単語を使用できます
今回は
[必須 'required'](https://readouble.com/laravel/7.x/ja/validation.html#rule-required)
を使用しました
入力値を必須ではなく任意にしたい場合は
[NULL許可 'nullable'](https://readouble.com/laravel/7.x/ja/validation.html#rule-nullable)
を使用します

SampleRequestのrulesメソッドが返している配列の要素名はHTMLのname属性値です
single_array.sample_inputというのはsingle_array[sample_input]というname属性値
multi_array.\*.sample_inputというのはmulti_array[0][sample_input]、multi_array[1][sample_input]‥‥というname属性値に相当します
さきほどのresources/lang/en/validation.phpのattributes配列に対応します

# Controllerにメソッド追加
(1) /sample/app/Http/Controllers/SampleController.phpに下記を追記
`use App\Http\Requests\SampleRequest;`

(2) /sample/app/Http/Controllers/SampleController.phpにvalidation1メソッド、validation2メソッドを追記

```
    public function validation1()
    {
        return view('sample.validation1');
    }

    public function validation2(SampleRequest $request)
    {
        $data = [
            'msg' => '入力チェックOK',
        ];
        return view('sample.validation2', $data);
    }
```

validation2メソッドの引数が先ほど作成したSampleRequestになっています
これでvalidation2へのリクエストが来た時に、SampleController#validation2が呼び出される前にSampleRequest#rulesに書いたエラーチェックが実行されます
そこでエラーチェックに引っかかったらリダイレクトが実行され、
さらに、blade.phpでold関数が使えるように、入力値が次のユーザーリクエストの処理中だけ利用できるフラッシュデータとしてセッションに保存されます

(3) /sample/routes/web.phpに下記を追記
`Route::get('sample/validation1', 'SampleController@validation1');
Route::post('sample/validation2', 'SampleController@validation2');`

# viewの作成
(1) /sample/resources/views/sample/validation1.blade.phpファイル作成

```validation1.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>

        <form action="{{ url('sample/validation2') }}" method="post">
            @csrf
            @error('sample_input')
                @foreach ($errors->get('sample_input') as $error)
                    <div style="color:red;">{{ $error }}</div>
                @endforeach
            @enderror
            <div>sample word1<input type="text" name="sample_input" value="{{ old('sample_input') }}"></div>

            @error('single_array.sample_input')
                @foreach ($errors->get('single_array.sample_input') as $error)
                    <div style="color:red;">{{ $error }}</div>
                @endforeach
            @enderror
            <div>sample word2<input type="text" name="single_array[sample_input]" value="{{ old('single_array.sample_input') }}"></div>

            @error('multi_array.0.sample_input')
                @foreach ($errors->get('multi_array.0.sample_input') as $error)
                    <div style="color:red;">{{ $error }}</div>
                @endforeach
            @enderror
            <div>sample word3<input type="text" name="multi_array[0][sample_input]" value="{{ old('multi_array.0.sample_input') }}"></div>
            <input type="submit" >
        </form>

    </body>
</html>


```

`@error`は、指定した属性のバリデーションエラーメッセージがあるかを判定します
`$errors`は、Illuminate\Support\MessageBagのインスタンスです
`$errors->get`で指定した属性のバリデーションエラーメッセージを取得します


(2) /sample/resources/views/sample/validation2.blade.phpファイル作成

```validation2.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        {{$msg}}
    </body>
</html>

```

# 動作確認
`http://localhost/laravelSample/sample/validation1`

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238103/ceebc3b7-e752-cc23-99f3-2a523fb12702.png)
何も入力せず送信ボタンをクリックしてみる

![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238103/69675032-675d-dc79-b3cb-f0ce49b3047f.png)
SampleRuleとrequiredのチェック結果が出力される
requiredのエラーメッセージは/sample/resources/lang/en/validation.phpにあらかじめ記載されています

![c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238103/6c354e09-187d-e19f-8eae-52de17cdec05.png)
sampleではない文字列を入力して送信ボタンをクリックしてみる
SampleRuleのチェック結果が出力される

![d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238103/d8f50f39-b014-6e99-cc8c-62b4374d375a.png)
sampleという文字列を入力して送信ボタンをクリックしてみる

![e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238103/025c0833-7040-37dd-f44d-2df3e6edd94e.png)
validation2に遷移できました