バリデータをチェーンするmyChainValidator
よくあるパターンとして
・パスワード入力フォームで、パスワードを変更する場合はチェックをいれてパスワード入力欄に入力する
というとき
<input type="checkbox" name="change_password" value="1" /> パスワードを変更する <br /> <input type="password" name="password1" /> <input type="password" name="password2" /> ※確認用
という感じのフォームになると思うのですが、この場合バリデータで検証させるルールは
change_password │ ├→ チェックなし → true └→ チェックあり ↓ パスワードチェック │ ├― passwrod1 ┬→ 入力なし → false | └→ 入力あり | ↓ └― password2 ─→ 同一性チェック ┬ 一致しない → false └ 一致する → true
という流れになると思います。
symfonyデフォルトのバリデータだけではymlでは表現しきれない(ActionのvalidateXXXではできますが)ので以下のようなカスタムバリデータを用意。
<?php class myChainValidator extends sfValidator { public function initialize ($context, $parameters = null) { parent::initialize($context); $this->setParameter('chain_error', 'chain error'); $this->getParameterHolder()->add($parameters); } public function execute (&$value, &$error) { if (!is_array($this->getParameter('chain'))) return false; $_params = array( 'required' => false, 'required_msg' => 'Required' , 'group' => null , ); $_ignore = explode(',', 'required,required_msg,group'); $context = $this->getContext(); $v = new sfValidatorManager(); $v->initialize($context); foreach ($this->getParameter('chain') as $name => $params) { $params = array_merge($_params, $params); $v->registerName( $name , $params['required'] , (isset($params['required']['msg'])) ? $params['required']['msg'] : $params['required_msg'] , null , $params['group'] , false ); foreach (array_keys($params) as $validator) { if (in_array($validator, $_ignore)) continue; $_validator = new $validator; $_validator->initialize($context, $params[$validator]); $v->registerValidator($name, $_validator); } } $v->execute(); return true; } }
バリデータ用のymlで
fields: change_password: myChainValidator: chain: password1: required: msg: 入力されていません password2: sfCompareValidator: check: password1 compare_error: 2つのバスワードが一致しません
と書けばとりあえず期待どおり動きます。
sfValidatorManagerのインスタンス作ったりしてるのであまり行儀は良くないけど割と使えます。