Yii Framework Forum: Navigation extension - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Navigation extension Rate Topic: -----

#1 User is offline   jayrulez 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 348
  • Joined: 29-July 09

Posted 07 August 2010 - 01:30 PM

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>

php:
foreach(array('cat', 'dog', 'cow') as $animal) echo $animal."\n";

python:
[(animal, print(animal)) for animal in ['cat', 'dog', 'cow']]

ruby:
['cat', 'dog', 'cow'].each {|animal| puts animal}


You say Tomato, I say Tomato.
0

#2 User is offline   jayrulez 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 348
  • Joined: 29-July 09

Posted 07 August 2010 - 01:33 PM

Feel free to suggest changes, improve and share changes :)
php:
foreach(array('cat', 'dog', 'cow') as $animal) echo $animal."\n";

python:
[(animal, print(animal)) for animal in ['cat', 'dog', 'cow']]

ruby:
['cat', 'dog', 'cow'].each {|animal| puts animal}


You say Tomato, I say Tomato.
0

#3 User is offline   Tony Casparro 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 7
  • Joined: 18-August 10

Posted 18 August 2010 - 07:03 PM

What's with the memoization and instances?
Where did you plan on placing this in your code structure?

Cheers!
--------------
Tony Casparro
Worth Monkey - For What It's Worth
0

#4 User is offline   Tony Casparro 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 7
  • Joined: 18-August 10

Posted 18 August 2010 - 07:08 PM

Just figured out why, when I tried to remove them and use a single instantiation. =)
But I'm still curious where you place the menu building code.
--------------
Tony Casparro
Worth Monkey - For What It's Worth
0

#5 User is offline   jayrulez 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 348
  • Joined: 29-July 09

Posted 19 August 2010 - 02:22 AM

I place it in the init() method of certain controllers. You can place it anywhere really as you are able to to add or remove items from any menu by calling addItem/removeItem
php:
foreach(array('cat', 'dog', 'cow') as $animal) echo $animal."\n";

python:
[(animal, print(animal)) for animal in ['cat', 'dog', 'cow']]

ruby:
['cat', 'dog', 'cow'].each {|animal| puts animal}


You say Tomato, I say Tomato.
0

#6 User is offline   jayrulez 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 348
  • Joined: 29-July 09

Posted 19 August 2010 - 04:36 AM

Updated. Documentation and examples coming soon

<?php

class Menu extends CComponent
{
	protected $_id;
	protected $_items;
	protected $_htmlOptions = array();
	
	public function __construct($id, $htmlOptions = array())
	{
		$this->setId($id);
		$this->setHtmlOptions($htmlOptions);
		$this->_items = new CMap;
		$this->init();
	}
	
	public function init()
	{
	}
	
	public function getId()
	{
		return $this->_id;
	}
	
	public function getHtmlOptions()
	{
		return $this->_htmlOptions;
	}
	
	public function setId($id)
	{
		if(!is_string($id))
		{
			throw new CException(Util::t('The id must be a string.'));
		}
		$this->_id = $id;
		return $this;
	}
	
	public function setHtmlOptions($htmlOptions, $mergeOld = false)
	{
		if(!is_array($htmlOptions))
		{
			throw new CException(Util::t('The html options must be a number.'));
		}
		if($mergeOld)
		{
			$this->_htmlOptions = CMap::mergeArray($this->_htmlOptions, $htmlOptions);
		}else{
			$this->_htmlOptions = $htmlOptions;
		}
		return $this;
	}
	
	public function addItem($itemData)
	{
		if(isset($itemData['id'], $itemData['label']))
		{
			$id          = $itemData['id'];
			$label       = $itemData['label'];
			$url         = isset($itemData['url'])         ? $itemData['url'] : '#';
			$weight      = isset($itemData['weight'])      ? $itemData['weight'] : 0;
			$htmlOptions = isset($itemData['htmlOptions']) ? $itemData['htmlOptions'] : array();
			$linkOptions = isset($itemData['linkOptions']) ? $itemData['linkOptions'] : array();
			$visible     = isset($itemData['visible'])     ? $itemData['visible'] : true;
			
			$this->_items->add($id, new MenuItem($id, $label, $url, $weight, $htmlOptions, $linkOptions, $visible));
		}else{
			throw new CException(Util::t('The item id and label must at least be specified.'));
		}
	}
	
	public function addItems($items)
	{
		foreach($items as $itemData)
		{
			$this->addItem($itemData);
		}
	}
	
	public function removeItem($itemId)
	{
		if($this->_items->contains($itemId))
		{
			$this->_items->remove($itemId);
		}
	}
	
	public function getItems()
	{
		return $this->_items;
	}
	
	public function getItem($itemId)
	{
		return $this->_items->contains($itemId) ? $this->_items[$itemId] : null;
	}
	
	public function hasItem($itemId)
	{
		return $this->getItem($itemId) !== null;
	}
	
	public function getIsEmpty()
	{
		$count = 0;
		foreach($this->_items as $item)
		{
			if($item->getVisible())
			{
				$count++;
			}
		}
		return $count === 0;
	}
	
	public function getVisibleItems()
	{
		$visibleItems = new CMap;
		
		foreach($this->getItems() as $id => $item)
		{
			if($item->getVisible()===true)
			{
				$visibleItems->add($id, $item);
			}
		}
		return $visibleItems;
	}
	
	protected function compareItems($itemA, $itemB)
	{
		if($itemA instanceof MenuItem && $itemB instanceof MenuItem)
		{
			if($itemA->getWeight() === $itemB->getWeight())
			{
				return 0;
			}
			return ($itemA->getWeight() <= $itemB->getWeight()) ? -1 : 1;
		}else{
			throw new CException(Util::t('Both items must be instances of MenuItem or one of it\'s children.'));
		}
	}
	
