Edited at

CakePHP3.6 validationの実行の順番は下から行われている

More than 1 year has passed since last update.

ユーザ登録をする際に、18歳未満の人は登録できないようにしたかったのですが、 バリデーションの順番でエラーになってしまった。


元のコード


src/Model/Table/UsersTable.php

<?php

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\Database\Schema\TableSchema;
use DateTime;

class ProfilesTable extends Table
{

public function validationDefault(Validator $validator)
{
$validator
->date('birthday')
->requirePresence('birthday', 'create')
->notEmpty('birthday', '生年月日を入力してください')
->add('birthday', [
'date' => [
'rule' => function ($value, $context) {
return (bool) preg_match('/^([1-9][0-9]{3})\/(0[1-9]{1}|1[0-2]{1})\/(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})$/', $value);
},
'message' => '生年月日はYYYY/MM/DDの形式で入力してください'
],
])
->add('birthday', [
'date' => [
'rule' => function($value, $context){
$birthdate = new DateTime($value);
$today = new DateTime();
$interval = $today->diff($birthdate);

return (bool) ($interval->y > 18);
},
'message' => '18歳未満の方は登録できません',
],
]);


YYYY/MM/DDの形式かどうかと18歳以上かどうか確認したい。

この時、1984/11/のような入力をするとエラーになってしまう。

DateTime::__construct(): Failed to parse time string (1984/11/) at position 4 (/): Unexpected character

18歳未満かどうか調べる時にもYYYY/MM/DDの形式かどうか調べてもいいのですが、それだとYYYY/MM/DDの形式でないときにエラー文が18歳未満の方は登録できませんになってしまうので、あまり良くない。

調べた結果、下から順番にバリデーションが行われていたので順番を変えてみた。


修正コード(順番を変えた)


src/Model/Table/UsersTable.php

<?php

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\Database\Schema\TableSchema;
use DateTime;

class ProfilesTable extends Table
{

public function validationDefault(Validator $validator)
{
$validator
->date('birthday')
->requirePresence('birthday', 'create')
->notEmpty('birthday', '生年月日を入力してください')
->add('birthday', [
'date' => [
'rule' => function($value, $context){
$birthdate = new DateTime($value);
$today = new DateTime();
$interval = $today->diff($birthdate);

return (bool) ($interval->y > 18);
},
'message' => '18歳未満の方は登録できません',
],
])
->add('birthday', [
'date' => [
'rule' => function ($value, $context) {
return (bool) preg_match('/^([1-9][0-9]{3})\/(0[1-9]{1}|1[0-2]{1})\/(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1})$/', $value);
},
'message' => '生年月日はYYYY/MM/DDの形式で入力してください'
],
]);


とりあえず、エラーにはならなくなった。

JUST HACK IT!