Create a custom menu using CMenu data-items (flat or tree structure)

3 followers

This wiki article has not been tagged with a corresponding Yii version yet.
Help us improve the wiki by updating the version information.

There are cases that you want more control to your menu Suppose you want a specific menu with complex css, layout, images. also you want to add extra content,html,css,javascript etc it run time foreach submenu item by conditions.

So, it is more simple to make your menu rather than to use an existent widget cmenu (rare case but it has happened to me)

Assume that you have a multi lever menu like that http://www.yiiframework.com/forum/index.php/topic/12700-cmenu-and-multi-level-nested-menu/page__view__findpost__p__62893

or the menu generated by database Suppose you have the items that generated by $this->getMenuTree() of the last wiki http://www.yiiframework.com/wiki/523/generate-a-multi-lever-array-sub-category-for-a-menu/

So you have to analyse the items to get more control for each item

$this->widget('zii.widgets.CMenu', array(
    'items'=>$this->getMenuTree() //array( ...multi array with unknown or not item attributes...)
    ...
    ...

The analysis

In your component add this code

private static function menuExploder($catTree, $level) {
        $res = array();
        //for each item recursively
        foreach ($catTree as $item) {
            $part = array();
            //get all attributes of the item except own items (if items exist)
            foreach ($item as $key => $val) { 
                if ($key != 'items')
                    $part[$key] = $val;
            }
//add the level of the sub category, also you could stores anything else you want likeincrements
            $part['level_menu'] = $level; 
            $res[] = $part; //stores to the results
            if (isset($item['items']) && is_array($item)) { //if item menu has sub menu
                //call recursively the same method
                $res_iter = self::menuExploder($item['items'], $level + 1); 
                //stores all sub menu items of the previous calling
                foreach ($res_iter as $key => $val) {
                    $res[] = $val;
                }
            }
        }
        return $res; //all the submenus items and own subcategory lever of the native menu in flat array 
    }

the result will seems like that

array (size=...)
    0 => 
    array (size=3)
      'label' => string 'root menu label 1'
      'url' => string '/your/link1'
      'level_menu' => 0
    1 => 
    array (size=3)
      'label' => string 'sub category label 1'
      'url' => string '/your/link2'
      'level_menu' => 1
    2 => 
    array (size=3)
      'label' => string 'sub-sub category label 1'
      'url' => string '/your/link3'
      'level_menu' => 2

Now you can make a simple html menu with ul and li (but you can make also anything you want!)

public static function visualTreePad($catTree) {
        $res = self::menuExploder($catTree, 0);
 
$html = '<ul>'; //root-parent ul
$curLev = 0; //first lever
 
 
       foreach ($res as $val) { //foreach item
 
            //the level menu is going to change so add <ul> tag parent
            if ((int) $val['level_menu'] > $curLev) { 
                $h = (int) $val['level_menu'] - $curLev;
                //may it needs multi <ul>, in most cases $h1=1
                $html .= str_repeat('<ul>', $h);
                //add the first item
                $html .= '<li>' . CHtml::link($val['label'], $val['url']) . '</li>'; 
                $curLev = (int) $val['level_menu'];
             //the submenu is goint to ends, so close it with </ul> tag
            } else if ((int) $val['level_menu'] < $curLev) {
                $h = $curLev - (int) $val['level_menu'];
                //may it needs multi <ul>, in most cases $h1=1
                $html .= str_repeat('</ul>', $h); 
                //add the last item
                $html .= '<li>' . CHtml::link($val['label'], $val['url']) . '</li>'; 
                $curLev = (int) $val['level_menu'];
            } else {
                //add the intermediate items
                $html .= '<li>' . CHtml::link($val['label'], $val['url']) . '</li>'; 
            }
        }
 
        $html .= '</ul>'; //close the root-parent ul
 
 
        return $html;
    }

echo the $html in your layout, there is a simple menu... but you can make it more rich and complex :)

Be the first person to leave a comment

Please to leave your comment.