简体   繁体   中英

How to manage password during update user profile in Yii2

I can add user successfully, For Password hashing I am using md5() But when I update user it is giving an error.

Here are the model rules:

public function rules()
{
    return [
        [['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status'], 'required'],
        ['email','email'],
        [['confirm'], 'compare', 'compareAttribute' => 'password','on'=>'create'],
        [['firstname', 'lastname', 'username', 'email', 'password', 'confirm', ], 'string', 'max' => 255],
    ];
}

In the form ie View, I am using following code:

<div class="form-group">
<?php
    if($case == 'create') { //this condition called when create user 
        echo $form->field($model, 'password')->passwordInput([
            'maxlength' => true,
            'placeholder' => 'Enter the Password',
        ]);
    }
    else { // during update
        echo $form->field($model, 'password')->passwordInput([
            'maxlength' => true,
            'placeholder' => 'Enter the Password',
            'value' => '',
        ]);
    }
?>
</div>

<div class="form-group">
    <?= $form->field($model, 'confirm')->passwordInput([
        'maxlength' => true,
        'placeholder' => 'Confirm Password',
    ]) ?>   
</div>

and in controller I am using following code:

public function actionUpdate($id)
{
    $model = $this->findModel($id);
    $case = "update";
    if ($model->load(Yii::$app->request->post())) {
        $model->save();
        return $this->redirect(['view', 'id' => $model->id]);
    }
    else {
        return $this->render('update', [
            'model' => $model,
            'all_users_array' => $all_users_array,
            'all_groups_array' => $all_groups_array,
            'case' => $case,
        ]);
    }
}

I am getting the error:

Undefined offset: 1 Failed to prepare SQL: UPDATE xbox_user SET password =:qp0, role =:qp1, modified =:qp2, status =:qp3 WHERE id =:qp4

Can anyone please let me what code should be modified there?

Thank you!

User Model

public function rules()
{
    return [
        [['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status'], 'required'],
        ['email','email'],
        [['password', 'confirm'], 'required', 'on' => 'create'],

        ['confirm', 'compare', 'compareAttribute' => 'password', 'message'=>"Passwords does not match." ],
        [['firstname', 'lastname', 'username', 'email', 'password', 'confirm', ], 'string', 'max' => 255],
    ];
}

Update Action

public function actionUpdate($id)
{
    $model = $this->findModel($id);
    $model->passowrd = '';
    $model->confirm = '';

    if ($model->load(Yii::$app->request->post())) {
        $model->role = $model->role[0]; 
        if (empty($model->password) || empty($model->confirm)) {
            $model->password = $model->getOldAttribute('password');
            $model->confirm = $model->getOldAttribute('confirm');
        }
        if ($model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }
    } else {
        return $this->render('update', [
            'model' => $model,
            'all_users_array'=>$all_users_array,
            'all_groups_array'=>$all_groups_array,
        ]);
    }
}

Form

<div class="form-group">
    <?= $form->field($model, 'password')->passwordInput(['maxlength' => true,'placeholder'=>'Enter the Password']) ?>
</div>
<div class="form-group">
    <?= $form->field($model, 'confirm')->passwordInput(['maxlength' => true,'placeholder'=>'Confirm Password']) ?>   
</div>

It is better to use scenarios in your case and use rules() too for other requirements, In Users.php model file write the following code:

public function scenarios(){
  $scenarios = parent::scenarios();
  $scenarios['create'] = ['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status', 'password','confirm'];
  $scenarios['update'] = ['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status'];
  return $scenarios;
}

/**
 * @inheritdoc
 */
public function rules()
{
    return [
        [['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status', 'password','confirm'], 'required'],
        ['email', 'filter', 'filter' => 'trim'],
        ['email', 'unique' ],
        ['email', 'unique' ,'targetAttribute' => 'email'],
        ['email', 'required'],
        ['email', 'email'],
        ['email', 'unique', 'targetClass' => '\common\models\Users', 'message' => 'This email address has already been taken.'],
        ['confirm', 'compare', 'compareAttribute'=>'password', 'message'=>"Passwords does not match." ],
        [['firstname', 'lastname', 'username', 'email', 'password', 'confirm', ], 'string', 'max' => 255],
    ];
}

In your views file use the following code:

<div class="form-group">
 <?php
  if($case == 'create'){
    echo $form->field($model, 'password')->passwordInput(['maxlength' => true,'placeholder'=>'Enter the Password']);
  }
  else{
    echo $form->field($model, 'password')->passwordInput(['maxlength' => true,'placeholder'=>'Enter the Password']);
 }
?>   
</div>
<div class="form-group">
    <?= $form->field($model, 'confirm')->passwordInput(['maxlength' =>true,'placeholder'=>'Confirm Password']) ?>   
 </div>

and in your controller file, UsersController.php use the following code:

public function actionUpdate($id)
{
  $model = $this->findModel($id);

  $model->scenario = 'update'; // calling scenario of update
  if ($model->load(Yii::$app->request->post())) {

        $req_array = yii::$app->request->post();
        $role  = $req_array['Users']['role'][0];

        $model->role = $role;
        if($req_array['Users']['password'] !== $req_array['Users']['confirm'])
        {
          $model->addError('confirm','Password and Confirm should be same.');
          $model->password = $req_array['Users']['password'];
          $model->confirm = $req_array['Users']['confirm'];
          return $this->render('update', [
              'model' => $model,
              'all_users_array'=>$all_users_array,
              'all_groups_array'=>$all_groups_array,
              'case'=>$case,
          ]);
        }
        elseif( ($req_array['Users']['password'] == $req_array['Users']['confirm']) && (!empty($req_array['Users']['password'])))
        {
          $model->password = MD5($req_array['Users']['password']);
          $model->save();
          return $this->redirect(['view', 'id' => $model->id]);
        }
        else
        {

          $model->save();
          return $this->redirect(['view', 'id' => $model->id]);
        }
      } else {
          $model->password = '';
          return $this->render('update', [
              'model' => $model,
              'all_users_array'=>$all_users_array,
              'all_groups_array'=>$all_groups_array,
              'case'=>$case,
          ]);
      }
    }

