Model password confirmation field.

I had some troubles with the password confirmation field for when adding updating user records, so i thought that i should share the way i got it working.

The scenario is the basic one, you have a database table (say user) and this table has a field called password, which is a sha1/md5/etc hash of the user password.

This is the workflow:
When you create a new user, the password needs to be hashed and saved, but when you update a user record, if the same scenario happens, we end up with a hash of the user hashed password, and we don't want this. Instead, on update, we will empty the user password from the model object, store it temporary in another variable then check to see if the password has been submitted in the form, if it was, it means the user password needs to be updated, therefore we need to hash the password(which is plain text now), if it wasn't submitted, then it means it doesn't need to be updated therefore, we restore it from the temporary variable.

So, here we go, the model:

<?php if ( ! defined('YII_PATH')) exit('No direct script access allowed');

class User extends CActiveRecord
{
    // holds the password confirmation word
    public $repeat_password;
    
    //will hold the encrypted password for update actions.
    public $initialPassword;
 
	/**
	 * @return array validation rules for model attributes.
	 */
	public function rules()
	{
		// NOTE: you should only define rules for those attributes that
		// will receive user inputs.
		return array(
            //password and repeat password
            array('password, repeat_password', 'required', 'on'=>'insert'),
            array('password, repeat_password', 'length', 'min'=>6, 'max'=>40),
            array('password', 'compare', 'compareAttribute'=>'repeat_password'),
            
		);
	}

	
	public function beforeSave()
	{
        // in this case, we will use the old hashed password.
        if(empty($this->password) && empty($this->repeat_password) && !empty($this->initialPassword))
            $this->password=$this->repeat_password=$this->initialPassword;

        return parent::beforeSave();
	}
    
    public function afterFind()
    {
        //reset the password to null because we don't want the hash to be shown.
        $this->initialPassword = $this->password;
        $this->password = null;
        
        parent::afterFind();
    }

    public function saveModel($data=array())
    {
            //because the hashes needs to match
            if(!empty($data['password']) && !empty($data['repeat_password']))
            {
                $data['password'] = Yii::app()->user->hashPassword($data['password']);
                $data['repeat_password'] = Yii::app()->user->hashPassword($data['repeat_password']);
            }

            $this->attributes=$data;
            
            if(!$this->save())
                return CHtml::errorSummary($this);

	     return true;
    }

}

When the user is created, we do it with the "insert" scenario, meaning that the password is required, but when we update it, we do it with the "update" scenario, meaning that the password is not required anymore, therefore when the form is submitted, the password fields can be empty, and the validation won't fail. This allows us to restore the hashed password from the temporary variable.

Just as a side note, here is how my controller methods looks:

public function actionCreate()
	{
		$user=new User('insert');

        $this->saveModel($user);
        
		$this->setViewData(compact('user'));
		$this->render('create', $this->getViewData());
	}

public function actionUpdate($id)
	{
	
        $user=$this->loadModel($id);
		$user->scenario='update';

        $this->saveModel($user);

        $this->setViewData(compact('user'));
		$this->render('update', $this->getViewData());
	}

protected function saveModel(User $user)
    {
        if(isset($_POST['User']))
		{
            $this->performAjaxValidation($user);
			$msg = $user->saveModel($_POST['User']);
			//check $msg here
		}
    }

And this is the rendering form:

<section>
        <?php echo $form->labelEx($user,'password'); ?>
		<div>
            <?php echo $form->passwordField($user,'password',array('maxlength'=>40)); ?>
            <?php echo $form->passwordField($user,'repeat_password',array('maxlength'=>40)); ?>
        </div>
        <?php echo $form->error($user,'password'); ?>
	</section>

Hope it helps :)

Chinese Version

8 0
19 followers
Viewed: 93 807 times
Version: 1.1
Category: How-tos
Written by: twisted1919
Last updated by: PashaL
Created on: Nov 25, 2011
Last updated: 11 years ago
Update Article

Revisions

View all history

Related Articles