url = $url;
        } else {
            $this->url = Url::fromPath($url);
        }
        $this->defaultRenderer = new MenuItemRenderer();
        parent::__construct(new PermittedMenuItemFilter($menu), RecursiveIteratorIterator::CHILD_FIRST);
    }
    /**
     * @param bool $value
     */
    public function useCustomRenderer($value = true)
    {
        $this->useCustomRenderer = $value;
        return $this;
    }
    /**
     * Register the outer ul opening html-tag
     */
    public function beginIteration()
    {
        $this->tags[] = '
';
    }
    /**
     * Register the outer ul closing html-tag
     */
    public function endIteration()
    {
        $this->tags[] = '
';
    }
    /**
     * Register a inner ul opening html-tag
     */
    public function beginChildren()
    {
        // The iterator runs in mode CHILD_FIRST so we need to remember
        // where to insert the parent's opening html tag once its rendered
        $parent = $this->getSubIterator(0)->current();
        $this->tags[$parent->getId() . '_begin'] = null;
        $this->tags[] = '';
    }
    /**
     * Register a inner ul closing html-tag
     */
    public function endChildren()
    {
        $this->tags[] = '
';
        // Remember the position of the parent's closing html-tag
        $parent = $this->getSubIterator(0)->current();
        $this->tags[$parent->getId() . '_end'] = null;
    }
    /**
     * Render the given child
     *
     * @param   Menu    $child      The menu's child to render
     *
     * @return  string              The child rendered as html
     */
    public function renderChild(Menu $child)
    {
        if ($child->getRenderer() !== null && $this->useCustomRenderer) {
            try {
                return $child->getRenderer()->render($child);
            } catch (Exception $e) {
                Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage());
            }
        }
        return $this->defaultRenderer->render($child);
    }
    /**
     * Return the menu rendered as html
     *
     * @return  string
     */
    public function render()
    {
        $passedActiveChild = false;
        foreach ($this as $child) {
            $childIsActive = $this->isActive($child);
            if ($childIsActive && $this->getDepth() > 0) {
                $passedActiveChild = true;
            }
            if ($childIsActive || ($passedActiveChild && $this->getDepth() === 0)) {
                $passedActiveChild &= $this->getDepth() !== 0;
                $openTag = '';
            } else {
                $openTag = '';
            }
            $content = $this->renderChild($child);
            $closingTag = '';
            if (array_key_exists($child->getId() . '_begin', $this->tags)) {
                $this->tags[$child->getId() . '_begin'] = $openTag . $content;
                $this->tags[$child->getId() . '_end'] = $closingTag;
            } else {
                $this->tags[] = $openTag . $content . $closingTag;
            }
        }
        return implode("\n", $this->tags);
    }
    /**
     * @see MenuRenderer::render()
     */
    public function __toString()
    {
        return $this->render();
    }
    /**
     * Return whether the current request url references the child's url
     *
     * @param   Menu    $child      The menu's child to check
     *
     * @return  bool
     */
    protected function isActive(Menu $child)
    {
        if (! $this->url) return false;
        if (! ($childUrl = $child->getUrl())) return false;
        return $this->url && $this->url->matches($childUrl);
    }
}