0
votes

I've got a password reset form for my Cake2.4 app, which is giving me some validation problems.

When I try to do a simple save on the user, I run up against a validation error that the email address is not unique- even though I'm just updating the user's password.

When I set $validate to false in my save, the form works fine. However, this skips ALL validation rules, including my password validation rules.

How do I do this save so that it doesn't complain about a non-unique email address, and still validates passwords properly?

The email address IS unique, and my controller action isn't trying to change it, as far as I can understand. Stipulating 'on create' in my model won't help- otherwise users can set their email address to someone else's.

public function reset_password($token = null) {

    if ($this->Session->read('Auth.User')) {
        $this->Session->setFlash(__('You\'re already logged in. Update your password here.'), 'flash/success');
        $this->redirect(array('action' => 'profile'));
    }

    if (!empty($token)){

        if ($user = $this->User->findBytoken($token)){
            $id = $user['User']['id'];
            $this->User->id = $id;
        }
        elseif (count($this->User->findBytoken($token) == 0)){
            $this->Session->setFlash(__('Your password reset link was invalid. Please request a new one'), 'flash/error');
            $this->redirect(array('action' => 'forgot_password'));
        }

        if (strtotime($user['User']['token_expires']) < strtotime('now')){
            $this->Session->setFlash(__('For your safety, your reset link has expired after 24 hours. Please request a new one'), 'flash/error');
            $this->redirect(array('action' => 'forgot_password'));
        }   

    } else {

        $this->Session->setFlash(__('You need a reset link to do that. Request one with your email address here.'), 'flash/success');
        $this->redirect(array('action' => 'forgot_password'));
    }

    if (!$this->User->exists($this->User->id)) {
        throw new NotFoundException(__('Invalid user'));
    }

    if ($this->request->is('post') || $this->request->is('put')) {
        $this->request->data['User']['token'] = null;
        $this->request->data['User']['token_expires'] = null;
        $this->request->data['User']['modified'] = false;
        unset($this->request->data['User']['image']);
        if ($this->User->save($this->request->data, $validate = false)) {
            $this->Session->setFlash(__('Your password has been updated. You can log in with your new password now'), 'flash/success');
            $this->redirect(array('action' => 'login'));
        } else {
            $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
            $this->set('user', $this->User->find('first', $options));
            $this->Session->setFlash(__('Your password could not be updated. Please, try again.'), 'flash/error');
        }
    } else {
        $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
        $this->set('user', $this->User->find('first', $options));
        $this->request->data = $this->User->find('first', $options);
    }
}
1

1 Answers

2
votes

From the CakePHP Docs http://book.cakephp.org/2.0/en/models/data-validation.html

The ‘on’ key can be set to either one of the following values: ‘update’ or ‘create’. This provides a mechanism that allows a certain rule to be applied either during the creation of a new record, or during update of a record.

If a rule has defined ‘on’ => ‘create’, the rule will only be enforced during the creation of a new record. Likewise, if it is defined as ‘on’ => ‘update’, it will only be enforced during the updating of a record.

public $validate = array(
    'email' => array(
        'rule1' => array(
            'rule'       => array('email'),
            'required'   => true,
            'allowEmpty' => false,
            'message'    => 'Email is invalid'
        ),
        'rule2' => array(
            'rule'       => 'isUnique',
            'required'   => true,
            'allowEmpty' => false,
            'on'         => 'create',
            'message'    => 'Email is not unique'
        )
);

Alternatively in the Controller you can turn off validation for just the email field and then not include it in the data to save.

$this->User->validator()->remove('email');
unset($this->request->data['User']['email']);

Also I highly recommend PasswordableBehavior