Skip to content

Move to a Twig Loader concept #278

Open
@gabrielsolomon

Description

@gabrielsolomon

Hello,

I really like the new Theme functionality.

But i was wondering if it would be interesting to move to a Loader concept similar to Twig and incorporate both the folder and theme functionality in it. This would mean that all the template resolve would be incapsulated in one place.

I was thinking something in the like of the code below.

If this is interesting i would be happy to make a complete PR

FilesystemResolveTemplatePath {

    /**
     * Hint path delimiter value.
     *
     * @var string
     */
    public const HINT_PATH_DELIMITER = '::';

    /**
     * Identifier of the main namespace.
     *
     * @var string
     */
    public const MAIN_NAMESPACE = '__main__';

    /**
     * The array of active view paths.
     *
     * @var array
     */
    protected $paths = [];


    /**
     * Get the fully qualified location of the view.
     *
     * @param string $name
     * @return string
     */
    public function find($name)
    {
        list($namespace, $view) = $this->parseName($name);

        return $this->findNamespacedView($view, $namespace);
    }

    /**
     * Adds a path where templates are stored.
     *
     * @param string $path A path where to look for templates
     * @param string $namespace A path namespace
     *
     * @return void
     */
    public function addPath($path, $namespace = self::MAIN_NAMESPACE)
    {
        $this->paths[$namespace][] = rtrim($path, '/\\');
    }

    /**
     * Prepends a path where templates are stored.
     *
     * @param string $path A path where to look for templates
     * @param string $namespace A path namespace
     * @return void
     */
    public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
    {
        $path = rtrim($path, '/\\');

        if (!isset($this->paths[$namespace])) {
            $this->paths[$namespace][] = $path;
        } else {
            array_unshift($this->paths[$namespace], $path);
        }
    }

    /**
     * @param $name
     * @param string $namespace
     * @return array
     */
    public function parseName($name, $namespace = self::MAIN_NAMESPACE)
    {
        if ($this->hasNamespaceInformation($name = trim($name))) {
            return $this->parseNamespacedName($name);
        }
        return [$namespace, $name];
    }

    /**
     * Get the segments of a template with a named path.
     *
     * @param string $name
     * @return array
     *
     * @throws \InvalidArgumentException
     */
    protected function parseNamespacedName($name)
    {
        $segments = explode(static::HINT_PATH_DELIMITER, $name);
        if (count($segments) != 2) {
            throw new InvalidArgumentException("View [$name] has an invalid name.");
        }
        if (!isset($this->paths[$segments[0]]) || count($this->paths[$segments[0]]) < 1) {
            throw new InvalidArgumentException("No path defined for namespace [{$segments[0]}].");
        }
        return $segments;
    }

    /**
     * Get the path to a template with a named path.
     *
     * @param string $name
     * @param $namespace
     * @return string
     */
    protected function findNamespacedView($name, $namespace)
    {
        return $this->findInPaths($name, $this->paths[$namespace]);
    }

    /**
     * Find the given view in the list of paths.
     *
     * @param string $name
     * @param array $paths
     * @return string
     *
     * @throws \InvalidArgumentException
     */
    protected function findInPaths($name, $paths)
    {
        foreach ((array)$paths as $path) {
            $file = $this->getViewFilename($name);
            if (file_exists($viewPath = $path . '/' . $file)) {
                return $viewPath;
            }
        }
        throw new TemplateNotFound(
            $name,
            $paths,
            'View [' . $name . '] not found in paths [' . implode(', ', $paths) . '].'
        );
    }

    /**
     * Returns whether or not the view name has any hint information.
     *
     * @param string $name
     * @return bool
     */
    public function hasNamespaceInformation($name)
    {
        return strpos($name, static::HINT_PATH_DELIMITER) > 0;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions