Laravelでバリデーション処理

Laravelのバリデーションは失敗したら自動でリクエスト元にリダイレクトしてくれて便利です。
基本的な「コントローラーでバリデーション処理」とコントローラーから分離して「FormRequestでバリデーション処理」についてまとめておきます。

開発環境

Laravel 6.6.0

コントローラーでバリデーション処理

基本的な処理

Illuminate\Http\Requestオブジェクトのvalidateメソッドに設定するだけで失敗時に自動でリクエスト元にリダイレクトしてくれます。

$request->validate(array $rules, array $messages, array $attributes);

第1引数にルールの配列
 フィールド名をキーに複数指定できます
第2引数にエラーメッセージの配列
 :attributeをメッセージ内容に含めることで属性名を表示させることができます。
第3引数に属性名の配列
 エラーメッセージ表示でフィールド名を置き換えることができます。

第2引数、第3引数については設定しなければデフォルト値が用意されているので任意です。

public function store(Request $request)
{
	// Validation
	$validatedData = $request->validate([
		'name' => 'required|min:3|max:16|unique:users',
	],
	[
		// messages
		'name.required' => ':attributeは必須です。',
	],
	[
		// attributes
		'name' => '「お名前」',
	]
}

バリデーションルールの書き方は
上記コードのようにパイプ「|」を使用する方法

'name' => 'required|min:3|max:16|unique:users',

と配列で指定する方法

		'name' => [
			'required',
			'min:3',
			'max:16',
			'unique:users',
		],

があります。

使用可能なバリデーションルールについてはhttps://readouble.com/laravel/6.x/ja/validation.html#available-validation-rulesを参照してください。

View(Blade)でバリデーションエラー表示

  <form action="/test/store" method="POST">
    @csrf
    <div class="form-group">
      <label>お名前</label>
      <input type="text" name="name" class="form-control" value="{{ old('name') }}">	<!-- ※1/ -->
<!-- ※2 -->
@if ($errors->first('name'))
      <div class="text-danger">
        {{ $errors->first('name') }}
      </div>
@endif
<!-- /※2 -->
    </div>
    <button type="submit" class="btn btn-primary">送信</button>
  </form>

※1
バリデーションエラーによって入力された値はフラッシュデータとしてセッションに保存されold関数で取得できます。

※2
最初のエラーメッセージを取得してエラー表示しています。

[補足]
@errorディレクティブを使用してエラー表示もできます。

@error('name')
	  <div class="text-danger">
		{{ $message }}
	  </div>
@enderror

自動リダイレクトさせたくない場合

リクエスト元にリダイレクトする前に何らかの処理を行いたい場合もあります。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
// Validatorファサードを利用
use Validator;

class TestController extends Controller
{
	public function index()
	{
		// 
		return view('test');
	}
	public function store(Request $request)
	{
		// validatorを作成
		$validator = Validator::make($request->all(), [
			'name' => 'required|min:3|max:16|unique:users',
		]);
		
		// 失敗したら
		if ($validator->fails()) {
			return redirect('test')
						->withErrors($validator)
						->withInput();
		}
	}
}

FormRequestでバリデーション処理

コントローラーの引数に設定しているRequestオブジェクトを変更してリクエストの時点でバリデーション処理を行ってしまおうということですね。

リクエストクラスの作成

# php artisan make:request TestConfirmRequest

リクエストクラスの設定

	public function authorize()
	{
		return true;		// ※1
	}

	public function rules()
	{
		return [
			'name' => 'required|min:3|max:16|unique:users',
		];
	}
	public function messages()
	{
		return [
			'name.required' => ':attributeは必須です。',
		];
	}
	public function attributes()
	{
		return [
			'name' => '「お名前」',
		];
	}

※1 authorize()
リクエストでユーザ認証を判断するときに使用するメソッド。
falseを返せばHTTPレスポンス404を返すので使用できません。
ルーティングやコントローラーなど他でユーザ認証するならtrueを返しておきます。

コントローラーで使用していた$request->validateの引数がメソッドにするだけですね。
バリデーションルールの書き方もパイプと配列の両方が可能です。

コントローラーでの使い方

作成したFormRequestをインポートしてメソッドの引数にTestConfirmRequestオブジェクトを指定するだけです。

//作成したFormRequestをインポート
use App\Http\Requests\TestConfirmRequest;

//public function store(Request $request)
public function store(TestConfirmRequest $request)

自動リダイレクトしたくない場合

failedValidationメソッドをオーバーライドして無効化するとともにコントローラーで失敗時の処理を行うためValidatorを取得できるメソッドを追加しておきます。

	// @Override
    protected function failedValidation(Validator $validator)
    {
		// 自動リダイレクト無効化
//        throw (new ValidationException($validator))
//                    ->errorBag($this->errorBag)
//                    ->redirectTo($this->getRedirectUrl());
    }

	/**
	 * Validator取得
	 * return Illuminate\Contracts\Validation\Validator $validator
	 */
    public function getValidator()
    {
        return $this->validator;
    }

コントローラーで失敗時のリダイレクト処理

$validator = $request->getValidator();

// バリデーション失敗時の処理
if ($validator->fails()) {
	return redirect('/test')
		->withErrors($validator)
		->withInput();
}

まとめ

今回はnameだけですが通常はフィールドもルールも多くなりコントローラーが肥大化するのは必至なのでバリデーションはFormRequestを利用して分離してシンプルな構造にしたいものです。
FormRequestはRequestクラスを継承しているのでvalidationDataメソッドをオーバーライドしてリクエストの前処理をしたりwithValidatorメソッドで追加処理も可能なようです。