此实现应该允许更轻松的定制。
用法:
<?php $orderLevelList = new OrderedLevelList; ?>
<ul class="main-menu">
<?php echo $orderLevelList->render($pages) ?>
</ul>
代码:
<?php
/**
* Menu generator - expects that outer UL already exists (to allow custom class for example)
*/
class OrderedLevelList
{
/**
* Renders list
*
* @param array $pages array
* @return string
*/
public function render($pages)
{
$result = '';
$lastLevel = $this->_getIntialLevel();
foreach ($pages as $page) {
$pageLevel = $this->_getLevel($page);
if ($pageLevel > $lastLevel) {
$result .= $this->_openList($pageLevel);
} elseif ($pageLevel < $lastLevel) {
$levelDiff = $lastLevel - $pageLevel;
for ($i = $levelDiff; $i >= 0; $i--) {
$result .= $this->_closeList($pageLevel);
$result .= $this->_closeItem();
}
} else {
$result .= $this->_closeItem();
}
$result .= $this->_openItem($page);
$result .= $this->_renderItem($page);
$lastLevel = $pageLevel;
}
$result .= $this->_closeItem();
return $result;
}
/**
* Renders contents of the item (what's inside the item)
*
* @param mixed $page
* @return string
*/
protected function _renderItem($page)
{
return sprintf('<a href="%s">%s</a>', $page['url'], $page['name']);
}
/**
* Accessor for the level attribute
*
* Can be overridden if you use objects instead of associative arrays
*
* @param mixed $page
* @return int
*/
protected function _getLevel($page)
{
return $page['level'];
}
/**
* Opens new level of list
*
* Can be overridden if you want for example OLs
*
* @param int $currentLevel
* @return string
*/
protected function _openList($currentLevel)
{
return sprintf('<ul class="%s">', 'level-' . $currentLevel);
}
/**
* Opens new item of list
*
* Override if you need more complex markup of items
*
* @param mixed $page
* @return string
*/
protected function _openItem($page)
{
return sprintf('<li class="%s">', 'item-' . $page['id']);
}
/**
* Closes current level of the list
*
* @param int $currentLevel
* @return string
*/
protected function _closeList($currentLevel)
{
return '</ul>';
}
/**
* Closes the previous item
*
* The actual item being closed cannot be accessed due to
* the way the algorithm works
*
* @return string
*/
protected function _closeItem()
{
return '</li>';
}
/**
* @return int
*/
protected function _getIntialLevel()
{
return 1;
}
}