composer package updates
[openemr.git] / vendor / twig / twig / lib / Twig / Loader / Filesystem.php
blob9149bc3ea46ff2651527f890537e972b70444c18
1 <?php
3 /*
4 * This file is part of Twig.
6 * (c) Fabien Potencier
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 /**
13 * Loads template from the filesystem.
15 * @author Fabien Potencier <fabien@symfony.com>
17 class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
19 /** Identifier of the main namespace. */
20 const MAIN_NAMESPACE = '__main__';
22 protected $paths = array();
23 protected $cache = array();
24 protected $errorCache = array();
26 private $rootPath;
28 /**
29 * @param string|array $paths A path or an array of paths where to look for templates
30 * @param string|null $rootPath The root path common to all relative paths (null for getcwd())
32 public function __construct($paths = array(), $rootPath = null)
34 $this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR;
35 if (false !== $realPath = realpath($rootPath)) {
36 $this->rootPath = $realPath.DIRECTORY_SEPARATOR;
39 if ($paths) {
40 $this->setPaths($paths);
44 /**
45 * Returns the paths to the templates.
47 * @param string $namespace A path namespace
49 * @return array The array of paths where to look for templates
51 public function getPaths($namespace = self::MAIN_NAMESPACE)
53 return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
56 /**
57 * Returns the path namespaces.
59 * The main namespace is always defined.
61 * @return array The array of defined namespaces
63 public function getNamespaces()
65 return array_keys($this->paths);
68 /**
69 * Sets the paths where templates are stored.
71 * @param string|array $paths A path or an array of paths where to look for templates
72 * @param string $namespace A path namespace
74 public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
76 if (!is_array($paths)) {
77 $paths = array($paths);
80 $this->paths[$namespace] = array();
81 foreach ($paths as $path) {
82 $this->addPath($path, $namespace);
86 /**
87 * Adds a path where templates are stored.
89 * @param string $path A path where to look for templates
90 * @param string $namespace A path namespace
92 * @throws Twig_Error_Loader
94 public function addPath($path, $namespace = self::MAIN_NAMESPACE)
96 // invalidate the cache
97 $this->cache = $this->errorCache = array();
99 $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
100 if (!is_dir($checkPath)) {
101 throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
104 $this->paths[$namespace][] = rtrim($path, '/\\');
108 * Prepends a path where templates are stored.
110 * @param string $path A path where to look for templates
111 * @param string $namespace A path namespace
113 * @throws Twig_Error_Loader
115 public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
117 // invalidate the cache
118 $this->cache = $this->errorCache = array();
120 $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
121 if (!is_dir($checkPath)) {
122 throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
125 $path = rtrim($path, '/\\');
127 if (!isset($this->paths[$namespace])) {
128 $this->paths[$namespace][] = $path;
129 } else {
130 array_unshift($this->paths[$namespace], $path);
134 public function getSource($name)
136 @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
138 return file_get_contents($this->findTemplate($name));
141 public function getSourceContext($name)
143 $path = $this->findTemplate($name);
145 return new Twig_Source(file_get_contents($path), $name, $path);
148 public function getCacheKey($name)
150 $path = $this->findTemplate($name);
151 $len = strlen($this->rootPath);
152 if (0 === strncmp($this->rootPath, $path, $len)) {
153 return substr($path, $len);
156 return $path;
159 public function exists($name)
161 $name = $this->normalizeName($name);
163 if (isset($this->cache[$name])) {
164 return true;
167 try {
168 return false !== $this->findTemplate($name, false);
169 } catch (Twig_Error_Loader $exception) {
170 @trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', get_class($this)), E_USER_DEPRECATED);
172 return false;
176 public function isFresh($name, $time)
178 return filemtime($this->findTemplate($name)) <= $time;
181 protected function findTemplate($name)
183 $throw = func_num_args() > 1 ? func_get_arg(1) : true;
184 $name = $this->normalizeName($name);
186 if (isset($this->cache[$name])) {
187 return $this->cache[$name];
190 if (isset($this->errorCache[$name])) {
191 if (!$throw) {
192 return false;
195 throw new Twig_Error_Loader($this->errorCache[$name]);
198 $this->validateName($name);
200 list($namespace, $shortname) = $this->parseName($name);
202 if (!isset($this->paths[$namespace])) {
203 $this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
205 if (!$throw) {
206 return false;
209 throw new Twig_Error_Loader($this->errorCache[$name]);
212 foreach ($this->paths[$namespace] as $path) {
213 if (!$this->isAbsolutePath($path)) {
214 $path = $this->rootPath.'/'.$path;
217 if (is_file($path.'/'.$shortname)) {
218 if (false !== $realpath = realpath($path.'/'.$shortname)) {
219 return $this->cache[$name] = $realpath;
222 return $this->cache[$name] = $path.'/'.$shortname;
226 $this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
228 if (!$throw) {
229 return false;
232 throw new Twig_Error_Loader($this->errorCache[$name]);
235 protected function parseName($name, $default = self::MAIN_NAMESPACE)
237 if (isset($name[0]) && '@' == $name[0]) {
238 if (false === $pos = strpos($name, '/')) {
239 throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
242 $namespace = substr($name, 1, $pos - 1);
243 $shortname = substr($name, $pos + 1);
245 return array($namespace, $shortname);
248 return array($default, $name);
251 protected function normalizeName($name)
253 return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name));
256 protected function validateName($name)
258 if (false !== strpos($name, "\0")) {
259 throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
262 $name = ltrim($name, '/');
263 $parts = explode('/', $name);
264 $level = 0;
265 foreach ($parts as $part) {
266 if ('..' === $part) {
267 --$level;
268 } elseif ('.' !== $part) {
269 ++$level;
272 if ($level < 0) {
273 throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
278 private function isAbsolutePath($file)
280 return strspn($file, '/\\', 0, 1)
281 || (strlen($file) > 3 && ctype_alpha($file[0])
282 && ':' === substr($file, 1, 1)
283 && strspn($file, '/\\', 2, 1)
285 || null !== parse_url($file, PHP_URL_SCHEME)
290 class_alias('Twig_Loader_Filesystem', 'Twig\Loader\FilesystemLoader', false);