Reputation: 2032
I want to have a dynamic menu base on the user's permission. For example there is a menu for the admin account and for the basic account.
I am currently doing it like the following.
<?php
if((yii::$app->user->can('admin')) || (yii::$app->user->can('blah')) || (yii::$app->user->can('blahblah'))) ..and so on
{
//..print the menu
}
//another condition for menu here.
?>
Is there a shortcut in that if condition?
say for example I declare an array with the permissions inside then i will just use in_array
method to check if the user has the right permission to see the links.
Upvotes: 1
Views: 6096
Reputation: 621
I use a simple over it.
DB: menu and childmenu
Join: menu_id (childmenu) to id (menu)
``
<ul>
$mainmenu = \common\models\Menu::find()->all();
foreach ($mainmenu as $data)
{
echo "<li><a href='$data->url'>$data->name_en</a><ul>";
$sub_menu = \common\models\Childmenu::find()->where(['menu_id'=>$data->id])->all();
foreach ($sub_menu as $sub_value)
{
echo "<li><a href='$sub_value->url'>$sub_value->name_en</a></li>";
}
echo "</ul></li>";
}
?></ul>
```
Upvotes: -1
Reputation: 1036
Use this: dynamic 2 level menuitem yii2
$menuItems = array();
$pages_record = Pages::find()->all();
$i = 0;
foreach ($pages_record as $data)
{
if($data->select_parent == 0)
{
$path = \Yii::$app->request->BaseUrl."/index.php?r=".$data->seo_url;
$menuItems[$i] = array('label' => $data->page_title, 'url' => $path);
$pages_sub_rec = Pages::findAll(['select_parent' => $data['pid']]);
foreach ($pages_sub_rec as $sub_value)
{
$menuItems[$i]['items'][] = array('label' => $sub_value->page_title, 'url' => '#');
}
$i++;
}
}
Upvotes: 0
Reputation: 33538
Yii2 templates ships with Bootstrap 3, and Nav widget is most often used for building menus.
Here is an example of declaring visibility of menu items dynamically:
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => [
[
'label' => 'Users',
'url' => ['/users'],
'visible' => Yii::$app->user->can('users.manage'),
],
...
],
]);
And you don't need to check every possible role, you need to check permission for accessing / managing specific section.
For example in the provided example every user with assigned permission users.manage
can view that menu item. So, add permssion and assign it to desired user roles.
Don't forget to check permissions in controller too, hiding it in layout doesn't make sense if the link is still accessible.
Sometimes you have the nested submenu with grouped items and you want to show it conditionally too, depending on the rights. You can do it like that:
$menuItems = [
[
'label' => 'Section',
'items' => [
[
'label' => 'Subsection One',
'url' => ['/sub-section-one/index']],
'visible' => Yii::$app->user->can('sub-section-one.manage'),
],
[
'label' => 'Subsection One',
'url' => ['/sub-section-one/index']],
'visible' => Yii::$app->user->can('sub-section-two.manage'),
],
],
],
],
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => $menuItems,
]);
The problem is if user didn't have permission for managing both subsections, the root section used for grouping is still visible. We obviously can add
'visible' => Yii::$app->user->can('sub-section-one.manage') || Yii::$app->user->can('sub-section-two.manage'),
But in case of RBAC authManager
being DbManager
and turned off caching additional queries will be performed and we kind of duplicating code.
So you can do something like this:
$sectionItems => [
[
'label' => 'Subsection One',
'url' => ['/sub-section-one/index']],
'visible' => Yii::$app->user->can('sub-section-one.manage'),
],
[
'label' => 'Subsection One',
'url' => ['/sub-section-one/index']],
'visible' => Yii::$app->user->can('sub-section-two.manage'),
],
],
$isSectionVisible = false;
foreach ($sectionItems as $sectionItem) {
if ($sectionItem['visible']) {
$isSectionVisible = true;
break;
}
}
And then:
$menuItems = [
[
'label' => 'Section',
'visible' => $isSectionVisible,
'items' => $sectionItems,
],
],
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => $menuItems,
]);
Or you can extend Nav
widget and implement this logic.
Also take a look at advanced template layout, there is also an example for building dynamic menu:
$menuItems = [
['label' => 'Home', 'url' => ['/site/index']],
];
if (Yii::$app->user->isGuest) {
$menuItems[] = ['label' => 'Login', 'url' => ['/site/login']];
} else {
$menuItems[] = '<li>'
. Html::beginForm(['/site/logout'], 'post')
. Html::submitButton(
'Logout (' . Yii::$app->user->identity->username . ')',
['class' => 'btn btn-link']
)
. Html::endForm()
. '</li>';
}
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => $menuItems,
]);
Upvotes: 3