4 * This file is part of Twig.
6 * (c) 2009 Fabien Potencier
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
13 * Loads template from the filesystem.
15 * @author Fabien Potencier <fabien@symfony.com>
17 class Twig_Loader_Filesystem
implements Twig_LoaderInterface
, Twig_ExistsLoaderInterface
19 /** Identifier of the main namespace. */
20 const MAIN_NAMESPACE
= '__main__';
28 * @param string|array $paths A path or an array of paths where to look for templates
30 public function __construct($paths = array())
33 $this->setPaths($paths);
38 * Returns the paths to the templates.
40 * @param string $namespace A path namespace
42 * @return array The array of paths where to look for templates
44 public function getPaths($namespace = self
::MAIN_NAMESPACE
)
46 return isset($this->paths
[$namespace]) ? $this->paths
[$namespace] : array();
50 * Returns the path namespaces.
52 * The main namespace is always defined.
54 * @return array The array of defined namespaces
56 public function getNamespaces()
58 return array_keys($this->paths
);
62 * Sets the paths where templates are stored.
64 * @param string|array $paths A path or an array of paths where to look for templates
65 * @param string $namespace A path namespace
67 public function setPaths($paths, $namespace = self
::MAIN_NAMESPACE
)
69 if (!is_array($paths)) {
70 $paths = array($paths);
73 $this->paths
[$namespace] = array();
74 foreach ($paths as $path) {
75 $this->addPath($path, $namespace);
80 * Adds a path where templates are stored.
82 * @param string $path A path where to look for templates
83 * @param string $namespace A path name
85 * @throws Twig_Error_Loader
87 public function addPath($path, $namespace = self
::MAIN_NAMESPACE
)
89 // invalidate the cache
90 $this->cache
= array();
93 throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
96 $this->paths
[$namespace][] = rtrim($path, '/\\');
100 * Prepends a path where templates are stored.
102 * @param string $path A path where to look for templates
103 * @param string $namespace A path name
105 * @throws Twig_Error_Loader
107 public function prependPath($path, $namespace = self
::MAIN_NAMESPACE
)
109 // invalidate the cache
110 $this->cache
= array();
112 if (!is_dir($path)) {
113 throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
116 $path = rtrim($path, '/\\');
118 if (!isset($this->paths
[$namespace])) {
119 $this->paths
[$namespace][] = $path;
121 array_unshift($this->paths
[$namespace], $path);
128 public function getSource($name)
130 return file_get_contents($this->findTemplate($name));
136 public function getCacheKey($name)
138 return $this->findTemplate($name);
144 public function exists($name)
146 $name = (string) $name;
147 if (isset($this->cache
[$name])) {
152 $this->findTemplate($name);
155 } catch (Twig_Error_Loader
$exception) {
163 public function isFresh($name, $time)
165 return filemtime($this->findTemplate($name)) <= $time;
168 protected function findTemplate($name)
170 $name = (string) $name;
173 $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
175 if (isset($this->cache
[$name])) {
176 return $this->cache
[$name];
179 $this->validateName($name);
181 $namespace = self
::MAIN_NAMESPACE
;
182 if (isset($name[0]) && '@' == $name[0]) {
183 if (false === $pos = strpos($name, '/')) {
184 throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
187 $namespace = substr($name, 1, $pos - 1);
189 $name = substr($name, $pos +
1);
192 if (!isset($this->paths
[$namespace])) {
193 throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
196 foreach ($this->paths
[$namespace] as $path) {
197 if (is_file($path.'/'.$name)) {
198 return $this->cache
[$name] = $path.'/'.$name;
202 throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths
[$namespace])));
205 protected function validateName($name)
207 if (false !== strpos($name, "\0")) {
208 throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
211 $name = ltrim($name, '/');
212 $parts = explode('/', $name);
214 foreach ($parts as $part) {
215 if ('..' === $part) {
217 } elseif ('.' !== $part) {
222 throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));