🗨️

Laravel 複数項目が全て必須の際、必須エラーメッセージは1つにまとめるカスタムルールを作りつつ、Ver.9.2の新機能も確認してみる

2022/02/24に公開

まえがき

ギュウさんのツイッターの呟きで、「Ver.9.2からカスタムルール使用時、エラーメッセージの指定が容易になった」というありがたい事を知ったので、これを早速試してみました。

という事で、カスタムルールの作成が必要になりますので、以下のような感じのものを作ってみます。

カスタムルール

例えば、住所にしても電話番号にしても、同じグループなんだけど、項目的には分かれていて、且つ全てが必須という事はよくあります。

例えば、pref、city、address1と項目があって、どこにも入力しないで送信すると、

「都道府県を入力して下さい」
「市区町村を入力して下さい」
「番地入力して下さい」

みたいに表示されたりしますが、3つ位ならまだしも、こういうのが5つとかあると、やや目が痛くなります。いっそ、「住所を全て入力して下さい」とまとめたくなります。

私の認識では、そういう便利なルールは Laravel 標準では存在しないと思いますので、カスタムルールを作ってみました。

では、まずは使い方から。foo1、foo2、foo3 という項目があって全てが必須の場合、以下の感じで指定します。(もちろん名前空間はインポートして下さい)

[
    'foo1' => new AllRequired('foo2', 'foo3');

    // 引数は配列形式もOK
    'foo1' => new AllRequired(['foo2', 'foo3']);
];

foo1が代表役となる感じで、これは、パラメータには指定しません。
で、今まではカスタムメッセージを設定する際は、個人的には以下のような感じでやっていました。

[
    'foo1' => (new AllRequired('foo2', 'foo3'))->setMessage("fooは、全て必須ですよ。");
];

まぁ、嫌いではなかったのですが、Ver.9.2 以降は、setMessage() とか自作しなくても、例えば、FormRequest なら、以下の感じでいけます。

    public function messages()
    {
        return [
            AllRequired::class => 'fooは、全て必須ですよ。',
        ];
    }

いい感じですね。

参考:[9.x] Allow specifiying custom messages for Rule objects #41145

ソースは以下の感じ

以下の感じとなりました。

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ImplicitRule;

class AllRequired implements ImplicitRule, DataAwareRule
{
    protected array $others = [];

    protected array $data = [];

    protected string $message = ":attributeを入力してください。";

    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct($others)
    {
        $this->others = is_array($others) ? $others : func_get_args();
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $fields = array_merge([$attribute], $this->others);

        foreach($fields as $field) {
            if (! isset($this->data[$field]) || blank($this->data[$field])) {
                return false;
            }
        }

        return true;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return $this->message;
    }

    /**
     * エラーメッセージを設定する
     *
     * @param string $message
     * @return object $this
     */
    public function setMessage($message)
    {
        $this->message = $message;

        return $this;
    }

    /**
     * Set the data under validation.
     *
     * @param  array  $data
     * @return $this
     */
    public function setData($data)
    {
        $this->data = $data;

        return $this;
    }
}

ざっくり解説ですいませんが、一部補足させていただきますと、

  • ImplicitRule を実装しています。これで、仮に項目が飛んで来なくても(nullでも)、validation が走ってくれます。

  • Ver8.42で追加された DataAwareRule を実装しています。これで検証対象となるデータを取得しています。

で、上記にある setMessage() のようなやり方は、今後はしなくても良くなる訳ですね。

雑感

少し便利になりました。

一応、次回は上に少し味付けして、テストコードも作ってみようと思います。

問題箇所等ありましたらコメント下さい。

Discussion