<?php
class Menu
{
const MENU_CACHE_KEY = 'menu_cache';
/** @var MenuItem[] */
protected $rootNodes = array();
protected $childNodes = array();
/** @var ICache */
protected $cache;
/**
* @param ICache $cache
*/
public function setCache(ICache $cache)
{
$this->cache = $cache;
}
public function hasCache()
{
return $this->cache instanceof ICache;
}
/**
* @param MenuItem $menuItem
*/
public function add(MenuItem $menuItem)
{
if ($menuItem->isParent()) {
$this->addRootNode($menuItem);
} else {
$this->addChildNode($menuItem);
}
}
/**
* @param MenuItem $menuItem
*/
private function addRootNode(MenuItem $menuItem)
{
array_push($this->rootNodes, $menuItem);
}
/**
* @param MenuItem $menuItem
*/
private function addChildNode(MenuItem $menuItem)
{
$this->ensureChildNodeExists($menuItem->parentId);
array_push($this->childNodes[$menuItem->parentId], $menuItem);
}
/**
* @param int $parentId
*/
private function ensureChildNodeExists($parentId)
{
if (!isset($this->childNodes[$parentId])) {
$this->childNodes[$parentId] = array();
}
}
/**
* @return string
*/
public function render()
{
if ($this->hasCache()) {
$cached = $this->cache->getItem(self::MENU_CACHE_KEY);
if (!empty($cached)) {
return $cached;
}
}
$html = '<ul>';
foreach ($this->rootNodes as $menuItem) {
$html .= '<li>' . $menuItem->render();
if (!empty($this->childNodes[$menuItem->id])) {
$html .= '<ul>';
/** @var $childMenuItem MenuItem */
foreach ($this->childNodes[$menuItem->id] as $childMenuItem) {
$html .= '<li>' . $childMenuItem->render() . '</li>';
}
$html .= '</ul>';
}
$html .= '</li>';
}
$html .= '</ul>';
if ($this->hasCache()) {
$this->cache->setItem(self::MENU_CACHE_KEY, $html);
}
return $html;
}
}
class MenuItem
{
public $id;
public $parentId;
public $label;
public $link;
/**
* @param array|null $params
*/
public function __construct($params = null)
{
if (!is_null($params)) {
$this->id = (int) $params['id'];
$this->label = $params['label'];
$this->link = $params['link'];
$this->parentId = (int) $params['parent_id'];
}
}
/**
* @return bool
*/
public function isParent()
{
return $this->parentId === 0;
}
/**
* @return string
*/
public function render()
{
return '<a href="' . $this->link . '">' . $this->label . '</a>';
}
}
interface ICache
{
/**
* @param string $key
*
* @return string|null
*/
public function getItem($key);
/**
* @param string $key
* @param string $value
*/
public function setItem($key, $value);
}
$dbResults = array(
array('id' => 1, 'parent_id' => 0, 'link' => '#', 'label' => 'Home'),
array('id' => 2, 'parent_id' => 0, 'link' => '#', 'label' => 'Portfolio'),
array('id' => 3, 'parent_id' => 0, 'link' => '#', 'label' => 'Projects'),
array('id' => 4, 'parent_id' => 2, 'link' => '#', 'label' => 'Design'),
array('id' => 5, 'parent_id' => 2, 'link' => '#', 'label' => 'Dev'),
array('id' => 6, 'parent_id' => 2, 'link' => '#', 'label' => 'Foo'),
array('id' => 7, 'parent_id' => 3, 'link' => '#', 'label' => 'Bar'),
);
$menu = new Menu();
/*
$menu->setCache(new RedisCache());
$menu->setCache(new FileCache());
$menu->setCache(new MemcachedCache());
*/
foreach ($dbResults as $row) {
$menu->add(new MenuItem($row));
}
echo $menu->render();
preferences:
32.71 ms | 402 KiB | 5 Q