3
votes

I have a Profile form that inherits from sfGuardRegisterForm

I have these fields:

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

Required fields are:

email_address, country and language

And the conditions are:

  1. If the email_address is not equal with the current email_address then check if it's unique then save it
  2. If the current_password is the actual password of the user then verify if new_password and password_again are equals and verify that the new_password is not equal to the actual password of the user

I just can't figure out in how implement this

EDIT

Thanks 1ed your example works but the problem is that I load the user Profile and I fill the fields: 'first_name', 'last_name', 'email_address', 'country', 'language' with the actual logged user so the email_address field will show the email address:

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

If the user dont change the email it will always show this message:

An object with the same "email_address" already exist.

I just want to skip that

Also this $this->getObject()->checkPassword() does not works, always show this message:

Incorrect current password.

I use:

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

To get actual user profile

EDIT2

Thanks again 1ed

This is very weird and I'm getting frustated, this is the situation

  1. I have a "workaround" for this but it does not follow the standard, I can make it works but using sfContext::getInstance()->getUser()->getGuardUser(); and it will be more unnecesary code
  2. If I use new ProfileForm($user) automatically fills all the fields, that's very good but I can't setDefault() I can't set null or empty any field so I can't use doUpdateObject() because this function only works when the current data is updated, also I have tested overriding bind(), save() etc. without results
2

2 Answers

5
votes

email_address uniqueness: you should set unique: true in schema, in sfDoctrineGuardPlugin that's the case by default, so in BasesfGuardUserForm you should see a unique validator already: sfValidatorDoctrineUnique(array('model' => 'sfGuardUser', 'column' => array('email_address'))

current_password: you should create a callback type post validator for this

// 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;
}

Alternatively you can create a custom post validator, but I think it's not necessary.

EDIT:

If you would like to display empty email address just like the password fields add these to your form class:

// 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);
}
0
votes

I'll try and explain this in methodical terms instead of giving you a big block of code.... So first, you want to if (email_addr != current_email) and if that's true, go on to do if (new_pass != current_pass) then follow on to make sure if (new_pass == new_pass_again) Inside all of these IFs, you can return a true/false or some kind of flag, or just //do code inside the brackets :p

EDIT: encase these IFs in: if (country != NULL && language != NULL && email_addr != NULL)