Navigation.php
<?php
class Navigation
{
private static $_instance = null;
private $_menus = array();
public static function getInstance()
{
if(self::$_instance === null)
self::$_instance = new self;
return self::$_instance;
}
public static function getMenu($menuId)
{
if(!isset(self::getInstance()->_menus[$menuId]))
self::getInstance()->_menus[$menuId] = new Menu($menuId);
return self::getInstance()->_menus[$menuId];
}
public static function removeMenu($menuId)
{
self::getInstance()->_menus[$menuId] = null;
}
public static function render($menuId)
{
if(($menu = self::getMenu($menuId)) !== null)
$menu->render();
}
}
Menu.php
<?php
class Menu
{
private $_id;
private $_items = array();
private $_htmlOptions = array();
public function __construct($id)
{
$this->_id = $id;
}
public function addItem($itemId, $item)
{
$label = isset($item['label']) ? $item['label'] : '';
$url= isset($item['url']) ? $item['url'] : '';
$weight= isset($item['weight']) ? $item['weight'] : 0;
$htmlOptions = isset($item['htmlOptions']) ? $item['htmlOptions'] : array();
$linkOptions = isset($item['linkOptions']) ? $item['linkOptions'] : array();
$visible = isset($item['visible']) ? $item['visible'] : true;
$items = isset($item['items']) ? $item['items'] : null;
$this->_items[$itemId] = new MenuItem($itemId,$label,$url,$weight,$htmlOptions,$linkOptions,$visible,$items);
}
public function addItems($items)
{
foreach($items as $id => $item)
$this->addItem($id, $item);
}
public function removeItem($itemId)
{
if(isset($this->_items[$itemId]))
unset($this->_items[$itemId]);
}
public function hasItem($itemId)
{
return isset($this->_items[$itemId]);
}
public function isEmpty()
{
$count = 0;
foreach($this->_items as $item)
{
if($item->getVisible())
$count++;
}
return $count <= 0;
}
public function getItem($itemId)
{
return isset($this->_items[$itemId]) ? $this->_items[$itemId] : null;
}
public function setHtmlOptions($htmlOptions = array(), $mergeOld = false)
{
if($mergeOld)
$this->_htmlOptions = CMap::mergeArray($this->_htmlOptions, $htmlOptions);
else
$this->_htmlOptions = $htmlOptions;
return $this;
}
public function getVisibleItems()
{
$visibleItems = array();
foreach($this->_items as $id => $item)
{
if($item->getVisible())
$visibleItems[$id] = $item;
}
return $visibleItems;
}
protected function compareItems($itemA, $itemB)
{
if($itemA->getWeight() === $itemB->getWeight())
{
return 0;
}
return ($itemA->getWeight() <= $itemB->getWeight()) ? -1 : 1;
}
protected function sortItems($items)
{
uasort($items,array($this,'compareItems'));
return $items;
}
public function render()
{
if(count($this->getVisibleItems()))
{
echo CHtml::openTag('ul', $this->_htmlOptions)."\n";
$this->renderRecursive($this->getVisibleItems());
echo CHtml::closeTag('ul')."\n";
}
}
protected function renderRecursive($items)
{
$items = $this->sortItems($items);
foreach($items as $item)
{
if($item instanceof MenuItem)
{
if($item->getVisible())
{
echo CHtml::openTag('li',$item->getHtmlOptions())."\n";
echo CHtml::link($item->getLabel(), $item->getUrl(), $item->getLinkOptions());
if(count($item->getItems()))
{
echo CHtml::openTag('ul')."\n";
self::renderRecursive($item->getItems());
echo CHtml::closeTag('ul')."\n";
}
echo CHtml::closeTag('li')."\n";
}
}
}
}
}
MenuItem.php
<?php
class MenuItem
{
private $_id;
private $_label;
private $_url;
private $_weight;
private $_htmlOptions;
private $_linkOptions;
private $_visible;
private $_items = array();
public function __construct($id, $label, $url, $weight = 0, $htmlOptions = array(), $linkOptions = array(), $visible = true, $items = array())
{
$this->_id = $id;
$this->_label = $label;
$this->_url = $url;
$this->_weight = $weight;
$this->_htmlOptions = $htmlOptions;
$this->_linkOptions = $linkOptions;
$this->_visible = $visible;
$this->_items = $items;
}
public function getLabel()
{
return $this->_label;
}
public function getUrl()
{
return $this->_url;
}
public function getWeight()
{
return $this->_weight;
}
public function getHtmlOptions()
{
return $this->_htmlOptions;
}
public function setHtmlOptions($htmlOptions = array(), $mergeOld = false)
{
if($mergeOld)
$this->_htmlOptions = CMap::mergeArray($this->_htmlOptions, $htmlOptions);
else
$this->_htmlOptions = $htmlOptions;
return $this;
}
public function setLinkOptions($linkOptions = array(), $mergeOld = false)
{
if($mergeOld)
$this->_linkOptions = CMap::mergeArray($this->_linkOptions, $linkOptions);
else
$this->_linkOptions = $linkOptions;
return $this;
}
public function getLinkOptions()
{
return $this->_linkOptions;
}
public function getVisible()
{
return $this->_visible;
}
public function getItems()
{
return $this->_items;
}
public function getItem($id)
{
return isset($this->_items[$id]) ? $this->_items[$id] : null;
}
public function addItem($id, $item)
{
$label = isset($item['label']) ? $item['label'] : '';
$url= isset($item['url']) ? $item['url'] : '';
$weight= isset($item['weight']) ? $item['weight'] : 0;
$htmlOptions = isset($item['htmlOptions']) ? $item['htmlOptions'] : array();
$linkOptions = isset($item['linkOptions']) ? $item['linkOptions'] : array();
$visible = isset($item['visible']) ? $item['visible'] : true;
$items = isset($item['items']) ? $item['items'] : null;
$this->_items[$id] = new self($id,$label,$url,$weight,$htmlOptions,$linkOptions,$visible,$items);
}
public function addItemIfHasItem($itemId, $id, $item)
{
if($this->getItem($itemId)!==null)
$this->getItem($itemId)->addItem($id, $item);
}
public function addItems($items)
{
foreach($items as $id => $item)
{
$this->addItem($id, $item);
}
}
public function removeItem($id)
{
if(isset($this->_items[$id]))
unset($this->_items[$id]);
}
}
Usage example: building menu
Navigation::getMenu('main.nav')->setHtmlOptions(array('class'=>'test'))->addItems(array(
'login'=>array('label'=>'h', 'url'=>'h','weight'=>1,'htmlOptions'=>array('class'=>'l')),
'login2'=>array('label'=>'l', 'url'=>'l','weight'=>0,'linkOptions'=>array('class'=>'l')),
));
Navigation::getMenu('user.nav')->addItems(array(
'login'=>array('label'=>'xxxxx', 'url'=>'xxx'),
'login2'=>array('label'=>'yyyy', 'url'=>'xxx'),
));
Navigation::getMenu('user.nav')->getItem('login')->addItems(array(
'login'=>array('label'=>'wwww', 'url'=>'xxx', 'visible'=>false),
'login2'=>array('label'=>'mmmm', 'url'=>'xxx'),
));
Navigation::getMenu('user.nav')->getItem('login')->getItem('login2')->addItems(array(
'login'=>array('label'=>'nnn', 'url'=>'xxx','weight'=>0),
'login2'=>array('label'=>'ooo', 'url'=>'xxx','weight'=>0),
));
Example: rendering menu
<div id="global-nav clearfix">
<div id="main-nav">
<?php Navigation::render('main.nav'); ?>
</div>
<div id="user-nav">
<?php Navigation::render('user.nav'); ?>
</div>
</div>