9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ミライトデザインAdvent Calendar 2021

Day 20

Laravelの必須チェック系ルールオブジェクト

Posted at

この記事は ミライトデザイン Advent Calendar 2021 20日目の記事です。

Laravelでカスタムバリデーションを行うときに使うルールオブジェクトについて書いてみます。

TL;DR

ImplicitRule使おう

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\ImplicitRule;

class PmRequired implements ImplicitRule
{
    /**
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return now()->hour < 12 || $value !== null;
    }

    /**
     * @return string
     */
    public function message()
    {
        return ':attributeは午前中は必須です。';
    }
}

バージョン

  • Laravel 8.76.2

Laravelのルールオブジェクト

Laravelには標準で様々なバリデーションチェックの種類がありますが、独自のバリデーションルールを作成したいことがしばしばあると思います。
公式サイトによると、

  • ルールオブジェクトを使う
  • クロージャを使う
  • Validatorファサードのextendメソッドを使う

という方式が紹介されていますが、今回はルールオブジェクトについてのお話をします。

ルールオブジェクトの使い方

ルールオブジェクトの使い方としては、まずmake:ruleというArtisanコマンドを実行し、新規のルールオブジェクトを生成します。
今回は、奇数かどうかのチェックを行うためのOddNumberというルールオブジェクトを作ってみます。

php artisan make:rule OddNumber

上記のコマンドを実行すると、app/rules下にOddNumber.phpが作成されます。

OddNumber.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class OddNumber implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        //
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The validation error message.';
    }
}

出来上がったRuleクラスを修正することで独自のバリデーションルールを作成することができます。
passメソッドでvalueの値をチェックして、true / falseを返しましょう。

例えば奇数かどうかチェックする場合は下記のようにすればOKです。
(行数削減のために、phpdocとコンストラクタを除外しています。)

OddNumber.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class OddNumber implements Rule
{
    public function passes($attribute, $value)
    {
        return ctype_digit($value) && $value % 2 === 1;
    }

    public function message()
    {
        return ':attributeは奇数ではありません。';
    }
}

Ruleクラスを作成したら、ValidatorやFormRequestに設定することで、独自のバリデーションルールを使用できます。

use App\Rules\OddNumber;

$request->validate([
    'name' => ['required', 'string', new OddNumber],
]);

マニュアルや他記事でも詳しく紹介されているので、詳しく知りたい方はぜひ調べてみてください。

ルールオブジェクトは空値をチェックできないらしい

ここからが本題です。
例えば独自ルールとして、午後に入力必須となるバリデーションルールを作りたいとします。

さきほどと同じようにRuleを作成してみます。

php artisan make:rule PmRequired
AmRequired
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Carbon;

class PmRequired implements Rule
{
    /**
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return Carbon::now()->hour < 12 || ($value !== null && $value !== '');
    }

    /**
     * @return string
     */
    public function message()
    {
        return ':attributeは午後は必須です。';
    }
}
use App\Rules\PmRequired;

$request->validate([
    'name' => [new PmRequired],
]);

しかし、実際にテストしてみるとわかるのですが、このルールは午後に空文字列を渡してもエラーになりません。

これは、LaravelのRuleの仕様となっており、公式ドキュメントにも明記されています。

By default, when an attribute being validated is not present or contains an empty string, normal validation rules, including custom rules, are not run.

デフォルトでは、バリデーションされる属性が存在しないか、空の文字列が含まれている場合、カスタムルールを含む通常のバリデーションルールは実行されません。

空文字列でチェック処理が動かないと、必須チェック系のカスタムルールが作成できません。
どうすればいいのでしょうか。

解決方法

実は解決方法は公式ドキュメントに記載されています。

Ruleの代わりにImplicitRuleを継承することで、属性が存在しなかったり空文字列の場合もルールオブジェクトによるチェックが行われるようになります。

作成方法は、artisanコマンドでRuleを作成するときに--implicitオプションを付けることです。

php artisan make:rule PmRequired --implicit

先ほどと同じようにapp/Rules下にファイルが作成されています。
先ほどとの違いは、継承元のクラスがIlluminate\Contracts\Validation\RuleではなくIlluminate\Contracts\Validation\ImplicitRuleになっていることです。

PmRequired.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\ImplicitRule;

class PmRequired implements ImplicitRule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        //
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The validation error message.';
    }
}

このクラスを修正し、先ほどと同じように午後に必須チェックが行われるようにします。

PmRequired.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\ImplicitRule;
use Illuminate\Support\Carbon;

class PmRequired implements ImplicitRule
{
    /**
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return Carbon::now()->hour < 12 || ($value !== null && $value !== '');
    }

    /**
     * @return string
     */
    public function message()
    {
        return ':attributeは午後は必須です。';
    }
}

これで無事に必須チェック系のルールオブジェクトが作成できました。

参考にしたサイト

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?