0
votes

Right i am working on yii 2.0 trying to amend the login system. It works when the users are just a hand coded array. Instead i want to make this work from a database.

I will show you what the initial Model looks like:

<?php

namespace app\models;

class User extends \yii\base\Object implements \yii\web\IdentityInterface
{
public $id;
public $username;
public $password;
public $authKey;
public $accessToken;

private static $users = [
    '100' => [
        'id' => '100',
        'username' => 'admin',
        'password' => 'admin',
        'authKey' => 'test100key',
        'accessToken' => '100-token',
    ],
    '101' => [
        'id' => '101',
        'username' => 'demo',
        'password' => 'demo',
        'authKey' => 'test101key',
        'accessToken' => '101-token',
    ],
];

/**
 * @inheritdoc
 */
public static function findIdentity($id)
{
    return isset(self::$users[$id]) ? new static(self::$users[$id]) : null;
}

/**
 * @inheritdoc
 */
public static function findIdentityByAccessToken($token, $type = null)
{
    foreach (self::$users as $user) {
        if ($user['accessToken'] === $token) {
            return new static($user);
        }
    }

    return null;
}

/**
 * Finds user by username
 *
 * @param  string      $username
 * @return static|null
 */
public static function findByUsername($username)
{
    foreach (self::$users as $user) {
        if (strcasecmp($user['username'], $username) === 0) {
            return new static($user);
        }
    }

    return null;
}

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

/**
 * @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 $this->password === $password;
}
}

okay so as you can see it is working on the hand coded array called $users. So i have made a table called "Users" and made the columns id username password authkey and accessToken.

Hoping that it would do the same thing with a database table, however i am getting an error when i try to log in. This is my new code

 <?php

namespace app\models;

/**
 * This is the model class for table "Cases".
 *
 * @property integer $id
 * @property string $username
 * @property string $password
 * @property string $authkey
 * @property string $accessToken
 */
class User extends \yii\db\ActiveRecord
{


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

public function rules()
{
    return [
        [['id','username','password','authkey','accessToken'], 'required'],
        [['id'], 'integer'],      
    ];
}

/**
 * @inheritdoc
 */
public function attributeLabels()
{
    return [
        'id' => 'id',
        'username' => 'username',
        'password' => 'password',
        'authkey' => 'authkey',
        'accessToken' => 'accessToken',
    ];
}

























/**
 * @inheritdoc
 */
public static function findIdentity($id)
{
    return isset(self::$users[$id]) ? new static(self::$users[$id]) : null;
}

/**
 * @inheritdoc
 */
public static function findIdentityByAccessToken($token, $type = null)
{
    foreach (self::$users as $user) {
        if ($user['accessToken'] === $token) {
            return new static($user);
        }
    }

    return null;
}

/**
 * Finds user by username
 *
 * @param  string      $username
 * @return static|null
 */
public static function findByUsername($username)
{
    foreach (self::$Users as $user) {
        if (strcasecmp($user['username'], $username) === 0) {
            return new static($user);
        }
    }

    return null;
}

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

/**
 * @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 $this->password === $password;
}
}

The error message i am getting when i try to log in is "Access to undeclared static property: app\models\User::$Users".

If you need to see my LoginForm Model and Controller action i will post them underneath here.

public function actionLogin()
{
    if (!\Yii::$app->user->isGuest) {
        return $this->goHome();
    }

    $model = new LoginForm();
    if ($model->load(Yii::$app->request->post()) && $model->login()) {
        return $this->goBack();
    } else {
        return $this->render('login', [
            'model' => $model,
        ]);
    }
}

and LoginForm model is:

<?php

namespace app\models;

use Yii;
use yii\base\Model;

/**
* LoginForm is the model behind the login form.
*/
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;

private $_user = false;


/**
 * @return array the validation rules.
 */
public function rules()
{
    return [
        // username and password are both required
        [['username', 'password'], 'required'],
        // rememberMe must be a boolean value
        ['rememberMe', 'boolean'],
        // password is validated by validatePassword()
        ['password', 'validatePassword'],
    ];
}

/**
 * Validates the password.
 * This method serves as the inline validation for password.
 *
 * @param string $attribute the attribute currently being validated
 * @param array $params the additional name-value pairs given in the rule
 */
public function validatePassword($attribute, $params)
{
    if (!$this->hasErrors()) {
        $user = $this->getUser();

        if (!$user || !$user->validatePassword($this->password)) {
            $this->addError($attribute, 'Incorrect username or password.');
        }
    }
}

/**
 * Logs in a user using the provided username and password.
 * @return boolean whether the user is logged in successfully
 */
public function login()
{
    if ($this->validate()) {
        return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
    } else {
        return false;
    }
}

/**
 * Finds user by [[username]]
 *
 * @return User|null
 */
public function getUser()
{
    if ($this->_user === false) {
        $this->_user = User::findByUsername($this->username);
    }

    return $this->_user;
}
}

Can any one advise what i should do , once again the error i get is:

Access to undeclared static property: app\models\User::$Users

and this error corresponds to this section of code

