yii : how to display the different menu(s) by user role?

17,588

Solution 1

If you're using RBAC you can set the 'visible' param of CMenu items depending on the users privileges, for example;

$this->widget('zii.widgets.CMenu',array(
    'items'=>array(
        array(
            'label'=>'Home',
            'url'=>array('site/index'),
        ),
        array(
            'label'=>'HR',
            'url'=>array('/hr/index'),
            'visible'=>Yii::app()->user->checkAccess('hr')
        ),
        array(
            'label'=>'Accounts',
            'url'=>array('/account/index'),
            'visible'=>Yii::app()->user->checkAccess('account')
        ),
        array(
            'label'=>'Operations',
            'url'=>array('/operations/index'),
            'visible'=>Yii::app()->user->checkAccess('operations')
        ),
    ),
);

This way users will only be able to see the items in the menu if they have access privileges for that area.

[EDIT]

As per simaremare's comment below, you can force caching of this query beyond the current request by extending CWebUser. Firstly, set your user to run through your new class (we'll call it TWebUser), so in your main.php config file;

'components'=>array(
    'user'=>array(
        ...
        'class'=>'TWebUser',
        ...
    ),
    ...
),

Now we need to create TWebUser to cache these beyond the current request (which is what CWebUser does (source code):

class TWebUser extends CWebUser
{
    private $_access=array();

    public function checkAccess($operation,$params=array(),$allowCaching=true)
    {
        if($allowCaching && $params===array() && isset($this->_access[$operation]))
            return $this->_access[$operation];

        $cache = Yii::app()->session['checkAccess'];
        if($allowCaching && !$this->getIsGuest() && isset($cache[$operation]) && time() - $cache[$operation]['t'] < 1800)
        {
            $checkAccess = $cache[$operation]['p'];
        } else {
            $checkAccess = Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);

            if($allowCaching && !$this->getIsGuest())
            {
                $access = isset($cache) ? $cache : array();
                $access[$operation] = array('p'=>$checkAccess, 't'=>time());
                Yii::app()->session['checkAccess'] = $access;
            }
        }

        return $this->_access[$operation] = $checkAccess;
    }
}

Now your access results will be set for the whole session. This does mean that if you edit the RBAC permissions for a given account, they'll have to log out and log in again to see the new changes reflected in the browser.

I hope that helps! I'm sure I found this workaround from someone else (probably on SO), but I can't find the original post to give them credit.

Solution 2

You would wrap an if-statement around the menu-items that you may or may not want to show.

In the if-statement, you would have to test whether the user qualifies to see your menu-items.

For example:

<?php if (Yii::app()->user->isGuest): ?>

  <?php $this->widget('zii.widgets.CMenu',array(
    'items'=>array(
  array(
        'label'=>'this menu item visible only for Guests (not logged in)', 
        'url'=>array('/site/index')),
      ),
    )); ?>

<?php endif; ?>
Share:
17,588
Thu Ra
Author by

Thu Ra

Updated on June 26, 2022

Comments

  • Thu Ra
    Thu Ra almost 2 years

    Q : How can I show display different menu(s) by user role?

    Description : the app has many roles. e.g HR manager, Account Manager, Operating Manager, Employee, Operator, ...., etc. I used rights and yii-user modules to create those roles. Those roles have different functions. So the app will show different menu for different user's role after logged in. Now, I can lock the function for different user. e.g when HR manger logged in, he/she can't route to other function of user role. But I don't know how to show the HR Menu for Hr Manager, only.

    I am not a newbie for yii. but I'm a newbie for those modules (rihgts and yii-user).

  • Thu Ra
    Thu Ra over 11 years
    Thank for you help. Yes, I knew this isGuest. but I've different role name at authitem tbl, e.g HR Manager. My problem is I don't know how to check HR Manager role. I tried isHRManager, but it is not working. And I tried Authenticated as isAuthenticated, but it is not working also. How can I check other role as isGuest?
  • simaremare
    simaremare about 11 years
    this will do query everytime doing checkAccess(), this seems not efficient.
  • Stu
    Stu about 11 years
    Hi @simaremare, that's a good point, the default user class (CWebUser) only caches these results for the current request, I've added an update that's a bit more efficient.
  • Sarvar N
    Sarvar N almost 10 years
    well explained, thanks. It gives me more idea about customizing RBAC.