[CakePHP3][Validation]0と自然数のみ許可するValidationのかけ方

  • 5
    いいね
  • 0
    コメント

<編集 2016/12/15 10:21>
昨夜投稿した分ですが、あいてたので。。。
CakePHP3 Advent Calendar 15日目です。
<編集終わり>

小ネタです

CakePHP3 で、数値に自然数というValidation をかけたかったけど、ちょっとハマった。
ついでに、Validationが、内部でどんなことをやってるか見たことがなかったので見てみた。

自然数のValidation

$validator
    ->integer('hoge')
    ->requirePresence('hoge', 'create')
    ->notEmpty('hoge')
    ->naturalNumber('hoge', __('[FATAL] not a natural number.'));

これだけで、自然数のValidation はできる。
つまり、hoge が、 0 以外だったら false になる。

これは簡単だ。
ただ、これを探していた時に見た、
http://api.cakephp.org/3.1/class-Cake.Validation.Validation.html#_naturalNumber
に、

boolean $allowZero optional false
Set true to allow zero, defaults to false

と書いてあった。

盛大に意訳すると、自然数だけでなく、自然数と0 というValidation をかけることもできると書いてある。

なるほど。
それは面白い。

ということで、やってみた。

First Try

$validator
    ->integer('hoge')
    ->requirePresence('hoge', 'create')
    ->notEmpty('hoge')
    ->naturalNumber('hoge', true,  __('[FATAL] not a natural number.'));

だが、うまく動かない。
それどころか、メッセージも表示されない。

困った。

Second Try

$validator
    ->integer('hoge')
    ->requirePresence('hoge', 'create')
    ->notEmpty('hoge')
    ->naturalNumber('hoge', [true],  __('[FATAL] not a natural number.'));

なんとなく、配列にしてみた。
結果は何も変わらない。

ということで、よくわからないから中身を見てみた。
見たのは、
http://api.cakephp.org/3.1/class-Cake.Validation.Validation.html#_naturalNumber

にあるように、Cake\Validation\Validationの中。
(リンクは、Cake\Validation\Validation のAPIについて書かれている)

そして、その中に、ルールが書いてあった。

public static function naturalNumber($check, $allowZero = false)
{
    $regex = $allowZero ? '/^(?:0|[1-9][0-9]*)$/' : '/^[1-9][0-9]*$/';

    return static::_check($check, $regex);
}

なんか、ちゃんと書かれてるっぽい。
なんで動かないんだろう?

ということで、念のため First Try の形に戻して debug してみた。

$validator
    ->integer('hoge')
    ->requirePresence('hoge', 'create')
    ->notEmpty('hoge')
    ->naturalNumber('hoge', [true],  __('[FATAL] not a natural number.'));

public static function naturalNumber($check, $allowZero = false)
{
    debug($check);
    debug($allowZero);
    exit;
    $regex = $allowZero ? '/^(?:0|[1-9][0-9]*)$/' : '/^[1-9][0-9]*$/';

    return static::_check($check, $regex);
}

結果

1
false

ん? __('[FATAL] not a natural number.') すら来てない。

ということで、一度冷静になって考えてみた。
なんでだろう?

そして、ヒントはBake で出てくるコメントに書いてあった。

public function validationDefault(Validator $validator)

これ、見るところ違ったんじゃない?
Validator と 書いてあるではないか。
さっきまで見ていたのはValidation
そもそもメソッドチェーンができるのは、$validatorValidator のインスタンスだからのはず。
これは、何かヒントがあるに違いない!!!
ということで、場所を変更してCake\Validation\Validator を見た。
すると、書いてあるではないか!!!

public function naturalNumber($field, $message = null, $when = null)
{
    $extra = array_filter(['on' => $when, 'message' => $message]);

    return $this->add($field, 'naturalNumber', $extra + [
        'rule' => ['naturalNumber', false]
    ]);
}

あれ?
これ、ラッパーしてるだけみたい。
しかも、

->naturalNumber('hoge')

の形だと、$allowZeroオプションが強制的に false になるみたい。。。

つまり、そもそも今までやってたやり方では実現できなかったらしい。

ということで正解は、

->add('hoge', 'naturalNumber',
 [
     'rule' => ['naturalNumber', true],
     'message' => '自然数で入力してください'
]);

でした。

それにしても、Validator が中で return $this->add()してるとは思ってなかった。
面白かった。

以上、小ネタでした。

この投稿は CakePHP3 Advent Calendar 201615日目の記事です。