Laravel 9.18 新バリデーション方式の「invokable ルール」を試してみる
前書き
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のバージョンを追うごとに新しいのが出てきたりして、今までの方法も使えるものの、ドキュメントからは姿を消したりしていました。
で、今回もそうなりました。
今までは、
- 今までのルールオブジェクト
- クロージャー
の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 は不要なので付けません。
ということで、作成されたクラスをこんな感じで編集します。(コメント部分はカット)
<?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 は、下記の感じ
<?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 は、下記の感じ
<!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
WIP 砲 によって
InvokableRule
が非推奨になってました。InvokableRule
Rule
ともに非推奨となり,InvokableRule
の形を選択した(名前衝突を回避した)新しいValidationRule
というインタフェースに統一しようという方針のようです。コメントありがとうございます❗
そうですね。しれっと非推奨にされてしまいましたね😣
私も気付いていたのですが、記事の更新を怠っていたので、上の方で軽く補足しておきました。