Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move to a Twig Loader concept #278

Open
gabrielsolomon opened this issue May 19, 2021 · 3 comments
Open

Move to a Twig Loader concept #278

gabrielsolomon opened this issue May 19, 2021 · 3 comments

Comments

@gabrielsolomon
Copy link

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;
    }
}
@ragboyjr
Copy link
Contributor

Hi @gabrielsolomon, you’d have to show me how this would be used and the differences between themes/folders. I’m not opposed to unifying them or offering an additional solution.

@gabrielsolomon
Copy link
Author

Thank you for your reply!
I tried to make a PR with how i see it #280

@luri-fr
Copy link

luri-fr commented Jun 17, 2022

Hi,

Like I comment in PR #280, i love concept and syntax.
Please accept the PR.

Is have some work to finalyse the PR ? Do you want help for that ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants