Cakephp PHP WEB開発

[Cakephp4]カスタムバリデーションを実装する!

※本サイトはPR表記を含みます。

バリデーションはお問い合わせフォームなどの作成に欠かせないものです。Cakephpではモデルテーブル内に、各フォームに合わせたバリデーションを記述していきます。元々Cakephpに用意されているバリデーションメソッドで要件を満たすことができればよいのですが、場合によっては独自のバリデートが必要になるケースも多々あると思います。

カスタムバリデートの実際に記述し、それをコールしてみましょう。

 

step
1
CustomValidation.phpファイルを作成

場所は任意でよいのかも?ですが、とりあえずModel/Tableと密接するので、その配下にディレクトリとファイルを作成することにします。(少なくとも関連性がある場所がいい)

Model/Table/Validation という形でディレクトリを作成しましょう。

 

step
2
CustomValidationを記述してく

カスタムバリデートメソッドを CutomValidation.php 内で記述します。継承元はValidationになります。

<?php
declare(strict_types=1);

namespace App\Model\Validation;

use Cake\Validation\Validation;

/**
 * カスタムバリデーション
 */
class CustomValidation extends Validation
{
    /**
     * [独自validateルール関数] URLは正しいか?
     *
     * @param string $type 'pattern1' | 'pattern2'
     * @return bool
     */
    public static function validateCorrectUrl($data, $type, $context): bool
    {
        $params = self::getParamsFromUrl($data);
        if (!$params) {
            return false;
        }
        // 当該パターン以外ならfalse
        if ($type != 'pattern1' || $type != 'pattern2') {
            return false;
        }
        // 期待するパラメータが存在した場合はバリデート通過
        return true;
    }

    /**
     * urlからパラメータを抽出
     *
     * @param string $url URL
     * @return array|false [期待するURLのパラメータ]
     */
    private static function getParamsFromUrl($url)
    {
        // 正しいURLだった場合は各パラメータの値を返す
        // 略
    }
}

得にコードに意味はありません。(めんどくさいから最後略に...)

注意点としては、カスタムバリデート内の各メソッドにstaticが付与されていることです

例えば、もし、staticにせず、validateCorrectUrl() メソッド内に $this->getParamsFromUrl() という形で呼び出したら、

Using $this when not in object context ~

という形でエラーになります。

Cakephpドキュメントを見てみると、

カスタムバリデートを利用する際、
// クラス名を使います。メソッドは静的なものでなければなりません。
$validator->setProvider('custom', 'App\Model\Validation');

https://book.cakephp.org/4/ja/core-libraries/validation.html#adding-validation-providers

という感じで、メソッドは静的なものであることが明記されています。

ドキュメントにしっかり目を通せば、エラーに遭遇することもないでしょうけども。まあ、注意ということで。

 

step
3
テーブル内でカスタムバリデーションをsetProvider()で呼び出す

カスタムバリデートを利用するために、setProvider()で呼び出します。

    /**
     * entity生成時に作動するバリデーション
     *
     * @param \Cake\Validation\Validator $validator A Validator instance
     * @return \Cake\Validation\Validator
     */
    public function validationDefault(Validator $validator): Validator
    {
        $validator->setProvider('customValidation', 'App\Model\Validation\CustomValidation');

        $validator->add('correct_url', 'validateCorrectUrl', [
             'rule' => 'validateCorrectUrl',
             'provider' => 'customValidation',
             'message' => '正しいURLではありません',
        ]);
    }

ruleにカスタムプロバイダーメソッド、providerプロパティにsetProvider()で指定したプロバイダ名で呼び出すことができます。

カスタムバリデーションの定義の仕方と、その呼び出しについてはこれで大丈夫だと思います。

 

カスタムバリデーションに追加引数を渡したい場合

カスタムバリデーションメソッドに追加で引数を渡したい場合は、

 shortcode
'rule' => ['validateCorrectUrl', 'pattern1'],

という感じで、ruleプロパティを配列にしつつ、渡したい値を渡すことができます。

と、同時にどうやってカスタムプロバイダ内で受け取るのか?というと、

public function validateCorrectUrl($data, $type, $context): bool
{
    // $typeの第二引数で値を取得できる
    var_dump($type); // 'pattern1'
}

上記の様に第二引数で受け取ることができます。

 

カスタムバリデーションを任意テーブル内で定義しつつ呼び出す場合

別にカスタムバリデーションを外だし(外部ファイルでまとめる)するほどでもなくね?という場合もあるかと思います。

そのような場合、

// DefaultValidationメソッド内
$validator
    ->allowEmptyDate('fieldName')
    ->add('fieldName', 'fromTodayOn', [
        'rule' => [$this, 'fromTodayOn'],
        'message' => '本日以降の日付を入力してください。',
    ]);
}

// fromTodyOn()はpublicで定義すること
public function fromTodayOn()
{
   // 任意実装(検証)後、true or false
   return true;
}

ruleプロパティの配列第一引数を$thisとして自身を指定しておき、第二引数で fromTodayOn()を指定することで、同テーブル内に定義されたカスタムバリデーションメソッドをコールすることができます。

-Cakephp, PHP, WEB開発
-