diff --git a/library/Icinga/Web/Menu.php b/library/Icinga/Web/Menu.php index a92679dfa..d5b7ba882 100644 --- a/library/Icinga/Web/Menu.php +++ b/library/Icinga/Web/Menu.php @@ -1,41 +1,83 @@ - * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 - * @author Icinga Development Team - * - */ // {{{ICINGA_LICENSE_HEADER}}} namespace Icinga\Web; -use Icinga\Logger\Logger; +use Zend_Config; +use RecursiveIterator; use Icinga\Application\Config; use Icinga\Application\Icinga; -use Icinga\Exception\NotReadableError; +use Icinga\Exception\ProgrammingError; -class Menu extends MenuItem +class Menu implements RecursiveIterator { + /** + * The id of this menu + * + * @type string + */ + protected $id; + + /** + * The title of this menu + * + * Used for sorting when priority is unset or equal to other items + * + * @type string + */ + protected $title; + + /** + * The priority of this menu + * + * Used for sorting + * + * @type int + */ + protected $priority = 100; + + /** + * The url of this menu + * + * @type string + */ + protected $url; + + /** + * The path to the icon of this menu + * + * @type string + */ + protected $icon; + + /** + * The sub menus of this menu + * + * @type array + */ + protected $subMenus = array(); + + /** + * Create a new menu + * + * @param int $id The id of this menu + * @param Zend_Config $config The configuration for this menu + */ + public function __construct($id, Zend_Config $config = null) + { + $this->id = $id; + + if ($config !== null) { + foreach ($config as $key => $value) { + $method = 'set' . implode('', array_map('ucfirst', explode('_', strtolower($key)))); + if (method_exists($this, $method)) { + $this->{$method}($value); + } + } + } + } + /** * Create menu from the application's menu config file plus the config files from all enabled modules * @@ -45,35 +87,236 @@ class Menu extends MenuItem { $menu = new static('menu'); $manager = Icinga::app()->getModuleManager(); - - try { - $menuConfigs = array(Config::app('menu')); - } catch (NotReadableError $e) { - Logger::error($e); - $menuConfigs = array(); - } - - try { - $modules = $manager->listEnabledModules(); - } catch (NotReadableError $e) { - Logger::error($e); - $modules = array(); - } + $modules = $manager->listEnabledModules(); + $menuConfigs = array(Config::app('menu')); foreach ($modules as $moduleName) { - try { - $moduleMenuConfig = Config::module($moduleName, 'menu'); - } catch (NotReadableError $e) { - Logger::error($e); - $moduleMenuConfig = array(); - } - - if (!empty($moduleMenuConfig)) { + $moduleMenuConfig = Config::module($moduleName, 'menu'); + if (false === empty($moduleMenuConfig)) { $menuConfigs[] = $moduleMenuConfig; } } - return $menu->loadMenuItems($menu->flattenConfigs($menuConfigs)); + return $menu->loadSubMenus($menu->flattenConfigs($menuConfigs)); + } + + /** + * Set the id of this menu + * + * @param string $id The id to set for this menu + * + * @return self + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Return the id of this menu + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Set the title of this menu + * + * @param string $title The title to set for this menu + * + * @return self + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Return the title of this menu if set, otherwise its id + * + * @return string + */ + public function getTitle() + { + return $this->title ? $this->title : $this->id; + } + + /** + * Set the priority of this menu + * + * @param int $priority The priority to set for this menu + * + * @return self + */ + public function setPriority($priority) + { + $this->priority = (int) $priority; + return $this; + } + + /** + * Return the priority of this menu + * + * @return int + */ + public function getPriority() + { + return $this->priority; + } + + /** + * Set the url of this menu + * + * @param string $url The url to set for this menu + * + * @return self + */ + public function setUrl($url) + { + $this->url = $url; + return $this; + } + + /** + * Return the url of this menu + * + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * Set the path to the icon of this menu + * + * @param string $path The path to the icon for this menu + * + * @return self + */ + public function setIcon($path) + { + $this->icon = $path; + return $this; + } + + /** + * Return the path to the icon of this menu + * + * @return string + */ + public function getIcon() + { + return $this->icon; + } + + /** + * Return whether this menu has any sub menus + * + * @return bool + */ + public function hasSubMenus() + { + return false === empty($this->subMenus); + } + + /** + * Add a sub menu to this menu + * + * @param string $id The id of the menu to add + * @param Zend_Config $itemConfig The config with which to initialize the menu + * + * @return self + */ + public function addSubMenu($id, Zend_Config $menuConfig = null) + { + if (false === ($pos = strpos($id, '.'))) { + $subMenu = new self($id, $menuConfig); + $this->subMenus[$id] = $subMenu; + } else { + list($parentId, $id) = explode('.', $id, 2); + + if ($this->hasSubMenu($parentId)) { + $parent = $this->getSubMenu($parentId); + } else { + $parent = $this->addSubMenu($parentId); + } + + $subMenu = $parent->addSubMenu($id, $menuConfig); + } + + return $subMenu; + } + + /** + * Return whether a sub menu with the given id exists + * + * @param string $id The id of the sub menu + * + * @return bool + */ + public function hasSubMenu($id) + { + return array_key_exists($id, $this->subMenus); + } + + /** + * Get sub menu by its id + * + * @param string $id The id of the sub menu + * + * @return Menu The found sub menu + * + * @throws ProgrammingError In case there is no sub menu with the given id to be found + */ + public function getSubMenu($id) + { + if (false === $this->hasSubMenu($id)) { + throw new ProgrammingError('Tried to get invalid sub menu "' . $id . '"'); + } + + return $this->subMenus[$id]; + } + + /** + * Order this menu's sub menus based on their priority + * + * @return self + */ + public function order() + { + uasort($this->subMenus, array($this, 'cmpSubMenus')); + foreach ($this->subMenus as $subMenu) { + if ($subMenu->hasSubMenus()) { + $subMenu->order(); + } + } + + return $this; + } + + /** + * Compare sub menus based on priority and title + * + * @param Menu $a + * @param Menu $b + * + * @return int + */ + protected function cmpSubMenus($a, $b) + { + if ($a->priority == $b->priority) { + return $a->getTitle() > $b->getTitle() ? 1 : ( + $a->getTitle() < $b->getTitle() ? -1 : 0 + ); + } + + return $a->priority > $b->priority ? 1 : -1; } /** @@ -83,7 +326,7 @@ class Menu extends MenuItem * * @return array The flattened config, as key-value array */ - public function flattenConfigs(array $configs) + protected function flattenConfigs(array $configs) { $flattened = array(); foreach ($configs as $menuConfig) { @@ -99,18 +342,89 @@ class Menu extends MenuItem } /** - * Load menu items + * Load the sub menus * - * @param array $items The items to load, as key-value array + * @param array $menus The menus to load, as key-value array * * @return self */ - public function loadMenuItems(array $items) + protected function loadSubMenus(array $menus) { - foreach ($items as $id => $itemConfig) { - $this->addChild($id, $itemConfig); + foreach ($menus as $menuId => $menuConfig) { + $this->addSubMenu($menuId, $menuConfig); } return $this; } + + /** + * Check whether the current menu node has any sub menus + * + * @return bool + */ + public function hasChildren() + { + $current = $this->current(); + if (false !== $current) { + return $current->hasSubMenus(); + } + + return false; + } + + /** + * Return a iterator for the current menu node + * + * @return RecursiveIterator + */ + public function getChildren() + { + return $this->current(); + } + + /** + * Rewind the iterator to its first menu node + */ + public function rewind() + { + reset($this->subMenus); + } + + /** + * Return whether the iterator position is valid + * + * @return bool + */ + public function valid() + { + return $this->key() !== null; + } + + /** + * Return the current menu node + * + * @return Menu + */ + public function current() + { + return current($this->subMenus); + } + + /** + * Return the id of the current menu node + * + * @return string + */ + public function key() + { + return key($this->subMenus); + } + + /** + * Move the iterator to the next menu node + */ + public function next() + { + next($this->subMenus); + } } diff --git a/library/Icinga/Web/MenuItem.php b/library/Icinga/Web/MenuItem.php deleted file mode 100644 index 6f5394ca6..000000000 --- a/library/Icinga/Web/MenuItem.php +++ /dev/null @@ -1,361 +0,0 @@ -id = $id; - if ($config !== null) { - $this->setConfig($config); - } - } - - /** - * Setter for id - * - * @param string $id - * - * @return self - */ - public function setId($id) - { - $this->id = $id; - return $this; - } - - /** - * Getter for id - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Setter for title - * - * @param string $title - * - * @return self - */ - public function setTitle($title) - { - $this->title = $title; - return $this; - } - - /** - * Getter for title - * - * @return string - */ - public function getTitle() - { - return $this->title ? $this->title : $this->id; - } - - /** - * Setter for priority - * - * @param int $priority - * - * @return self - */ - public function setPriority($priority) - { - $this->priority = (int) $priority; - return $this; - } - - /** - * Getter for priority - * - * @return int - */ - public function getPriority() - { - return $this->priority; - } - - /** - * Setter for URL - * - * @param string $url - * - * @return self - */ - public function setUrl($url) - { - $this->url = $url; - return $this; - } - - /** - * Getter for URL - * - * @return string - */ - public function getUrl() - { - return $this->url; - } - - /** - * Setter for icon path - * - * @param string $path - * - * @return self - */ - public function setIcon($path) - { - $this->icon = $path; - return $this; - } - - /** - * Getter for icon path - * - * @return string - */ - public function getIcon() - { - return $this->icon; - } - - /** - * Setter for icon class - * - * @param string $iconClass - * - * @return self - */ - public function setIconClass($iconClass) - { - $this->iconClass = $iconClass; - return $this; - } - - /** - * Getter for icon class - * - * @return string - */ - public function getIconClass() - { - return $this->iconClass; - } - - /** - * Set the configuration for the item - * - * @param Zend_Config $config - */ - public function setConfig($config) - { - foreach ($config as $key => $value) { - $method = 'set' . implode('', array_map('ucfirst', explode('_', strtolower($key)))); - if (method_exists($this, $method)) { - $this->{$method}($value); - } - } - } - - /** - * Add a child to MenuItem - * - * @param string $id - * @param object $itemConfig - * - * @return self - */ - public function addChild($id, $itemConfig = null) - { - if (false === ($pos = strpos($id, '.'))) { - // Root item - $menuItem = new self($id, $itemConfig); - $this->children[$id] = $menuItem; - } else { - // Submenu item - list($parentId, $id) = explode('.', $id, 2); - - if ($this->hasChild($parentId)) { - $parent = $this->getChild($parentId); - } else { - $parent = $this->addChild($parentId); - } - - $menuItem = $parent->addChild($id, $itemConfig); - } - - return $menuItem; - } - - /** - * Check whether the item has any children - * - * @return bool - */ - public function hasChildren() - { - return !empty($this->children); - } - - /** - * Get sorted children - * - * @return array - * - * @see MenuItem::cmpChildren() - */ - public function getChildren() - { - usort($this->children, array($this, 'cmpChildren')); - return $this->children; - } - - /** - * Return whether a given child id exists - * - * @param string $id - * - * @return bool - */ - public function hasChild($id) - { - return array_key_exists($id, $this->children); - } - - /** - * Get child by its id - * - * @param string $id - * @param mixed $default - * - * @return MenuItem - * - * @throws ProgrammingError - */ - public function getChild($id) - { - if (!$this->hasChild($id)) { - throw new ProgrammingError(sprintf('Trying to get invalid Menu child "%s"', $id)); - } - - return $this->children[$id]; - } - - /** - * Set HTML anchor tag attributes - * - * @param array $attribs - * - * @return self - */ - public function setAttribs(array $attribs) - { - $this->attribs = $attribs; - return $this; - } - - /** - * Get HTML anchor tag attributes - * - * @return array - */ - public function getAttribs() - { - return $this->attribs; - } - - /** - * Compare children based on priority and title - * - * @param MenuItem $a - * @param MenuItem $b - * - * @return int - */ - protected function cmpChildren($a, $b) - { - if ($a->priority === $b->priority) { - return ($a->getTitle() > $b->getTitle()) ? 1 : -1; - } - - return ($a->priority > $b->priority) ? 1 : -1; - } -}