	protected function sortItems($items)
	{
		$items = $items->toArray();
		
		uasort($items,array($this,'compareItems'));
		
		return new CMap($items);
	}
	
	public function render($return = false)
	{
		$menuContent = '';
		
		if($this->getVisibleItems()->count())
		{
			$menuContent .= CHtml::openTag('ul', $this->_htmlOptions)."\n";
			$menuContent .= $this->renderRecursive($this->getVisibleItems(), true);
			$menuContent .= CHtml::closeTag('ul')."\n";
		}
		if($return)
		{
			return $menuContent;
		}else{
			echo $menuContent;
		}
	}
	
	protected function renderRecursive($items, $return = false)
	{
		$items = $this->sortItems($items);
		
		$content = '';
		
		foreach($items as $item)
		{
			if($item instanceof MenuItem)
			{
				if($item->getVisible())
				{
					$content .= CHtml::openTag('li',$item->getHtmlOptions())."\n";
					$content .= CHtml::link($item->getLabel(), $item->getUrl(), $item->getLinkOptions());
					if(count($item->getVisibleItems()))
					{
						$content .= CHtml::openTag('ul')."\n";
						$content .= self::renderRecursive($item->getVisibleItems(), $return);
						$content .= CHtml::closeTag('ul')."\n";
					}
					$content .= CHtml::closeTag('li')."\n";
				}
			}
		}
		
		if($return)
		{
			return $content;
		}else{
			echo $content;
		}
	}
}

class MenuItem extends Menu
{
	protected $_label;
	protected $_url;
	protected $_weight;
	protected $_linkOptions = array();
	protected $_visible;
	
	public function __construct($id, $label, $url = '#', $weight = 0, $htmlOptions = array(), $linkOptions = array(), $visible = true)
	{
		$this->setId($id);
		$this->setLabel($label);
		$this->setUrl($url);
		$this->setWeight($weight);
		$this->setHtmlOptions($htmlOptions);
		$this->setLinkOptions($linkOptions);
		$this->setVisible($visible);
		
		$this->_items = new CMap;
		
		$this->init();
	}
	
	public function init()
	{
		parent::init();
	}
	
	public function getLabel()
	{
		return $this->_label;
	}
	
	public function getUrl()
	{
		return $this->_url;
	}
	
	public function getWeight()
	{
		return $this->_weight;
	}
	
	public function getLinkOptions()
	{
		return $this->_linkOptions;
	}
	
	public function getVisible()
	{
		return $this->_visible;
	}
	
	public function setLabel($label)
	{
		if(!is_string($label))
		{
			throw new CException(Util::t('The item label must be a string.'));
		}
		$this->_label = $label;
		return $this;
	}
	
	public function setUrl($url)
	{
		if(!(is_array($url) || is_string($url)))
		{
			throw new CException(Util::t('The item url must be a string or an array.'));
		}
		$this->_url = $url;
		return $this;
	}
	
	public function setWeight($weight)
	{
		if(!is_numeric($weight))
		{
			throw new CException(Util::t('The item weight must be a number.'));
		}
		$this->_weight = (int)$weight;
		return $this;
	}
	
	public function setLinkOptions($linkOptions, $mergeOld = false)
	{
		if(!is_array($linkOptions))
		{
			throw new CException(Util::t('The item link options must be a number.'));
		}
		if($mergeOld)
		{
			$this->_linkOptions = CMap::mergeArray($this->_linkOptions, $linkOptions);
		}else{
			$this->_linkOptions = $linkOptions;
		}
		return $this;
	}
	
	public function setVisible($visible)
	{
		if(!is_bool($visible))
		{
			throw new CException(Util::t('The item visibility must be set to a boolean value.'));
		}
		$this->_visible = $visible;
		return $this;
	}
}

class Navigation
{
	private static $_instance;
	
	private $_menus = array();
	
	public function __construct()
	{
		$this->_menus = new CMap;
	}
	
	public static function getInstance()
	{
		if(self::$_instance === null)
		{
			self::$_instance = new self;
		}
		return self::$_instance;
	}
	
	public static function getMenu($menuId)
	{
		$instance = self::getInstance();
		
		if(!$instance->_menus->contains($menuId))
		{
			$instance->_menus[$menuId] = new Menu($menuId);
		}
		return $instance->_menus[$menuId];
	}
	
	public static function removeMenu($menuId)
	{
		$instance = self::getInstance();
		if($instance->_menus->contains($menuId))
		{
			$instance->_menus->remove($menuId);
		}
	}
	
	public static function render($menuId, $return)
	{
		$menuData = '';
		if(($menu = self::getMenu($menuId)) !== null)
		{
			if(count($menu))
			{
				$menuData = $menu->render(true);
			}
		}
		if($return)
		{
			return $menuData;
		}else{
			echo $menuData;
		}
	}
}

php:
foreach(array('cat', 'dog', 'cow') as $animal) echo $animal."\n";

python:
[(animal, print(animal)) for animal in ['cat', 'dog', 'cow']]

ruby:
['cat', 'dog', 'cow'].each {|animal| puts animal}


You say Tomato, I say Tomato.
0

#7 User is offline   Bijay Rungta 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 4
  • Joined: 27-August 10

Posted 17 December 2010 - 01:45 AM

Why not Create an Extension or Something to share and improve?

How do you manage various Menu Items?

Do you have any Database Table to manage Menu Items?
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users