1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\Loader;
13
14use Twig\Error\LoaderError;
15
16/**
17 * Loads templates from other loaders.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21final class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface
22{
23    private $hasSourceCache = [];
24    private $loaders = [];
25
26    /**
27     * @param LoaderInterface[] $loaders
28     */
29    public function __construct(array $loaders = [])
30    {
31        foreach ($loaders as $loader) {
32            $this->addLoader($loader);
33        }
34    }
35
36    public function addLoader(LoaderInterface $loader)
37    {
38        $this->loaders[] = $loader;
39        $this->hasSourceCache = [];
40    }
41
42    /**
43     * @return LoaderInterface[]
44     */
45    public function getLoaders()
46    {
47        return $this->loaders;
48    }
49
50    public function getSourceContext($name)
51    {
52        $exceptions = [];
53        foreach ($this->loaders as $loader) {
54            if (!$loader->exists($name)) {
55                continue;
56            }
57
58            try {
59                return $loader->getSourceContext($name);
60            } catch (LoaderError $e) {
61                $exceptions[] = $e->getMessage();
62            }
63        }
64
65        throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
66    }
67
68    public function exists($name)
69    {
70        if (isset($this->hasSourceCache[$name])) {
71            return $this->hasSourceCache[$name];
72        }
73
74        foreach ($this->loaders as $loader) {
75            if ($loader->exists($name)) {
76                return $this->hasSourceCache[$name] = true;
77            }
78        }
79
80        return $this->hasSourceCache[$name] = false;
81    }
82
83    public function getCacheKey($name)
84    {
85        $exceptions = [];
86        foreach ($this->loaders as $loader) {
87            if (!$loader->exists($name)) {
88                continue;
89            }
90
91            try {
92                return $loader->getCacheKey($name);
93            } catch (LoaderError $e) {
94                $exceptions[] = \get_class($loader).': '.$e->getMessage();
95            }
96        }
97
98        throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
99    }
100
101    public function isFresh($name, $time)
102    {
103        $exceptions = [];
104        foreach ($this->loaders as $loader) {
105            if (!$loader->exists($name)) {
106                continue;
107            }
108
109            try {
110                return $loader->isFresh($name, $time);
111            } catch (LoaderError $e) {
112                $exceptions[] = \get_class($loader).': '.$e->getMessage();
113            }
114        }
115
116        throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
117    }
118}
119
120class_alias('Twig\Loader\ChainLoader', 'Twig_Loader_Chain');
121