This little tutorial explains a way how you can retrieve more parameters from Yii::app()->user by adding a component that extends CWebUser and retrieves the user information from database table named User.
There is also another method of doing this that retrieves the variables from session or cookie instead:
How to add more information to Yii::app()->user (based on session or cookie)
Steps to follow:
- Make sure you have got a database User model.
- Create a component that extends CWebUser.
- Specify in the config.php what user class the application must use.
1. The User model should be a file like this, that you probably already have, anyway for who doesn't:
<?php
// this file must be stored in:
// protected/models/User.php
class User extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* @return CActiveRecord the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return 'User';
}
}
?>
2. Then we create the WebUser component:
<?php
// this file must be stored in:
// protected/components/WebUser.php
class WebUser extends CWebUser {
// Store model to not repeat query.
private $_model;
// Return first name.
// access it by Yii::app()->user->first_name
function getFirst_Name(){
$user = $this->loadUser(Yii::app()->user->id);
return $user->first_name;
}
// This is a function that checks the field 'role'
// in the User model to be equal to 1, that means it's admin
// access it by Yii::app()->user->isAdmin()
function isAdmin(){
$user = $this->loadUser(Yii::app()->user->id);
return intval($user->role) == 1;
}
// Load user model.
protected function loadUser($id=null)
{
if($this->_model===null)
{
if($id!==null)
$this->_model=User::model()->findByPk($id);
}
return $this->_model;
}
}
?>
3. The last step, configure the application
// you must edit protected/config/main.php
// and find the application components part
// you should have other components defined there
// just add the user component or if you
// already have it only add 'class' => 'WebUser',
// application components
'components'=>array(
'user'=>array(
'class' => 'WebUser',
),
),
That's all now you can use the following commands:
Yii::app()->user->first_name - property that returns name
Yii::app()->user->isAdmin() - function that returns admin status
And now you can add all the functions you want to WebUser component.
problem with php 5.3 solved
My problem was similar to that described by waveslider. The reason is that Guest is not listed in the user table and therefor it has no id, that is Yii::app()->user->id is not set. In php 5.2 it is ok because it assignes default values to variables but php5.3 does not. So we get error "Trying to get property of non-object" because $user is not created.
I solved my problem with code like this:
public function getName() { if(Yii::app()->user->getIsGuest()) { return ""; } else { $user = $this->loadUser(Yii::app()->user->id); return $user->email; } }
Get all posts by current user
I found this method is very usefull to get data in Relational Active Record table. For example, each user have many posts. In WebUser declare
function getModel() { $user = $this->loadUser(Yii::app()->user->id); return $user; }
And now to get all posts by the current user, you just call
Yii::app()->user->model->posts
An alternative using user session
Hi, I performed this alternative, I expect you like it
class UserIdentity extends CUserIdentity{ private $id; private $model; public function getId() { return $this->id; } public function getModel() { return $this->model; } public function authenticate() { $user= User::model()->find('LOWER(email)=?', array(strtolower($this->username))); if($user === null) { $this->errorCode= CBaseUserIdentity::ERROR_UNKNOWN_IDENTITY; } elseif($user->password !== $this->password) { $this->errorCode= CBaseUserIdentity::ERROR_PASSWORD_INVALID; } else { $this->model= $user; $this->id= $user->id; $this->username= $user->email; $this->errorCode= self::ERROR_NONE; } return !$this->errorCode; } }
class WebUser extends CWebUser{ public function getModel() { return Yii::app()->getSession()->get('model'); } public function login($identity, $duration) { parent::login($identity, $duration); Yii::app()->getSession()->add('model', $identity->getModel()); } public function logout($destroySession= true) { // I always remove the session variable model. Yii::app()->getSession()->remove('model'); } }
An alternative using user session
I forgot one line in WebUser.logout:
public function logout($destroySession= true) { // I always remove the session variable model. Yii::app()->getSession()->remove('model'); parent::logout(); }
$user might be null
Great wiki thank you
I just needed to change the isAdmin() function to check if the $user exists, returning 0 if it doesn't
function isAdmin() { $user = $this->loadUser(Yii::app()->user->id); if ($user===null) return 0; else return intval($user->role) == 1; }
override afterLogin
how to override afterLogin function?. I try to add code like this on EWebUser class but no yet work.
class EWebUser extends CWebUser { protected function afterLogin($fromCookie) { parent::afterLogin($fromCookie); $fh=fopen(Yii::getPathOfAlias('webroot').'/after_login.txt', 'w'); fwrite($fh, 'Hello World'); fclose($fh); } }
Any suggestion?. Thanks
Re: override afterLogin
remove line:
parent::afterLogin($fromCookie);
Add your class in config/main.php like mentioned above.
Note that you should reffer to CWebUser via variable $this instead of Yii::app()->user
That's all
Built-in functionality
Why not simply use CWebUser.setState() and CWebUser.getState(). Quoting Yii's Class Reference:
«[setState()] Stores a variable in user session.
This function is designed to be used by CWebUser descendant classes who want to store additional user information in user session. By storing a variable using this function, the variable may be retrieved back later using getState. The variable will be persistent across page requests during a user session.»
For auto-updating information
If your user has information that you want to auto-update, you can use this:
class WebUser extends CWebUser { private $model = null; public function getModel() { if(!isset($this->id)) $this->model = new User; if($this->model === null) $this->model = User::model()->findByPk($this->id); return $this->model; } public function __get($name) { try { return parent::__get($name); } catch (CException $e) { $m = $this->getModel(); if($m->__isset($name)) return $m->{$name}; else throw $e; } } public function __set($name, $value) { try { return parent::__set($name, $value); } catch (CException $e) { $m = $this->getModel(); $m->{$name} = $value; } } public function __call($name, $parameters) { try { return parent::__call($name, $parameters); } catch (CException $e) { $m = $this->getModel(); return call_user_func_array(array($m,$name), $parameters); } } }
which allows you to - well, say you have the attribute "canPost" in your User model - you get to
if(Yii::app()->user->canPost)
The downside, of course, is that it has to run the SQL for pulling a model the first time you Yii::app()->user->[something in the user model] - the upside is that it updates the info from SQL.
thanks :)
Thanks :)
If you have your user details on a different table then the one you store the login details
In your loadModel(), you can use
with a relation between your login details table, and user (ie. student) table, and do something around this:
$this->_model=Student::model()->find("site_user_id = $student_id");
Then you can star retrieving data from your student model as well.
AFAIK, just pay attention to what you wish store on SESSION.
If there's a better way, pls, drop a comment. :)
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.