How To Prevent Updating For Some Fields/attributes

Here is the thing:

Admin can create and update users. Form will provide fileds for username, password, password repeat, email, and user role. When admin want to update some user, it would be nice of he do not need to update password too, since password is hashed in database, and admin may not know what is user’s password. For example admin just want to update user role. The problem is I can not manage to make that happen. I made password and password repeat field not required on update, and I can save new user credentials, but update action is also saving new password ( nothing ), so user can not log in anymore. If I change password too, then everything works, but it would be nice if model will save new password only if it is enetered in form, if it is not, it shouldn’t. In non yii site I make this quite easy, but with yii I have problem, and I do not know why.

here are the rules in user model:




public function rules()

{

  return array(

    array('username, email, type', 'required'),

    array('password', 'required', 'on' => 'insert'),

    array('username', 'length', 'max' => 55),

    array('password', 'length', 'max' => 55),

    array('email', 'length', 'max' => 128),

    array('email, username', 'unique'),

    array('email', 'email'),

    array('type', 'length', 'max' => 6),

    array('password', 'compare', 'on' => 'insert'),

    array('password_repeat', 'safe', 'on' => 'insert'),

    array('id, username, password, email, type, profile', 'safe', 'on' => 'search'),

  );

}



and this is update action from user controller:




public function actionUpdate($id)

{

  $model = $this->loadModel($id, 'User');

		

  Yii::app()->authManager->revoke($model->type, $id);


  if (isset($_POST['User']))

  {

    $model->setAttributes($_POST['User']);

		

    if ($model->save())

    {

	$this->redirect(array('view', 'id' => $model->id));

    }

  }


  $this->render('update', array(

     'model' => $model,

  ));

}



Also I am using beforeSave for password hashing in user model:




public function beforeSave()

{	

  $this->password = User::hashPassword($this->password);

  return parent::beforeSave();

}



I have tried manualy assigning form submitted data to model attributes, and checking if password field is not empty to prevent empty password to be set, but it didn’t worked.

What is the catch ?

Don’t hash password in beforeSave - it’s just complicate everything.

Try use something like that:


public function actionUpdate($id)

{

  $model = $this->loadModel($id, 'User');


  $old_user = $model;


  $model->password = '';

                

  Yii::app()->authManager->revoke($model->type, $id);


  if (isset($_POST['User']))

  {

    $model->setAttributes($_POST['User']);

  

    if(empty($model->password))

      $model->password = $old_user->password;

    else 

      $model->password = User::hashPassword($model->password);

                

    if ($model->save())

    {

        $this->redirect(array('view', 'id' => $model->id));

    } else {

      $model->password = $_POST["User"]["password"];

    }

  }


  $this->render('update', array(

     'model' => $model,

  ));

}

If I do not provide password when saving, this will save nothing as a password. Password field in database will be set to blank. :(

Solution would be not to update password field at all, but I can not manage to do this with yii, I would have to write manual sql for this, and I’m trying not to… One more thing that confuses me is that when I do manual attribute assignment ( don’t include password form fields ), it still saves something that breaks user.

No, check the code. When password field is empty, then password is not changing - old password is used.


    if(empty($model->password))

      $model->password = $old_user->password;



I have tried, it doesn’t work as I said before…

That’s weird. Are you sure, that user password is not empty before user update? Or you don’t have other magic, that can set empty password?

I just checked variables with few echo + die().





$old_user = $model;

		

echo $old_user->password;

die();




displays old password, so that is working.

But in before save if I try to display password, when I do not enter anything in form field it displays nothing:




public function beforeSave()

{	

  //$this->password = User::hashPassword($this->password);

		

  echo $this->password;

  die();

  return parent::beforeSave();

}



So the problem is that in the meantime something set $model->password to nothing, event if there is no code that is doing it :o. There is no other method working with update / passwords/ whatever … than this one. Maybe my model rules are not right ? idk…

this is where it breaks, it displays nothing:




if (empty($model->password))

{

    $model->password = $old_user->password;

				

    echo $model->password;

    die();

}



If I submit something as password it will display hashed password…


public function actionUpdate($id)

{

  $model = $this->loadModel($id, 'User');


  $old_password = $model->password;


  $model->password = '';

                

  Yii::app()->authManager->revoke($model->type, $id);


  if (isset($_POST['User']))

  {

    $model->setAttributes($_POST['User']);

  

    if(empty($model->password))

      $model->password = $old_password;

    else 

      $model->password = User::hashPassword($model->password);

                

    if ($model->save())

    {

        $this->redirect(array('view', 'id' => $model->id));

    } else {

      $model->password = $_POST["User"]["password"];

    }

  }


  $this->render('update', array(

     'model' => $model,

  ));

}

Try that. “$old_user = $model;” creates only reference to $model, so this is still the same object. It’s too late hour for me, my brain stops working :P

use this in beforeSave.




beforeSave()

{

if($this->isNewRecord)

{

// do ur encryption here


}

return parent::beforeSave();

}



Yeah, now it is working, I don’t know how I didn’t saw it too :D

Thanks for helping!

And thank you Ahamed also, I’m using your solution when creating new records. When updating, I’m doing hashing manually as rob006 suggested, to avoid mess.

If i have done validation for password like max 20 then it don’t allow me to create passsword and display error like this

and also populate the password field with encrypted one.

Password is too long (maximum is 20 characters).

Thanks @rob006

I don’t want to update password field while edit user profile.

it worked for me and helpful to someone.

User.php model


protected function beforeSave() {

             

            if($this->isNewRecord){ // Create

               $this->password = md5($this->password);

            }

             else{  // Update

                 

             if($this->password && $this->password != $this->current_password)

                  $this->password = md5($this->password);

             else

                $this->password = $this->current_password;

        }




     return parent::beforeSave();

}

UserController.php controller


public function actionUpdate($id){

                

      $model=$this->loadModel($id);

      

      $model->current_password = $model->password; //<-----assign password to [b]$current_pasword[/b] while updating


      // Uncomment the following line if AJAX validation is needed

      $this->performAjaxValidation($model);


      if(isset($_POST['User']))

      {

	 $model->attributes=$_POST['Merchant'];

	 if($model->save()){

         

              $this->redirect("profile");                            

         }

      }


       $this->render('editprofile',array(

	 	'model'=>$model,

       ));


}