gorogoroyasu

福岡の開発会社で働いている。

自作のValidatorを使う

CakePHPドキュメントには、 再利用可能なバリデーターを作成するという説明書きがあります。
PR を送るのは後回しにして 今回の記事では、その使い方を書いていこうと思います。

ドキュメントに書いてあるコードはこんな感じです。

namespace App\Model\Validation;

use Cake\Validation\Validator;

class ContactValidator extends Validator
{
    public function __construct()
    {
        parent::__construct();
        // バリデーションのルールを加える
    }
}

なるほど。ContactValidatorというバリデーターを作ることができるのかということがわかります。 つまり、この機能を使うと、

public function __construct()
{
    parent::__construct();
    $this
        ->scala('name')
        ->requirePresence('name')
        ->notBlank('name');
}

という書き方ができるようになります。

これをうまいこと呼ぶと、いつもモデルで書いているおなじみの、

class UsersTable extends Table
{
    public function validationDefault(Validator $validator)
    {
        $validator
            ->scala('name')
            ->requirePresence('name')
            ->notBlank('name');

        return $validator;
    }
}

が、

class UsersTable extends Table
{
    public function validationDefault(Validator $validator)
    {
        return $validator;
    }
}

というふうに書けそうです。 では、$validator を ContactValidator に変更するにはどのようにすればよいのでしょうか?

答えは、モデルの設定にあります。

use App\Validation\ContactValidator;

class UsersTable extends Table
{
    // この行を追加
    protected $_validatorClass = UsersValidator::class;

    public function validationDefault(Validator $validator)
    {
        return $validator;
    }
}

$_validatorClass というプロパティに呼び出したいValidator をセットします。 あとは、自動でいい感じに $validator が ContactValidator のインスタンスに差し替えられます。

これを使うと、明示的に宣言しつついい感じでValidation を隠蔽できます。 更に、Behavior を new する必要すらないので、テストが(前回よりも更に)書きやすい!

ちなみに、

public function validationAdd(Validator $validator)
{
    // default とは違う処理
    return $validator;
}

という処理を書きたいことがあります。 そんなときは、

use App\Model\Validator\UsersAddValidator;

class UsersTable extends Table
{
    protected function createValidator($name)
    {
        if ($name == 'add') {
            $this->_validatorClass = UsersAddValidator::class;
        }
        return parent::createValidator($name);
    }
}

という感じで、$this->_validatorClass を上書きしてあげると良いでしょう。