 foreach (self::$Users as $user) {
        if (strcasecmp($user['username'], $username) === 0) {
            return new static($user);
        }
    }
2

2 Answers

0
votes

In your new User class change this methods:

public static function findIdentity($id)
    {
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
    }
    /**
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $type = null)
    {
        throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
    }
    /**
     * Finds user by username
     *
     * @param string $username
     * @return static|null
     */
    public static function findByUsername($username)
    {
        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
    }

See more in Yii2 Advanced template - https://github.com/yiisoft/yii2-app-advanced/blob/master/common/models/User.php#L61

Or take this class(from Yii2 Advanced template) in your app.

0
votes

Use one Object for User Model instead your three different objects.

class User extends ActiveRecord implements IdentityInterface
{
    const LOGIN_SCENARIO = 'login';
    const CREATE_SCENARIO = 'create';
    const UPDATE_SCENARIO = 'update';

    /**
     * Table name
     *
     * @return string
     */
    public static function tableName()
    {
        return 'user';
    }

    /**
     * Primary key
     */
    public static function primaryKey()
    {
        return ['id'];
    }

    /**
     * Set attribute labels
     *
     * @return array
     */
    public function attributeLabels()
    {
        return [
            'login'    => Yii::t('app', 'Login'),
            'password' => Yii::t('app', 'Password')
        ];
    }

    /**
     * Rules
     *
     * @return array
     */
    public function rules()
    {
        return [
            [
                [
                    'login',
                    'password'
                ],
                'required',
                'on' => self::LOGIN_SCENARIO
            ],
            [
                'password',
                'validatePassword',
                'on' => self::LOGIN_SCENARIO
            ],
            [
                [
                    'role',
                    'login',
                    'confirm',
                    'password',
                ],
                'required',
                'on' => self::CREATE_SCENARIO
            ],
            [
                [
                    'role',
                    'login',
                ],
                'required',
                'on' => self::UPDATE_SCENARIO
            ],
            [
                [
                    'name',
                    'status',
                    'password',
                    'create_dt',
                    'update_dt'
                ],
                'safe',
            ],
        ];
    }

    /**
     * Password validation
     */
    public function validatePassword($attribute)
    {
        // Validate pass
    }

    /**
     * @param null $id
     *
     * @return bool|mixed
     */
    public function saveUser($id = null)
    {
        /** @var self $user */
        $user = $this->findIdentity($id) ? $this->findIdentity($id) : $this;
        $user->setScenario($this->scenario);
        // Make Save
    }

    /**
     * @param $id
     *
     * @throws \Exception
     */
    public function deleteUser($id)
    {
        /** @var self $user */
        if($user = $this->findIdentity($id)) {
            // Make Delete 
        }
    }

    /**
     * Finds an identity by the given ID.
     *
     * @param string|integer $id the ID to be looked for
     *
     * @return IdentityInterface the identity object that matches the given ID.
     * Null should be returned if such an identity cannot be found
     * or the identity is not in an active state (disabled, deleted, etc.)
     */
    public static function findIdentity($id)
    {
        return static::findOne($id);
    }

    /**
     * Returns an ID that can uniquely identify a user identity.
     * @return string|integer an ID that uniquely identifies a user identity.
     */
    public function getId()
    {
        return $this->getPrimaryKey();
    }
}

And one User Model working with users, with different scenarios, can create, delete, make login etc.

And at html, for login form, put code like this:

<?php $model = new namespace\User() ?>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'login') ?>
<?= $form->field($model, 'password')->passwordInput() ?>

And for login, in controller, put code like this:

    /**
     * Login action
     *
     * @return mixed
     */
    public function actionLogin()
    {
        $user = new namespace\User();
        $user->setScenario(namespace\User::LOGIN_SCENARIO);
        $user->load(Yii::$app->request->post());
        if($user->validate()) {
            // Make Login
            return true;
        }
        return false;
    }