Using this code, you will not get error of required password in update, In case if you fill the password then process of confirm password and required will be run. Hope this helps for you.

I have my own basic User model i reuse for most projects, which handles updating new password or leaving the previous one if no password is provided by the update form. Also implements IdentityInterface so it can be used for login to the Application.

My basic User model:

<?php

namespace app\models;

use Yii;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;

class User extends ActiveRecord implements IdentityInterface {
    const SCENARIO_LOGIN = 'login';
    const SCENARIO_CREATE = 'create';
    const SCENARIO_UPDATE = 'update';

    // We use $hash to save the hashed password we already have saved in the DB
    public $hash;
    public $password_repeat;

    /**
     * @inheritdoc
     */
    public static function tableName() {
        return 'user';
    }

    /**
     * @inheritdoc
     */
    public function scenarios() {
        $scenarios = parent::scenarios();
        $scenarios[self::SCENARIO_LOGIN] = ['user', 'password'];
        $scenarios[self::SCENARIO_CREATE] = ['user', 'password', 'password_repeat', 'email', 'authKey'];
        $scenarios[self::SCENARIO_UPDATE] = ['user', 'password', 'password_repeat', 'email'];
        return $scenarios;
    }

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['user'], 'string', 'max' => 45],

            [['email'], 'string', 'max' => 45],
            [['email'], 'email'],

            [['password', 'password_repeat'], 'string', 'max' => 60],

            [['authKey'], 'string', 'max' => 32],

            [['user', 'password'], 'required', 'on' => self::SCENARIO_LOGIN],
            [['user', 'password', 'password_repeat', 'email'], 'required', 'on' => self::SCENARIO_CREATE],
            [['user', 'email'], 'required', 'on' => self::SCENARIO_UPDATE],

            // Generate a random String with 32 characters to use as AuthKey
            [['authKey'], 'default', 'on' => self::SCENARIO_CREATE, 'value' => Yii::$app->getSecurity()->generateRandomString()],

            [['password'], 'compare', 'on' => self::SCENARIO_CREATE, 'skipOnEmpty' => true],

            [['user'], 'unique'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels() {
        return [
            'id' => 'Id',
            'user' => 'User',
            'password' => 'Password',
            'authKey' => 'AuthKey',
            'email' => 'Email',
        ];
    }

    /**
     * @inheritdoc
     */
    public function beforeSave($insert) {
        if (parent::beforeSave($insert)) {
            if($insert) {
                $this->password = Yii::$app->getSecurity()->generatePasswordHash($this->password);
            }
            else {
                if(strlen($this->password) > 0) {
                    $this->password = Yii::$app->getSecurity()->generatePasswordHash($this->password);
                }
                else {
                    $this->password = $this->hash;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * @inheritdoc
     */
    public function afterFind() {
        $this->hash = $this->password;
        $this->password = '';
        parent::afterFind();
    }

    /**
     * @inheritdoc
     */
    public static function findIdentity($id) {
        return self::findOne($id);
    }

    /**
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $type = null) {
        throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
    }

    /**
     * @inheritdoc
     */
    public static function findByUsername($username) {
        $model = static::findOne(['user' => $username]);
        return $model;
    }

    /**
     * @inheritdoc
     */
    public function getId() {
        return $this->getPrimaryKey();
    }

    /**
     * @inheritdoc
     */
    public function getAuthKey() {
        return $this->authKey;
    }

    /**
     * @inheritdoc
     */
    public function validateAuthKey($authKey) {
        return $this->authKey === $authKey;
    }

    /**
     * Validates password
     *
     * @param string $password password to validate
     * @return boolean if password provided is valid for current user
     */
    public function validatePassword($password) {
        return Yii::$app->getSecurity()->validatePassword($password, $this->hash);
    }
}

This way you only need to use the corresponding scenario in your create , update and login actions:

$model->scenario = User::SCENARIO_LOGIN;
$model->scenario = User::SCENARIO_CREATE;
$model->scenario = User::SCENARIO_UPDATE;

First try this one

[['confirm'], 'compare', 'compareAttribute' => 'password','on'=>'create']

if not work then please follow the following steps create your scenario for updation and don't compare password Did you try scenarios.. i will give a simple example for user registration and user login i hope it will help you

<?php
class User extends Model
{
    public $name;
    public $email;
    public $password;
    public function rules(){
        return [
            [['name','email','password'],'required'],
            ['email','email'],
            [['name', 'email', 'password'], 'required', 'on' => 'register'],
            ];
    }
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios['login'] = ['name','password'];//Scenario Values Only Accepted
        return $scenarios;
    }
}
?>

Apply Scenario For Model See the below code, We added two ways of setting the scenario of a model. By default, scenario will support the model rules.

<?php
class UserController extends Controller
{
    // APPLY SCENARIOS
    // scenario is set as a property
    public function  actionLogin(){
        $model = new User;
        $model->scenario = 'login';
    }
    // scenario is set through configuration
    public function  actionRegister(){
        $model = new User(['scenario' => 'register']);
    }
}
?>

在此输入图像描述 在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM