標準のValidatorを拡張してカスタマイズする方法

拡張Validatorの組み込み

活用例
全体ルールで各フィールドにバリデーションエラーを1つのみ表示する
バリデーションエラーメッセージを共通化する
独自のバリデーションルールの読み込みを共通化する

拡張Validatorの組み込み

既存のValidatorを拡張したclassを作成します。

/src/Model/Validation/CustomValidator.php

<?php
declare(strict_types=1);

namespace App\Model\Validation;

use Cake\Validation\Validator;

/**
 * Validatorの拡張
 *
 * @link https://book.cakephp.org/4/ja/core-libraries/validation.html
 */
class CustomValidator extends Validator
{

}

このclassをModel/TableやForm以下のvalidationDefaultで読み込みます。

<?php
declare(strict_types=1);

namespace App\Model\Table;

use App\Model\Validation\CustomValidator;

    ………
    ……
    ………

    /**
     * Default validation rules.
     *
     * @param \Cake\Validation\Validator $validator Validator instance.
     * @return \Cake\Validation\Validator
     */
    public function validationDefault(Validator $validator): Validator
    {
        /** @var \App\Model\Validation\CustomValidator $validator */
        $validator = new CustomValidator();

        ………
        ……
        ………

        return $validator;
    }

各フィールドにバリデーションエラーを1つのみ表示する

CustomValidator.phpに下記を追記することで、各フィールドにバリデーションエラーを1つのみ表示するよう全体ルールを変更することができます。
[参考記事] 1つのフィールドにバリデーションエラーを1つだけ表示させる方法

    /**
     * 新しいルールをフィールドのルール セットに追加します。
     *
     * @param string $field The name of the field from which the rule will be added
     * @param array|string $name The alias for a single rule or multiple rules array
     * @param \Cake\Validation\ValidationRule|array $rule the rule to add
     * @throws \InvalidArgumentException If numeric index cannot be resolved to a string one
     * @return $this
     */
    public function add(string $field, $name, $rule = [])
    {
        // バリデーションエラーは各フィールドに1つのみ表示する
        if (!isset($rule['last'])) {
            $rule['last'] = true;
        }

        return parent::add($field, $name, $rule);
    }

標準の記法だと、全てのルールのオプションに'last' => trueを書く必要があります。
またbakeコマンドで生成されるコードでは、オプションを付けるために全てをaddメソッドに書き換える必要があります。

上記の方法だとこのような手間が1つで済みます。

$validator
    ->add('body', [
        'minLength' => [
            'rule' => ['minLength', 10],
            'last' => true,
            'message' => 'コメントには中身のある本文が必要です。',
        ],
        'maxLength' => [
            'rule' => ['maxLength', 250],
            'last' => true,
            'message' => 'コメントが長すぎることはできません。'
        ]
    ]);

// bakeで生成されるコードはオプションを付けるために全て書き換えが必要
$validator
    ->scalar('name')
    ->maxLength('name', 50)
    ->requirePresence('name', 'create')
    ->notEmptyString('name');

バリデーションエラーメッセージを共通化する

CustomValidator.phpに下記を追記することで、maxLengthのバリデーションエラーメッセージを共通で変更することができます。

    /**
     * 文字列の長さの検証ルールをフィールドに追加します。
     *
     * @param string $field The field you want to apply the rule to.
     * @param int $max The maximum length allowed.
     * @param string|null $message The error message when the rule fails.
     * @param callable|string|null $when Either 'create' or 'update' or a callable that returns
     *   true when the validation rule should be applied.
     * @see \Cake\Validation\Validation::maxLength()
     * @return $this
     */
    public function maxLength(string $field, int $max, ?string $message = null, $when = null)
    {
        if ($message === null) {
            $message = __('{0}文字以下で入力してください。', $max);
        }

        return parent::maxLength($field, $max, $message, $when);
    }

バリデーションエラーメッセージにフィールド名を追加したい場合には次のようにし、国際化i18n(多言語化)でフィールド名を変換します。
[参考記事] 国際化i18n(多言語化)

    /**
     * フィールド名を取得する
     *
     * @param string $field The name of the field.
     * @return string
     */
    private function getFieldName(string $field)
    {
        return __(ucwords(str_replace('_', ' ', preg_replace('/_id$/i', '', $field))));
    }

    /**
     * 文字列の長さの検証ルールをフィールドに追加します。
     *
     * @param string $field The field you want to apply the rule to.
     * @param int $max The maximum length allowed.
     * @param string|null $message The error message when the rule fails.
     * @param callable|string|null $when Either 'create' or 'update' or a callable that returns
     *   true when the validation rule should be applied.
     * @see \Cake\Validation\Validation::maxLength()
     * @return $this
     */
    public function maxLength(string $field, int $max, ?string $message = null, $when = null)
    {
        if ($message === null) {
            $message = __('{0}は{1}文字以下で入力してください。', $this->getFieldName($field), $max);
        }

        return parent::maxLength($field, $max, $message, $when);
    }

標準だと文字数でも型でもバリデーションエラーはほとんど「The provided value is invalid」です。
i18nのresources/locales/cake.potで定義されています。

これをそれぞれバリデーションの種類に合わせて変更するには全てのルールにメッセージを記述する必要があります。

上記の方法だとこのような手間が1ファイルで済みます。

$validator
    ->maxLength('name', 50, '文字数が多いです。')
    ->notEmptyString('name', '必須項目です。');

独自のバリデーションルールの読み込みを共通化する

CustomValidator.phpに下記を追記することで、
/src/Model/Validation/CustomValidation.php
のカスタムバリデーションを1箇所で読み込むことができます。

    /**
     * Constructor
     */
    public function __construct()
    {
        parent::__construct();

        $this->setProvider('customValidation', 'App\Model\Validation\CustomValidation');
    }

標準の記法だと、カスタムバリデーションを使う箇所全てに$this->setProvider()を書く必要があります。

関連記事

スポンサーリンク

chia wallet get_transaction トランザクションを取得する

ホームページ製作・web系アプリ系の製作案件募集中です。

上に戻る