spotonlive/sl-navigation

View on GitHub
src/SpotOnLive/Navigation/Navigation/Container.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php

namespace SpotOnLive\Navigation\Navigation;

use Auth;
use SpotOnLive\Navigation\Options\ContainerOptions;
use SpotOnLive\Navigation\Exceptions\IllegalConfigurationException;

class Container implements ContainerInterface
{
    /** @var ContainerOptions */
    protected $options;

    /** @var null */
    protected $assertionService;

    /**
     * @param array $config
     * @param null $assertionService
     */
    public function __construct(array $config = [], $assertionService = null)
    {
        $this->options = new ContainerOptions($config);
        $this->assertionService = $assertionService;

        $this->prepare();
    }

    /**
     * Render navigation in partial
     *
     * @param string $partial
     * @return string
     */
    public function renderPartial($partial)
    {
        $html = view($partial, [
            'container' => $this,
        ]);

        return (string) $html;
    }

    /**
     * Render navigation
     *
     * @param null|integer $maxDepth
     * @return string
     */
    public function render($maxDepth = null)
    {
        $options = $this->getOptions()->get('options');
        $class = $options['ul_class'];

        $html = sprintf(
            "<ul class=\"%s\"%s>\n",
            $class,
            $this->getAttributes()
        );

        foreach ($this->getPages() as $page) {
            $html .= $this->renderPage($page, $maxDepth);
        }

        $html .= '</ul>';

        return $html;
    }

    /**
     * Check for a valid assertion service
     *
     * @throws IllegalConfigurationException
     */
    protected function validateAssertionService()
    {
        if (!$this->assertionService) {
            throw new IllegalConfigurationException(
                _('Please require spotonlive/assertions` to use assertions in your navigation')
            );
        }
    }

    /**
     * Render page
     *
     * @param \SpotOnLive\Navigation\Navigation\Page $page
     * @param null $maxDepth
     * @param int $depth
     * @return null|string
     * @throws \SpotOnLive\Navigation\Exceptions\NoRouteException
     */
    public function renderPage(Page $page, $maxDepth = null, $depth = 0)
    {
        // Check for depth
        if (!is_null($maxDepth) && $depth > $maxDepth) {
            return null;
        }

        $options = $page->getOptions()->get('options');
        $classes = [];

        // Check if the page should be rendered
        if (!$options['render']) {
            return null;
        }

        // Check for assertions
        if (isset($options['assertion'])) {
            $this->validateAssertionService();

            if (!$this->assertionService->isGranted($options['assertion'], $this->getUser())) {
                return null;
            }
        }

        // CSS class for li
        if ($options['li_class']) {
            $classes[] = $options['li_class'];
        }

        // Active page
        if ($page->isActive()) {
            $classes[] = 'active';
        }

        $html = sprintf(
            "      <a href=\"%s\"%s>%s</a>\n",
            $page->getUrl(),
            $page->getAttributes('a'),
            $page->getLabel()
        );

        $pages = $page->getPages();

        if (count($pages) && (is_null($maxDepth) || $maxDepth != $depth)) {
            $ul_class = $options['ul_class'];

            $html .= sprintf(
                "      <ul class=\"%s\"%s>\n",
                $ul_class,
                $page->getAttributes('ul')
            );

            foreach ($pages as $subPage) {
                $html .= $this->renderPage($subPage, $maxDepth, ($depth + 1));
            }

            $html .= "      </ul>\n";
        }

        // Use wrapper from config
        $wrappedHtml = sprintf(
            $options['wrapper'],
            $html
        );

        // Wrap in <li> tag
        $li = sprintf(
            "   <li class=\"%s\"%s>\n%s    </li>\n",
            implode(" ", $classes),
            $page->getAttributes('li'),
            $wrappedHtml
        );

        return $li;
    }

    /**
     * Get pages
     *
     * @return array|Page[]
     */
    public function getPages()
    {
        $pagesArray = $this->getOptions()->get('pages');

        if (is_null($pagesArray)) {
            $pagesArray = [];
        }

        $pages = [];

        foreach ($pagesArray as $pageConfig) {
            $page = new Page($pageConfig);
            $pages[] = $page;
        }

        return $pages;
    }

    /**
     * Get attributes as string
     *
     * @return string
     */
    public function getAttributes()
    {
        $attributes = $this->getOptions()->get('ul_attributes');

        if (is_null($attributes)) {
            $attributes = [];
        }

        $attributesString = [];

        foreach ($attributes as $attr => $val) {
            $val = htmlspecialchars($val);
            $attributesString[] = sprintf('%s="%s"', $attr, $val);
        }

        $attributes = implode(" ", $attributesString);

        if (!$attributes) {
            return null;
        }

        return " " . $attributes;
    }

    /**
     * Prepare container
     *
     * @return bool
     * @throws IllegalConfigurationException
     */
    protected function prepare()
    {
        $options = $this->getOptions();

        $providerClass = $options->get('provider');
        $providerOptions = $options->get('provider_options');

        if (!class_exists($providerClass)) {
            throw new IllegalConfigurationException(
                sprintf(
                    'Provider class not found: %s',
                    $providerClass
                )
            );
        }

        /** @var Providers\NavigationProviderInterface $provider */
        $provider = app($providerClass);

        if (!$provider instanceof Providers\NavigationProviderInterface) {
            throw new IllegalConfigurationException(
                sprintf(
                    '%s must implement %s',
                    $providerClass,
                    Providers\NavigationProviderInterface::class
                )
            );
        }

        $provider->setOptions($providerOptions);

        $this->setOptions($provider->resolve($options));

        return true;
    }

    /**89
     * @return ContainerOptions
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * @param ContainerOptions $options
     */
    public function setOptions($options)
    {
        $this->options = $options;
    }

    /**
     * Get user
     */
    protected function getUser()
    {
        return Auth::user();
    }

    /**
     * @return null
     */
    public function getAssertionService()
    {
        return $this->assertionService;
    }

    /**
     * @param null $assertionService
     */
    public function setAssertionService($assertionService)
    {
        $this->assertionService = $assertionService;
    }
}