Extending the user object after r66

Hi qiang,

i am a little bit troubled with your r66 checkin regarding the removal of the WebUser.php class. I previously extended it with methods like this one: [tt]Yii::app()->user->hasAvatar()[/tt]. Now i am not sure where to implement these methods.

Greetings from Hamburg / Germany

  • rojaro -

it is not removed. U can still do what u r doing now. The change is about decoupling authentication from CWebUser.

But exactly this decoupling is what really confuses me.

In PRADO used to extend the user object to also carry information like the users email address, his numeric database Id as primary identifier so i could do stuff like $this->Application->User->Id (which would return the database id), $this->Application->User->Username, $this->Application->User->Email,  etc. As all that stuff is stored in the session, i dont have to reload the user record foreach request where i have to display user specific details.

Since the authentication is now done in Identity::authenticate() method, the user record is also loaded there.

public function authenticate()


{


    if(User::model()->findByAttributes(array('LoginName'=>$this->username,'Password'=>hash('sha256', $this->password))) !== null)


    $this->errorCode=self::ERROR_NONE;


else


    $this->errorCode=self::ERROR_PASSWORD_INVALID;


return !$this->errorCode;


}

Therefore, in order to save a sql query, i would have to populate the additional user properties from within Identity::authenticate

public function authenticate()


{


    if(($userRecord = User::model()->findByAttributes(array('LoginName'=>$this->username,'Password'=>hash('sha256',$this->password)))) !== null)


    {


        $user = Yii::app()->getUser();


        $user->setId($userRecord->Id);


        $user->setUserName($userRecord->LoginName);


        $user->setNickName($userRecord->NickName);


        $user->setEmail($userRecord->Email);


        $user->setAvatar($userRecord->AvatarId);


        // many more properties ...


        $this->errorCode=self::ERROR_NONE;


    }


    else


        $this->errorCode=self::ERROR_PASSWORD_INVALID;


    return !$this->errorCode;


}

Is this the right way to do it?

No. Do not access user in identity. Please read the Guide for the example about persisting "title".

You are refering to http://www.yiiframew…ide/topics.auth and the following code example right?

class Identity extends CIdentity


{


    public function authenticate()


    {


        $valid=User::model()->findByAttributes(array(


            'username'=>$this->username,


            'password'=>md5($this->password))) !== null;


        if(!$valid)


        {


            $this->errorCode=self::ERROR_UNKNOWN;


            $this->errorMessage='some message';


        }


        return $valid;


    }


 


    public function getTitle()


    {


        return $this->getState('title');


    }


 


    public function setTitle($value)


    {


        $this->setState('title',$value);


    }


}

I see you've defined a getter and a setter, but the setter is never called. Shouldn't this example look like this instead?

class Identity extends CIdentity


{


	public function authenticate()


	{


		if(($userRecord=User::model()->findByAttributes(array('LoginName'=>$this->username)))===null)


			$this->errorCode=self::ERROR_USERNAME_INVALID;


		elseif($userRecord->Password!=hash('sha256', $this->password))


			$this->errorCode=self::ERROR_PASSWORD_INVALID;


		else


		{


			$this->errorCode=self::ERROR_NONE;


			$this->setTitle($userRecord->Title);


		}


		return $this->errorCode;


	}


	


	public function getTitle()


	{


		return $this->getState('title');


	}





	public function setTitle($value)


	{


		$this->setState('title',$value);


	}


}

You're right. I will fix it.

In general, do not access Yii::app()->user in identity code. The user object will fetch the needed data from identity automatically when you do Yii::app()->user->login(). You may also use "yiic webapp" to generate a new app to see how this works.

Quote

You may also use "yiic webapp" to generate a new app to see how this works.

I did, but since the generated “demo” doesn’t use any databases and relies on a hard coded user name and pasword, it isn’t really useful as example when you have to deal with a database instead ;)

I just simplified that example a little bit …

class Identity extends CIdentity


{


	public function authenticate()


	{


		if(($userRecord=User::model()->findByAttributes(array('LoginName'=>$this->username)))===null)


			return $this->errorCode=self::ERROR_USERNAME_INVALID;


		


		if($userRecord->Password!=hash('sha256', $this->password))


			return $this->errorCode=self::ERROR_PASSWORD_INVALID;


		


		$this->setTitle($userRecord->Title)


		return $this->errorCode=self::ERROR_NONE;


	}


	


	public function getTitle()


	{


		return $this->getState('title');


	}





	public function setTitle($value)


	{


		$this->setState('title',$value);


	}


}

Thanks. I just did the similar thing.

Hope this new identity feature is more flexible than previous.

We can now create various identity classes such as OpenID, LDAP, and reuse them easily.

Looks good to me, now that i finally got it working ;D