概要
cakePHP4のバリデーションを動的に変更する方法(既存のルールをcontroller側で一時的に無効化する方法)について解説します。
例えば、ユーザー情報の登録、パスワード変更において以下のような要件があったとします。このとき、UsersTableのvalidationDefaultに設定済みのルールを動的に変更するにはどうしたら良いでしょうか?
- ユーザー追加時には現在のパスワードのチェックは不要
- ユーザー情報編集時に、パスワード欄に入力があれば、現在のパスワード、確認用パスワードをチェックする。
- ユーザー情報編集時に、パスワード欄に入力が無ければ、現在のパスワード、確認用パスワードをチェック不要。
前提環境
- Hosting Server: さくらインターネット
- PHP: 7.4.9
- cakePHP: 4.1.1
コードのポイント
動的にValidatorの設定を変更する方法はいくつか考えられますが、今回はあらかじめ必要な設定を全て記入し、必要に応じて設定を外していく方法を使用します。
controllerからvalidatorを取得するには「$this->(モデル名->getValidator();」を使います。
設定を外していくには「offsetUnset」を使用します。
サンプルコード
※注意!
本来ならばパスワードの文字数や確認用パスワードとの一致など、ルールがもっと必要ですが、サンプルコードのため除外しています。
/src/Model/Table/UsersTable.php
public function validationDefault(Validator $validator): Validator
{
$validator
->requirePresence('email')
->notEmptyString('email', 'メールアドレスは省略出来ません。')
->email('email', false, 'メールアドレスの形式ではありません。')
->requirePresence('username')
->notEmptyString('username', 'ユーザ名は省略出来ません。')
->requirePresence('password')
->notEmptyString('password', 'パスワードは省略出来ません。')
->requirePresence('password_check')
->notEmptyString('password_check', '確認用パスワードは省略出来ません。')
return $validator;
}
/src/Controller/UsersController.php
public function edit($id = null)
{
$user = $this->Users->get($id);
if ($this->request->is(['patch', 'post', 'put'])) {
// パスワードに入力があるか確認、パスワードがなければ更新対象としない。
if (empty($this->request->getData('password'))) {
// バリデーションのルールを解除する。
$this->offsetPasswordValidator();
// 更新対象からも外しておく
$user->setAccess('password', false);
} else {
$user->setAccess('password', true);
}
$user = $this->Users->patchEntity($user, $this->request->getData());
if ($this->Users->save($user)) {
$this->Flash->success(__('ユーザー情報の変更を保存しました。'));
return $this->redirect(['controller'=>'pages', 'action' => 'index']);
} else {
$this->Flash->error(__('ユーザー情報の変更の保存に失敗しました。もう一度お試しください。'));
}
}
// 編集画面表示時点ではパスワードの入力があるかどうかわからないので
// バリデーションのルールを解除する。
// ここで解除しないと、パスワードが必須のままになる。
$this->offsetPasswordValidator();
$this->set(compact('user'));
}
// バリデーションのルール解除用の関数。
// 複数回呼ばれるので関数にまとめた。
private function offsetPasswordValidator()
{
$validator = $this->Users->getValidator();
$validator->offsetUnset('password_now');
$validator->offsetUnset('password');
$validator->offsetUnset('password_check');
}