Laravel 複数項目が全て必須の際、必須エラーメッセージは1つにまとめるカスタムルールを作りつつ、Ver.9.2の新機能も確認してみる
まえがき
ギュウさんのツイッターの呟きで、「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