🍰

CakePHP2で独自のバリデーション関数を定義する

2020/09/25に公開

CakePHP (2.4.x) には豊富なバリデーション用の関数が用意されていますが、たまには自分で定義したいこともあります。しかしドキュメントの日本語訳は整備されておらず(2013/11/20現在)原本を読みながら進めても、どうもハマりから抜け出せない。そんなことが続いたので解決法をメモしておきます。

どこに定義するか

  • Modelクラス内(一番わかりやすい)
    • しかし独自バリデーションが増えると肥大化し厄介
  • 別の何かのクラス(ここで悩む)

今回は別の何かのクラスに定義する方法で進めます。

Behaviorを使う

英語版ドキュメントでは、'rule' => ['validationMethod', 'arg', 'className']のようなことをしていたので、てっきりここでクラス名を指定するものかと思いきやこれは間違いでした。これは国別のローカライズに対応するためのものと判り、今回の独自関数の件とは全く別物です。

独自バリデーション関数を、Modelを肥大化させずにまとめておくにはBehaviorが便利でしょう。

MyValidationBehavior.php
class MyValidationBehavior extends ModelBehavior
{
    // ルール定義
    public static function rules()
    {
        $rules = [
            'myField' => [
                'myRule1' => [
                    'rule' => ['myMethod1', 'arg'],
                ],
                'myRule2' => [
                    'rule' => ['myMethod2', 'arg', 'arg2'], // 複数記述しても使われない
                ]
            ],
        ];
        
        return $rules;
    }

    // 独自バリデーション関数
    public function myMethod1($model, $check, $arg) {
        return true; // booleanを返す式
    }

    public function myMethod2($model, $check, $arg, $arg2) {
        return true;
    }
}

長ったらしいクラス名なんて嫌という方は、語尾のBehaviorのみ必須で、あとは自由に命名可能です。あまり頻繁に書くクラス名でもないので、私はFooValidationBehaviorと命名しています。

myMethod1($model, $check, $arg)の記法は要注意で、第1引数の'model'はBehavior内に宣言する関数すべてに必要な引数、第2引数`check`はフォームから与えられた文字列となり、これらを抜かすと動きません。第3引数はルール定義に宣言した値です。それ以降については単に値を書き足しても引数としては使用されないので、必要ならば第3引数に連想配列などを渡すのが分かりやすいかと思います。

MyModel.php
class MyModel extends AppModel
{
    public $name   = 'MyModel';
    public $actsAs = ['MyValidation']; // ここで上記Behaviorを宣言
    
    public function __construct()
    {
        parent::__construct();
        if (isset($this)) {
            $this->validate = MyValidationBehavior::rules();
        }
        return $this;
    }
}

モデル側ではpublic $actsAsの変数に配列でBehavior名を宣言します。このときCake側の規則によりBehaviorは不要です。

また、よくチュートリアルや解説ブログなどで、そのままpublic $validate = […];としている例が多いですが、こうなると非常に配列のネストが深くなり不快なので、__construct()を用意して、そこで代入しています。

管理を楽にするために独自バリデーション関数とルール定義はひとつのソース内に有ったほうがよいと考えました。


CakePHPは規則が多く微妙に不便と感じるところがありつつも、割となんとでもなるように作られているという印象です。複雑、肥大化しやすい部分はうまく切り分けて管理したいものです。

Discussion