Laravelのバリデーションにおける基礎をまとめる

## 目標
**Laravelのバリデーションの基礎を知って、ある程度は使えるようにする**

## バリデーションって?
フォームなどの入力内容に対してエラーなどを表示する機能。
入力必須のフォームなのに、何も入力されてなかったらエラーメッセージなどを表示できるようになる。
こんな感じに(↓)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/cc6987fd-b037-a0db-d3ae-b7ce61b24848.png)



## バリデーション作成
### リクエストの作成
そもそも`バリデーション`とは機能。
その機能を使えるようにするファイルは`request`で作成する。

ターミナルで下記を実行して、バリデーションを使えるようにするリクエストファイルを作成する。

```
 $ php artisan make:request ValidationRequest(作成したいファイル名)
```

このコマンドを実行すると、`(プロジェクト名)\app\Http\Requests`にターミナルで入力したファイル名のリクエストファイルが作成される。

### リクエストファイルを解説

作成したリクエストファイルはこのようなコードが書かれている。

```(プロジェクト名)\app\Http\Requests\ValidationRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ValidationRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }
}
```

コメントアウトされている部分に説明があるように、実際のバリデーションのルールなどを記載していくのは、**`public function rules()`**の中。

**`public function authorize()`**は認証機能などを有効化している際、現在ページを操作しているユーザーが認証されたユーザーかどうかを判定するというもの。
デフォルトで`true`、有効化されているが、必要なければ`false`にしておく。

### バリデーションルールを作成する

今回は冒頭にあったユーザー検索画面のバリデーションルールを作成してみる。
バリデーションで確認される入力内容を設定するファイルはこんな感じ。
本当のファイル名は`search.blade.php`だが、見栄えのために`.php`ファイルとして見せる。

```search(.blade).php
<div class="card-header">
    ユーザー検索
</div>
<div class="card-body">
	<p>検索したいユーザーの情報を入力してください。</p>
	 <div class="search">
        <form method="post" action="result">
        	<div class="category">
        		<p>検索項目: </p>
        		<select name="search_category">
        			<option value="0" selected>選択してください</option>
        			@for($i = 0; $i < 4; $i++)
        			<option value="{{ $NAME[$i] }}">{{ $NAME[$i] }}</option>
        			@endfor
				</select>
        	</div>
        	<div class="word">
        		<p>検索ワード: </p>
        		<input type="text" name="search_word">
        	</div>
			<input type="submit" value="検索する">
            @csrf
        </form>
    </div>
```

そこまで重要じゃないので、`serch_category`というセレクターと`search_word`という入力フォームがあり、`result`にそれらの値が送られることを把握してもらえれば十分。

それらのフォームにおけるバリデーションとして、以下のようなルールを作成した。

```ValidationRequest.php
public function authorize()
{
    return true;
}

public function rules()
{
    return [
        'search_category' => 'not_in:0',
        'search_word' => 'required',
    ];
}
```

バリデーションルールは**`'バリデーション対象となるフォームのname' => 'バリデーションルール'`** という形で指定していく。
今回設けたルールを説明していく。

`search_category`の`not_in:0`は`value='0'以外の値を選択してください`というルール。
`search_word`の`required`は`入力必須`のルール。

他にも多様なルールがあるが、必要に応じて[公式ドキュメント](https://readouble.com/laravel/5.5/ja/validation.html)などを調べるのがオススメ。

### バリデーションルールを適用する

では、作ったルールを適用していく。
バリデーションルールを記載したリクエストファイルの適用先はコントローラーとなる。
そして、その適用されるコントローラーは値を入力するページのコントローラーではなく、**入力された値を受け取ったり、送られたりするページのコントローラー**である。
そのため、今回の例でいえば、フォームの送信先、`result`のコントローラーにバリデーションルールを適用していく。

```(プロジェクト名)\app\Http\Controllers\ResultController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests\SearchRequest;
use App\User;

class ResultController extends Controller
{
    public function result(SearchRequest $request)
    {
        $category = $request -> input('search_category');
        $word = $request -> input('search_word');
        $search_data = array(
        	'category' => $category,
        	'word' => $word
        );
        $user_data = User::where($category, 'like', "%$word%") -> get();
        return view('user/result',['Search' => $search_data, 'User' => $user_data]);
    }
}
```

適用するといっても、**`use App\Http\Requests\SearchRequest;`で作成したリクエストを宣言**して、**`result()`の中に`(SearchRequest $request)`を記入する**だけ。
こうすることで、`result()`の処理が実行される前に送信された値に対して`SearchRequest`が働き、ルールを満たしていなかったらその後の処理を行わず、その前の画面、入力画面へと戻される。
入力画面に戻される際、**`GET`メソッドでリダイレクトされる**ため、ルーティング処理などに注意が必要。


**バリデーションルールを適用するコントローラはデータを送られる側のコントローラー** である事を覚えておきたい。


### バリデーションエラーを表示する

このままページを動かしても、何も表示されず画面が変わらないだけなので、バリデーションルールを満たしていないことを伝える必要がある。
そのためにも、`~.blade.php`ファイルを次のように変更する。

```search(.blade).php

//中略
        	<div class="word">
        		<p>検索ワード: </p>
        		<input type="text" name="search_word">
        	</div>
			<input type="submit" value="検索する">
            @csrf
        </form>
         @if(count($errors) > 0)
	        <ul class="error">
	        @foreach ($errors->all() as $error)
	            <li>{{ $error }}</li>
	        @endforeach
	        </ul>
	    @endif
    </div>
```

バリデーションルールを満たしていない場合、`$errors`にエラーメッセージが格納される。
この状態でバリデーションルールを満たしていない場合、次のようにエラーが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218398/a945f200-4c7d-64e1-5dc0-27efce5694e1.png)

