diff --git a/library/Icinga/Web/Navigation/NavigationItem.php b/library/Icinga/Web/Navigation/NavigationItem.php index 2c70bf37e..86aa39467 100644 --- a/library/Icinga/Web/Navigation/NavigationItem.php +++ b/library/Icinga/Web/Navigation/NavigationItem.php @@ -9,7 +9,7 @@ use IteratorAggregate; use Icinga\Application\Icinga; use Icinga\Exception\IcingaException; use Icinga\Exception\ProgrammingError; -use Icinga\Web\View; +use Icinga\Web\Navigation\Renderer\NavigationItemRenderer; use Icinga\Web\Url; /** @@ -24,6 +24,11 @@ class NavigationItem implements IteratorAggregate */ const LINK_ALTERNATIVE = 'span'; + /** + * The class namespace where to locate navigation type renderer classes + */ + const RENDERER_NS = 'Web\\Navigation\\Renderer'; + /** * Whether this item is active * @@ -97,11 +102,11 @@ class NavigationItem implements IteratorAggregate protected $urlParameters; /** - * View + * This item's renderer * - * @var View + * @var NavigationItemRenderer */ - protected $view; + protected $renderer; /** * Create a new NavigationItem @@ -500,33 +505,6 @@ class NavigationItem implements IteratorAggregate return $this; } - /** - * Return the view - * - * @return View - */ - public function view() - { - if ($this->view === null) { - $this->setView(Icinga::app()->getViewRenderer()->view); - } - - return $this->view; - } - - /** - * Set the view - * - * @param View $view - * - * @return $this - */ - public function setView(View $view) - { - $this->view = $view; - return $this; - } - /** * Set this item's properties * @@ -600,6 +578,79 @@ class NavigationItem implements IteratorAggregate return $this->getUrl() !== $item->getUrl(); } + /** + * Create and return the given renderer + * + * @param string $name + * + * @return NavigationItemRenderer + */ + protected function createRenderer($name) + { + $renderer = null; + foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) { + $classPath = 'Icinga\\Module\\' . $module->getName() . '\\' . static::RENDERER_NS . '\\' . $name; + if (class_exists($classPath)) { + $renderer = new $classPath(); + break; + } + } + + if ($renderer === null) { + $classPath = 'Icinga\\' . static::RENDERER_NS . '\\' . $name; + if (class_exists($classPath)) { + $renderer = new $classPath(); + } + } + + if ($renderer === null) { + throw new ProgrammingError( + 'Cannot find renderer "%s" for navigation item "%s"', + $name, + $this->getName() + ); + } elseif (! $renderer instanceof NavigationItemRenderer) { + throw new ProgrammingError('Class %s must inherit from NavigationItemRenderer', $classPath); + } + + return $renderer; + } + + /** + * Set this item's renderer + * + * @param string|NavigationItemRenderer $renderer + * + * @return $this + * + * @throws InvalidArgumentException If the $renderer argument is neither a string nor a NavigationItemRenderer + */ + public function setRenderer($renderer) + { + if (is_string($renderer)) { + $renderer = $this->createRenderer($renderer); + } elseif (! $renderer instanceof NavigationItemRenderer) { + throw new InvalidArgumentException('Argument $renderer must be of type string or NavigationItemRenderer'); + } + + $this->renderer = $renderer; + return $this; + } + + /** + * Return this item's renderer + * + * @return NavigationItemRenderer + */ + public function getRenderer() + { + if ($this->renderer === null) { + $this->setRenderer('NavigationItemRenderer'); + } + + return $this->renderer; + } + /** * Return this item rendered to HTML * @@ -607,28 +658,7 @@ class NavigationItem implements IteratorAggregate */ public function render() { - $label = $this->view()->escape($this->getLabel()); - if (($icon = $this->getIcon()) !== null) { - $label = $this->view()->icon($icon) . $label; - } - - if (($url = $this->getUrl()) !== null) { - $content = sprintf( - '%s', - $this->view()->propertiesToString($this->getAttributes()), - $this->view()->url($url, $this->getUrlParameters()), - $label - ); - } else { - $content = sprintf( - '<%1$s%2$s>%3$s', - static::LINK_ALTERNATIVE, - $this->view()->propertiesToString($this->getAttributes()), - $label - ); - } - - return $content; + $this->getRenderer()->render($this); } /** diff --git a/library/Icinga/Web/Navigation/Renderer/NavigationItemRenderer.php b/library/Icinga/Web/Navigation/Renderer/NavigationItemRenderer.php new file mode 100644 index 000000000..3a9d377e2 --- /dev/null +++ b/library/Icinga/Web/Navigation/Renderer/NavigationItemRenderer.php @@ -0,0 +1,81 @@ +view === null) { + $this->setView(Icinga::app()->getViewRenderer()->view); + } + + return $this->view; + } + + /** + * Set the view + * + * @param View $view + * + * @return $this + */ + public function setView(View $view) + { + $this->view = $view; + return $this; + } + + /** + * Render the given navigation item as HTML anchor + * + * @param NavigationItem $item + * + * @return string + */ + public function render(NavigationItem $item) + { + $label = $this->view()->escape($item->getLabel()); + if (($icon = $item->getIcon()) !== null) { + $label = $this->view()->icon($icon) . $label; + } + + if (($url = $item->getUrl()) !== null) { + $content = sprintf( + '%s', + $this->view()->propertiesToString($item->getAttributes()), + $this->view()->url($url, $item->getUrlParameters()), + $label + ); + } else { + $content = sprintf( + '<%1$s%2$s>%3$s', + $item::LINK_ALTERNATIVE, + $this->view()->propertiesToString($item->getAttributes()), + $label + ); + } + + return $content; + } +}