Problem Understanding UserIdentity::authenticate() in Chapter 7

Hi Everyone,

I’ve been studying ‘Agile Yii Development’ from Jeffrey Winesett and it has turned out to be a great resource.

I’ve been facing a small problem in Chapter 7, for which I haven’t found any solution yet. The author is explaining the ‘user authentication workflow’ and he shows the code for UserIdentity::authenticate() twice. Both the times the code is different. I fail to understand what is right and I feel there is some mistake in the book.

Now, initially, while explaining the components/UserIdentity.php class, he shows that the authenticate() method looks like this,




public function authenticate()

     {

       $users=array(

         // username => password

         'demo'=>'demo',

         'admin'=>'admin',

       );

       if(!isset($users[$this->username]))

         $this->errorCode=self::ERROR_USERNAME_INVALID;

       else if($users[$this->username]!==$this->password)

         $this->errorCode=self::ERROR_PASSWORD_INVALID;

       else

         $this->errorCode=self::ERROR_NONE;

       return !$this->errorCode;

     }



This, as we all know, is correct.

In the next few pages, while explaining how LoginForm::authenticate() works, he mentions that an instance of UserIdentity is created in it and then the :authenticate() method of UserIdentity is called as shown below,




public function authenticate($attribute,$params)

     {

       $this->_identity=new UserIdentity($this->username,$this->password);

       if(!$this->_identity->authenticate())

         $this->addError('password','Incorrect username or password.');

     }



This is also correct, isn’t it? Finally, he says that the above :authenticate method which is called inside LoginForm::authenticate(), looks like this,




public function authenticate($attribute,$params)

   {

     if(!$this->hasErrors())  // we only want to authenticate when no input errors

     {

       $identity=new UserIdentity($this->username,$this->password);

       $identity->authenticate();

       switch($identity->errorCode)

       {

         case UserIdentity::ERROR_NONE:

           $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days

           Yii::app()->user->login($identity,$duration);

           break;

         case UserIdentity::ERROR_USERNAME_INVALID:

           $this->addError('username','Username is incorrect.');

           break;

         default: // UserIdentity::ERROR_PASSWORD_INVALID

           $this->addError('password','Password is incorrect.');

           break;

       }

     }

   }



I have not found this method anywhere in the demo application or Yii root classes. The above method again creates an instance of UserIdentity and calls :authenticate? The method is called inside <b>itself</b>?

I haven’t been able to understand the authentication work flow because of this. I strongly feel the explanation of this topic in the book is not correct.

Would really appreciate if this problem is cleared.

Cheers.

Okay. I discovered that it is in fact, an "identified issue" in the book (http://www.yiiframework.com/forum/index.php?/topic/11920-identified-issues/).

Hi, trashedCoder

I also fall in the same problem u face…actually the book is written for Yii 1.1.2 and I am using later version which is changed in some cases like for the authentication login the code for authenticate() in UserIdentity.php is


$users=array(

			//username => password

			'demo'=>'demo',

			'admin'=>'admin',

		);

		if(!isset($users[$this->username]))

			$this->errorCode=self::ERROR_USERNAME_INVALID;

		else if($users[$this->username]!==$this->password)

			$this->errorCode=self::ERROR_PASSWORD_INVALID;

		else

			$this->errorCode=self::ERROR_NONE;

		return !$this->errorCode;



and for the LoginForm.php authenticate method is like


public function authenticate($attribute,$params)

	{

		if(!$this->hasErrors())

		{

			$this->_identity=new UserIdentity($this->username,$this->password);

			if(!$this->_identity->authenticate())

				$this->addError('password','Incorrect username or password.');

		}

	}

and finally where the confusion is this code actually belongs to LoginForm.php login() method


public function login()

	{

		if($this->_identity===null)

		{

			$this->_identity=new UserIdentity($this->username,$this->password);

			$this->_identity->authenticate();

		}

		if($this->_identity->errorCode===UserIdentity::ERROR_NONE)

		{

			$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days

			Yii::app()->user->login($this->_identity,$duration);

			return true;

		}

		else

			return false;	}

if u r following the book for connecting the user login from database just add this code into the UserIdentity.php


$user = User::model()->findByAttributes(array('username'=>$this->username));

		if($user === null){

			$this->errorCode = self::ERROR_USERNAME_INVALID;

		}

		else{

			if($user->password !== $user->encrypt($this->password)){

				$this->errorCode = self::ERROR_PASSWORD_INVALID;

			}

			else{

				$this->_id = $this->id;

				if($user->last_login_time === null){

					$lastLogInTime = time();

				}

				else{

					$lastLogInTime = strtotime($user->last_login_time);	

				}

				$this->setState('lastLogInTime', $lastLogInTime);

				$this->errorCode = self::ERROR_NONE;

			}

		}

		return !$this->errorCode;

do not add this method


public function getId(){

		return $this->_id;		

	}

it will work…:)