🔥

Laravel 9.18 新バリデーション方式の「invokable ルール」を試してみる

2022/06/22に公開
2

前書き

Laravel 9.18.0 で、幾つか気になる新機能がリリースされました。そのうちの新しいカスタムルールの作成方法となる「invokable ルール」というのを試してみました。

参考リンク
GitHub: Introduce Invokable validation classes #42689
GitHub: Allow invokable rules to push messages to nested (or other) attributes #42801
GitHub: Standardise invokable rule translation functionality #42873
GitHub: Add invokable option to make rule command #42742
本家ドキュメント

本題の前に(Laravel Ver. 10 情報)

下記は、Laravel Ver. 9.18 時の記事になりますが、この記事を元にした記述では、Ver. 10 以降では、非推奨扱いな記述になります。Laravel 10 の場合は、make:rule コマンドで基本のテンプレートが生成されますので、そちらをベースとして利用するようにして下さい。

php artisan make:rule FooRule
php artisan make:rule BarRule --implicit

本題

そもそもカスタムルールの作成方法って、Laravelのバージョンを追うごとに新しいのが出てきたりして、今までの方法も使えるものの、ドキュメントからは姿を消したりしていました。

で、今回もそうなりました。

今までは、

  1. 今までのルールオブジェクト
  2. クロージャー

の2通りの方法がドキュメントには記載されていましたが、今回の新しい方法は、「ルールオブジェクト」の進化版的な感じですので、その「今までのルールオブジェクト」のドキュメントが消え、代わりにこの新しい「invokable ルール」がドキュメントに記載されました。

では早速

ということで、早速コマンドを使って invokable ルールのクラスを作成します。

今回は、name が yotaro でないとエラーになるというやや意味不明なバリデーションを作成します。

次のコマンドで作成します(--invokable を付けます)
(Laravel 10 では、--invokable は、付けません。デフォルトで invokable です)

php artisan make:rule NameRule --invokable

# もし implicit 版にしたい場合は、--implicit も追加します。
php artisan make:rule NameRule --invokable --implicit

--implicit を付けると、クラスに implicit というプロパティが加わり、implicit 版となりますが、今回は特に implicit は不要なので付けません。

ということで、作成されたクラスをこんな感じで編集します。(コメント部分はカット)

NameRule.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\InvokableRule;

class NameRule implements InvokableRule
{
    public function __invoke($attribute, $value, $fail)
    {
        if ($value !== 'yotaro') {
            $fail('あなたのお名前では入れません。');
        }
    }
}

(↑ Laravel 10 では、少しこの雛形周りが変わっています。特に、メソッド名が validate() になっています)

web.php は、下記の感じ

web.php
<?php

use App\Rules\NameRule;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Route::post('/', function (Request $request) {
    $request->validate([
        'name' => ['nullable', new NameRule],
    ]);

    return view('welcome');
});

welcome.blade.php は、下記の感じ

welcome.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイトル</title>
</head>
<body>

<h2>エラー内容</h2>
<ul>
    @foreach($errors->getMessages() as $key => $items)
    <li>
        {{ $key }}
        <ul>
            @foreach($items as $item)
            <li>
                {{ $item }}
            </li>
            @endforeach
        </ul>
    </li>
    @endforeach
</ul>

<form method="post">
@csrf

<input type="text" name="name">
<input type="submit" value="送信する">
</form>

</body>
</html>

これで、適当な名前を入力して送信すると、

  • name
    • あなたのお名前では入れません。

みたいにエラー表示されます。更に、$fail() は、続けて書いたりでき、例えば、

        if ($value !== 'yotaro') {
            $fail('あなたのお名前では入れません。');
            $fail('こんにちは、世界!');
        }

とかすると、

  • name
    • あなたのお名前では入れません。
    • こんにちは、世界!

のようになります。更に欲張って、config/app.php で、'locale' => 'ja', として、
lang/ja/validation.php に 'foobar' => 'ふーばー', と追加した上で、

        if ($value !== 'yotaro') {
            $fail('あなたのお名前では入れません。');
            $fail('こんにちは、世界!');
            $fail('validation.foobar')->translate();
        }

としたりすると、

  • name
    • あなたのお名前では入れません。
    • こんにちは、世界!
    • ふーばー

と表示されます。翻訳された訳ですね。まぁ、$fail(trans('validation.foobar')); とやっても同じです。

更に、$fail() の変わった使い方として、

        if ($value !== 'yotaro') {
            $fail('あなたのお名前では入れません。');
            $fail('こんにちは、世界!');
            $fail('validation.foobar')->translate();  // $fail(trans('validation.foobar')); と同じ

            $fail('email', 'それは無効です。');
        }

とすると、

  • name
    • あなたのお名前では入れません。
    • こんにちは、世界!
    • ふーばー
  • email
    • それは無効です。

と、name 以外のキーにエラーを割り当てる事ができます。

この $fail() は、クロージャー版でもあったりしますが、そちらのクロージャー版では、ここまで豪華な機能はまだありません。Laravel10で、同等機能が実装されます。
(今回書いた以外にも $fail() には、幾つかまだ機能があります)

以上になります。

雑感

開発されている @timacdonald さん、今かなりホットなようです❤️‍🔥

間違い等ありましたら、コメント下さい。

Discussion

mpywmpyw

WIP 砲 によって InvokableRule が非推奨になってました。InvokableRule Rule ともに非推奨となり,InvokableRule の形を選択した(名前衝突を回避した)新しい ValidationRule というインタフェースに統一しようという方針のようです。

nshironshiro

コメントありがとうございます❗
そうですね。しれっと非推奨にされてしまいましたね😣
私も気付いていたのですが、記事の更新を怠っていたので、上の方で軽く補足しておきました。