cssでエラーメッセージを赤くするように変更してあるが、これでバリデーション機能は実装することができた。

```style.css
.error{
  color: red;
  font-size: 15px;
}
```

## バリデーションのカスタマイズ
### エラーメッセージをカスタマイズする

バリデーションルールを満たしていない場合、エラーメッセージを表示できるようになったが、エラーメッセージが英語である。
日本語にしたいだけでなく、自分好みにカスタマイズしたい場合もあるだろう。
そのような場合は、次のようなコードを入力する。

```ValidationRequest.php

//中略

public function rules()
{
    return [
        'search_category' => 'not_in:0',
        'search_word' => 'required',
    ];
}

public function messages() {
    return [
        'search_category.not_in' => '検索カテゴリーを入力してください。',
        'search_word.required' => '検索ワードは20字以内で入力してください。',
    ];
}
```

エラーメッセージは**`messages()`**でカスタマイズできる。
その内容は、**`バリデーション対象のname.バリデーションルール => 表示したいメッセージ`**で宣言する。
今回はバリデーション対象の両方においてルールが1つずつしかないためこのような形になったが、複数のルールがある場合は以下のように宣言できる。

```SampleRequest.php
public function rules()
{
    return [
        'entry_name' => 'required|max:20|unique:user,name',
    ];
}

public function messages() {
    return [
        'entry_name.required' => '名前を入力してください。',
        'entry_name.max' => '名前は20字以内で入力してください。',
        'entry_name.unique' => 'この名前は既に利用されています。',
    ];
}
```

### エラーメッセージ表示場所のカスタマイズ

先程の写真ではエラーメッセージが一ヶ所にまとまっていたが、冒頭ではそれぞれの項目ごとにそれぞれのエラーメッセージが表示されていた。
そのような表示にしたいときは、次のようにコードを入力する。

```search(.blade).php

//中略

<form method="post" action="result">
	<div class="category">
		<p>検索項目: </p>
		<select name="search_category">
			<option value="0" selected>選択してください</option>
			@for($i = 0; $i < 4; $i++)
			<option value="{{ $NAME[$i] }}">{{ $NAME[$i] }}</option>
			@endfor
		</select>
	</div>
    
    @if($errors->has('search_category'))
    <div class="error">
        <p>{{ $errors->first('search_category') }}</p>
    </div>
    @endif
	
    <div class="word">
		<p>検索ワード: </p>
		<input type="text" name="search_word">
	</div>
    
    @if($errors->has('search_word'))
    <div class="error">
        <p>{{ $errors->first('search_word') }}</p>
    </div>
    @endif
	
    <input type="submit" value="検索する">
    @csrf
</form>

```

エラーメッセージを表示するコードについて説明していく。
**`@if($errors->has('バリデーション対象のname'))`**で、`バリデーション対象のname`に対してエラーメッセージが`$errors`に格納されているかを判断する。
格納されているようであれば、**`{{ $errors->first('バリデーション対象のname') }}`**で、対象における最初のエラーメッセージを表示するよう指定している。

ここまでのコードをファイルに反映させれば、冒頭の画像のようなバリデーション機能を利用できるようになる。

## バリデーションを更に使いこなす
### 入力値の保持

バリデーションルールを満たさない値が入力されても、その値をフォームなどに保持したい。
そのような際は、表示用のページのフォームなどに次のような`value`の設定をする。

```sample(.blade).php
<input type="text" name="name" value="{{ old('name') }}">
```

**`{{ old('バリデーション対象のname') }}`**を設定することで、バリデーションルールに満たさなくても値が保持される。

また、`old`関数では初期値を第二引数で指定できる。
その場合は、**`{{ old('バリデーション対象のname', '0') }}`**といった形になる。

## バリデーションをより使いこなす
- [Laravelでuniqueの対象から自分自身の値を外す方法](https://qiita.com/kaitaku/items/d38e9e498b094405dede)



## 参考文献

- [Laravelのバリデーションにはフォームリクエストを使おう](https://qiita.com/sakuraya/items/abca057a424fa9b5a187)
- [Laravel 5.5 バリデーション](https://readouble.com/laravel/5.5/ja/validation.html)
- [【Laravelメモ】バリデーションエラー時の入力フォームの値を保持するoldヘルパの使い方](https://naoya-ono.com/blog/laravel-old-helper/)
- [Laravelでログイン機能付きサイト作成 with XAMPP(1/4)　基礎学習編](https://qiita.com/kaitaku/items/e3f0b144b5eb182e9681)