Yii: How to make a dynamic sub-menu

I’ve seen a number of people have been trying to build a dynamic submenu that sits underneath the main menu and changes with each main menu.

The standard Yii menu widget assumes or enforces the hard-coding of menu entries within the layout.php file. Within this you can define functions to determine the user context but I felt this would be much better defined within each individual controller. After all, the purpose of the MVC architecture is to divide layout, business logic and data. So this solutions moves that sub-menu logic from the layout.php into each controller.

I based my idea on an article ( here ) on how to use CPortlets to build a static user menu in a sidebar.

So here is the logic to build a widget that is dynamic, such that you can define the sub-menu items in each controller.

components/submenu.php

 PHP |  copy code |? 
01
02
Yii::import('zii.widgets.CPortlet');
03
 
04
class SubMenu extends CPortlet
05
{
06
public $title;
07
public $menu;
08
 
09
public function init()
10
{
11
  $this->hideOnEmpty=true;
12
 
13
  $controllerId = Yii::app()->controller;
14
 
15
  if (method_exists($controllerId, 'getSubMenu')) {
16
    $this->menu= $controllerId->getSubMenu();
17
  }
18
  parent::init();
19
}
20
 
21
protected function renderContent()
22
{
23
  if (isset ($this->menu)) {
24
    $this->render('subMenu', array('menu'=>$this->menu));
25
    }
26
}

components/views/submenu.php

 PHP |  copy code |? 
01
<ul>
02
    <?php
03
        $count = count($menu);
04
        for ($i = 0; $i < $count; $i++) {
05
            $mItem=$menu[$i];
06
            if (isset($mItem[2])) {
07
                echo "<li ".$mItem[2]." >";
08
            } else {
09
                echo "<li>";
10
            }
11
            $mName=$mItem[0];
12
            $mLink=$mItem[1];
13
           echo CHtml::link($mName,$mLink)."</li>";
14
        }
15
    ?>
16
</ul>

 PHP |  copy code |? 
01
02
<?php
03
        $count = count($menu);
04
        for ($i = 0; $i < $count; $i++) {
05
            $mItem=$menu[$i];
06
            if (isset($mItem[2])) {
07
                echo "<li ".$mItem[2]." >";
08
            } else {
09
                echo "<li>";
10
            }
11
            $mName=$mItem[0];
12
            $mLink=$mItem[1];
13
           echo CHtml::link($mName,$mLink)."</li>";
14
        }
15
    ?>
16
</ul>

controller/some_controller.php

 PHP |  copy code |? 
01
02
public function getSubMenu() {
03
 
04
  $subMenuItems=array();
05
  if(UserModule::isAdmin()) {
06
    $mu=UserModule::t('Manage User');
07
    $subMenuItems[$mu]='/user/admin';
08
    $subMenuItems[UserModule::t('List User')]='/user';
09
  }
10
  $subMenuItems[UserModule::t('Profile')]='/user/profile';
11
  $subMenuItems[UserModule::t('Edit')]='edit';
12
  $subMenuItems[UserModule::t('Change password')]='changepassword';
13
  $subMenuItems[UserModule::t('Logout')]='/user/logout';
14
 
15
  return $subMenuItems;
16
 
17
}

layout/main.php
 HTML |  copy code |? 
1
2
<div id="submenu">
3
  <?php $this->widget('SubMenu'); 
4
?>
5
</div>
6

You could then add styling like this:
 CSS |  copy code |? 
1
&nbsp;
2
 
3
#submenu ul {padding: 6px 20px 5px 20px;&nbsp;  margin: 0px;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
4
#submenu ul li {display: inline;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
5
#submenu ul li a {&nbsp;color: #539DC7;&nbsp;background-color: transparent;font-size: 12px; font-weight: bold;&nbsp; text-decoration: none;&nbsp; padding: 5px 8px;&nbsp;border-right: 1px solid #539DC7;&nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
6
#submenu ul li a:hover,
7
#submenu ul li.active a {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; color: #6399CD;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; background-color: #EFFDFF;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text-decoration: none;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;

see also  How to make a dynamic sub-menu – UPDATE



If you found this article useful » please +1 me on Google.