// SPDX-License-Identifier: GPL-3.0-or-later
namespace Icinga\Web\Navigation\Renderer;
use ArrayIterator;
use Exception;
use RecursiveIterator;
use Icinga\Application\Icinga;
use Icinga\Exception\IcingaException;
use Icinga\Web\Navigation\Navigation;
use Icinga\Web\Navigation\NavigationItem;
use Icinga\Web\View;
/**
* Renderer for single level navigation
*/
class NavigationRenderer implements RecursiveIterator, NavigationRendererInterface
{
/**
* The tag used for the outer element
*
* @var string
*/
protected $elementTag;
/**
* The CSS class used for the outer element
*
* @var string
*/
protected $cssClass;
/**
* The navigation's heading text
*
* @var string
*/
protected $heading;
/**
* The content rendered so far
*
* @var array
*/
protected $content;
/**
* Whether to skip rendering the outer element
*
* @var bool
*/
protected $skipOuterElement;
/**
* The navigation's iterator
*
* @var ArrayIterator
*/
protected $iterator;
/**
* The navigation
*
* @var Navigation
*/
protected $navigation;
/**
* View
*
* @var View
*/
protected $view;
/**
* Create a new NavigationRenderer
*
* @param Navigation $navigation
* @param bool $skipOuterElement
*/
public function __construct(Navigation $navigation, $skipOuterElement = false)
{
$this->skipOuterElement = $skipOuterElement;
$this->iterator = $navigation->getIterator();
$this->navigation = $navigation;
$this->content = array();
}
/**
* {@inheritdoc}
*/
public function setElementTag($tag)
{
$this->elementTag = $tag;
return $this;
}
/**
* {@inheritdoc}
*/
public function getElementTag()
{
return $this->elementTag ?: static::OUTER_ELEMENT_TAG;
}
/**
* {@inheritdoc}
*/
public function setCssClass($class)
{
$this->cssClass = $class;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCssClass()
{
return $this->cssClass;
}
/**
* {@inheritdoc}
*/
public function setHeading($heading)
{
$this->heading = $heading;
return $this;
}
/**
* {@inheritdoc}
*/
public function getHeading()
{
return $this->heading;
}
/**
* 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;
}
public function getChildren(): NavigationRenderer
{
return new static($this->current()->getChildren(), $this->skipOuterElement);
}
public function hasChildren(): bool
{
return $this->current()->hasChildren();
}
public function current(): NavigationItem
{
return $this->iterator->current();
}
public function key(): int
{
return $this->iterator->key();
}
public function next(): void
{
$this->iterator->next();
}
public function rewind(): void
{
$this->iterator->rewind();
if (! $this->skipOuterElement) {
$this->content[] = $this->beginMarkup();
}
}
public function valid(): bool
{
$valid = $this->iterator->valid();
if (! $this->skipOuterElement && !$valid) {
$this->content[] = $this->endMarkup();
}
return $valid;
}
/**
* Return the opening markup for the navigation
*
* @return string
*/
public function beginMarkup()
{
$content = array();
$content[] = sprintf(
'<%s%s role="navigation">',
$this->getElementTag(),
$this->getCssClass() !== null ? ' class="' . $this->getCssClass() . '"' : ''
);
if (($heading = $this->getHeading()) !== null) {
$content[] = sprintf(
'