Symfony 1.4条件验证


Symfony 1.4 conditional validation

我有一个继承自sfGuardRegisterFormProfile表单

我有以下字段:

$this->useFields(
    array('first_name', 
          'last_name',
          'email_address',
          'country',
          'language',
          'current_password',
          'new_password',
          'password_again',
    )
);

必填字段为:

email_addresscountrylanguage

条件是:

  1. 如果email_address与当前email_address不相等然后检查它是否唯一,然后保存
  2. 如果current_password是用户的实际密码,则验证new_passwordpassword_again是否相等,并验证new_password是否不等于用户的实际口令

我只是不知道如何实现这个

编辑

感谢1ed您的示例有效,但问题是我加载了用户配置文件,并用实际登录的用户填充字段:'first_name', 'last_name', 'email_address', 'country', 'language',因此email_address字段将显示电子邮件地址:

//...
$this->widgetSchema['email_address']->setDefault($this->_user->getEmailAddress());
//...

如果用户不更改电子邮件,它将始终显示以下消息:

已经存在具有相同"email_address"的对象。

我只想跳过

此外,此$this->getObject()->checkPassword()不起作用,始终显示以下消息:

当前密码不正确。

我使用:

$this->_user=sfContext::getInstance()->getUser()->getGuardUser();

获取实际用户配置文件

EDIT2

再次感谢1ed

这很奇怪,我很沮丧,这就是的情况

  1. 我有一个"变通方法",但它不符合标准,我可以让它工作,但使用sfContext::getInstance()->getUser()->getGuardUser();,它将是更不必要的代码
  2. 如果我使用new ProfileForm($user)自动填充所有字段,这很好我不能setDefault()我不能设置nullempty任何字段,所以我不能使用doUpdateObject(),因为这个函数只在当前数据更新时工作,而且我测试了覆盖bind()save()等,但没有结果

email_address唯一性:您应该在模式中设置unique: true,在sfDoctrineGuardPlugin中默认情况是这样,所以在BasesfGuardUserForm中您应该已经看到一个唯一的验证器:sfValidatorDoctrineUnique(array('model' => 'sfGuardUser', 'column' => array('email_address'))

current_password:您应该为这个创建一个回调类型的后验证器

// in sfGuardRegisterForm::configure()
// these fields can be blank
$this->getValidator('current_password')->setOption('required', false);
$this->getValidator('new_password')->setOption('required', false);
$this->getValidator('password_again')->setOption('required', false);
// check the current password (this validator is not `required` by default)
$this->mergePostValidator(new sfValidatorCallback(array(
  'callback' => array($this, 'checkPassword'),
), array(
  'invalid' => 'Incorrect current password.'
)));
// add this method to the same form class
public function checkPassword(sfValidatorBase $validator, array $values, array $arguments)
{
  // if a new password is given check whether the old one is correct or not and rise an error if not correct
  if(0 != strlen($values['new_password']) && !$this->getObject()->checkPassword($values['current_password']))
  {
    throw new sfValidatorErrorSchema($validator, array(
      'current_password' => new sfValidatorError($validator, 'invalid')
    ));
  }
  return $values;
}

或者,您可以创建一个自定义的post-validator,但我认为没有必要。

编辑:

如果你想像密码字段一样显示空的电子邮件地址,请将其添加到你的表单类中:

// at form load remove the default value
protected function updateDefaultsFromObject()
{
  parent::updateDefaultsFromObject();
  if (isset($this['email_address']))
  {
    $this->setDefault('email_address', '');
  }
}
// before save remove empty email address
protected function doUpdateObject($values)
{
  if (isset($values['email_address']) && 0 == strlen($values['email_address']))
  {
    unset($values['email_address']);
  }
  parent::doUpdateObject($values);
}

我将尝试用有条理的术语来解释这一点,而不是给你一大块代码。。。。因此,首先,如果(email_addr!=current_email),您想要,如果这是真的,请继续执行如果(new_pass!=current_pass),则继续执行以确保if(new_pass==new_pass_again)/do代码:p

编辑:将这些if封装在:if(country!=NULL&&language!=NULL&&email_addr!=NULL)