バリデーションの実例をちょっと休んで、実際にバリデーションを実行する部分を見てみます。お客さんのプロジェクトで最近この辺を詳しく見る機会があったので、皆さんと共有です。

一般的にはコントローラで使わるのですが、以下のようにいくつかあります。

リクエストのvalidate()メソッド

まず、代表的(5.5の時点で)なのがLaravelのドキュメンテーションの例としても使われている、Requestオブジェクトのメソッド、validate()。

...
public function store(Request $request)
{
    $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // The blog post is valid...
}

このvalidateでは、それだけで与えられたルールの配列をもとに入力値、この場合、$request->all()を判定して、問題があるなら、エラーメッセージと入力値とともに前のページに戻ります。

しかし、驚くことに、これはRequestのクラスのメソッドではありません!メソッドの形をしたマクロで、以下のファイルで定義されています(このマクロに関しては将来投稿を作成する予定です)。

<?php

namespace Illuminate\Foundation\Providers;

use Illuminate\Http\Request;
use Illuminate\Support\AggregateServiceProvider;

class FoundationServiceProvider extends AggregateServiceProvider
{
    /**
     * The provider class names.
     *
     * @var array
     */
    protected $providers = [
        FormRequestServiceProvider::class,
    ];

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        parent::register();

        $this->registerRequestValidate();
    }

    /**
     * Register the "validate" macro on the request.
     *
     * @return void
     */
    public function registerRequestValidate()
    {
        Request::macro('validate', function (array $rules, ...$params) {
            validator()->validate($this->all(), $rules, ...$params);

            return $this->only(collect($rules)->keys()->map(function ($rule) {
                return str_contains($rule, '.') ? explode('.', $rule)[0] : $rule;
            })->unique()->toArray());
        });
    }
}

コントローラのValidatesRequestsトレイトのvalidate()メソッド

先の例を使えば、以下のようになります。

...
public function store(Request $request)
{
    $this->validate($request,
        [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
       ]);
...
}

validate()の第1引数にリクエストのオブジェクトを渡します。こちらも、$request->all()を判定して、問題があるなら、エラーメッセージと入力値とともに前のページに戻ります。

このvalidateは、ValidateRequestsのトレイトのメソッドで、以下のようにコントローラの親クラスで宣言されています。


namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

Validatorクラス

上の2つが存在しなかった時代からLaravelをやってきている人たちにはこのやり方は馴染みあります。上の2つに比べてコードが長くなるものの、何をやっているか明確になります。

...
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // Store the blog post...
    }

バリデーターのオブジェクトを作成してから、判定作業(fails())を実行して、エラーならリダイレクトです。

validator()ヘルパー

最後に、Validator::make()を簡略化したヘルパー、validator()があります。

...
    public function store(Request $request)
    {
        $validator = validator($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        $validator->validate();
...

$validator->validate();これ、どこかで見たような。そう、最初のvalidateのマクロの定義の中で使用されています。

このようにバリデーションの実行にいろいろやり方があるのは、Laravelが進化を続けている証拠ですね。

By khino