😸

[Laravel]バリデーションクラスを作成して、コントローラーから処理を切り離す[バリデーション]

2022/10/21に公開

altテキスト

SkinnyContollerを目指す

  • 環境

Amazon Linux 2
Composer version 2.3.9
Laravel Framework 9.19.0
PHP 8.0.18

上記のSkinnyControllerとはなにかと一言でいうと、

「Controller内にビジネスロジックは書かずに、Viewを返す責任のみを負うべき」

※単一責任の法則(クラスにも言えることです)

これを達成するためにいくつかの手法が存在します。


①DBに関するロジックは、モデルに入れて Eloquent を優先して使用する
②ビジネスロジックはサービスクラスの中に書いて、コンストラクタ or Facades で呼ぶ
③バリデーションはリクエストクラスに書く

今回は、③の「バリデーションはリクエストクラスに書く」の実施方法を書いていこうと思います。

Validation の書き方は3種類

Laravel 9.x バリデーション

Validation1Controller.php
public function store(Request $request)
{
	// リクエストデータの受け取り
	$data = $request->all();
	
	// バリデーションの実施
	$validated = $request->validate([
	  'title' => 'required|unique:posts|max:255',
	  'body' => 'required',
	]); // rulesは、 |:ヴァーティカルバー で区切るか []:配列 としても設定できます。
	
	return view();
}

Validation2Controller.php
// Validatorクラスを使用するため
use Illuminate\Support\Facades\Validator;

public function store(Request $request)
{
	// リクエストデータの受け取り
	$data = $request->all();
	
	// バリデーションの実施
	// ルールの設定
	$validation_rules = [
		'title' => 'required|string|max: 255',
		'age' => 'numeric',
	];
	
	// エラーメッセージのカスタマイズ
	$validation_message = [
		'required' => ':attributeは必須です',
		'title.string' => ':attributeが不正な値です',
		'age.max' => ':attributeは数値での入力をお願いします',
	];
	
	// 各リクエストの名称 >> エラーメッセージの:attributeに入る文字です。
	$validation_attribute = [
		'title' => 'タイトル',
		'age' => '年齢',
	];
	
	// バリデーションエラー発生時にリダイレクトする
	if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // バリデーション済みデータの取得
        $validated = $validator->validated();

        // バリデーション済みデータの一部を取得
        $validated = $validator->safe()->only(['name', 'email']);
        $validated = $validator->safe()->except(['name', 'email']);
	
	return view();
}


リクエストクラスを作成することで、コントローラーの処理が走る前にバリデーションを
実施するので、コードの可視性が向上する

リクエストクラスの作成,

$ php artisan make:request TestRequest

/App/Http/Request内に生成されます。

Validation3Controller.php

// リクエストクラスの呼び出し
use App\Http\Request\TestRequest;

public function store(TestRequest $request) // TestRequestを引数に設定する
{
	// バリデーション済みデータを取得
	$data = $request->all();
	
	return view();
}

TestRequest.php
<?php

namespace App\Http\Request;
// FormRequestを継承します。
use Illuminate\Foundation\Http\FormRequest;

class TestRequest extends FormRequest
{
     /**
     *  リダイレクト先の指定 
     *  $redirect       = '[Redirect url]'
     *  $redirectRoute  = '[Redirect Routing Name]'
     *  $redirectAction = '[Redirect to Controller Action]'
     * 
     *  動作するfunction >> 継承元の FormRequest::getRedirectUrl()
     * 
     */
    protected $redirect = '/post_top';
    protected $redirectRoute = 'post.post_top';
    protected $redirectAction = '';

    /**
     * Determine if the user is authorized to make this request.
     * ユーザーがこの要求を行うことを許可されているかどうかを判別
     *
     * @return bool
     */
    public function authorize()
    {
        // falseを返すと 403: This action UnAuthorized が返される
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     * リクエストに適用される検証ルールを定義:取得
     *
     * @return array<string, mixed>
     */
    public function rules()
    {
        return [
            'title' => 'required|string|max: 255',
	    'age' => 'numeric',
        ];
    }

    /**
     * 定義済みバリデーションルールのエラーメッセージ取得
     *
     * @return array
     */
    public function messages()
    {
        return [
            'required' => ':attributeは必須です',
	    'title.string' => ':attributeは不正な値です',
	    'title.max' => ':attributeは255文字以下です',
        ];
    }

    /**
     * バリデーションエラーのカスタム属性の取得
     *
     * @return array
     */
    public function attributes()
    {
        return [
            'title' => 'タイトル',
	    'age' => '年齢',
        ];
    }

    /**@Override FormRequest->validationData() : array
     * >> バリデーションの直前に前処理を挟む場合
     * 
     * @return array
     */
    public function validationData()
    {
        $data = $this->all();
	
        // 前処理:例えば全角英数字を半角に変換する
        // if (isset($data['name']))
        //    $data['name'] = mb_convert_kana($data['name'], 'a');
	
        return $data;
    }
}

エラーメッセージはどうやって受け取るのか

バリデーションエラー発生時にリダイレクトが行われます、
この時に withInput() を使用することによって、セッション情報に書き込まれます。

このバリデーションのセッション情報は、

session('_old_input');

で確認することができます。

TestRequest.php

~~~~~~~~~~
if ($validator->fails()) {
   return redirect('post/create')
	->withErrors($validator) // エラーメッセージ
	->withInput(); // >> session('_old_input')へ書き込み;
}

~~~~~~~~~~

  • blade.php での受け取り
post_top.blade.php
// 値の受け取りは、 old()ヘルパー
<input type="hidden" name="title" value="{{ old('title') }}">

// エラーメッセージを一括で受け取る
@if ($erros->any()) // エラーメッセージがあれば,,,
	@foreach ($erros->all() as $error) // foreachでエラー内容を表示
		<p>{{ $error }}</p>
	@endforeach
@endif

// 直接リクエスト名で関連するエラーメッセージを呼び出す
@error('title')
 // title.required でもいいですし、
 // title.* でtitleに関するエラーメッセージを全てという意味になります。
	<p>{{ $message }}</p>
@error

クロージング

次回は、サービスクラスへビジネスロジックを移動させる、Facades, ServiceProviderを利用した
簡易的な呼び出しを書いていこうと思います。

Discussion