mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-12 10:26:32 +00:00
feature #2195 fixed the filesystem loader with relative paths (fabpot)
This PR was merged into the 1.x branch.
Discussion
----------
fixed the filesystem loader with relative paths
closes #2145
TODO
- [x] document the new `$rootPath` option
- [x] add test with a `$rootPath` different from `getcwd()`
- [x] test the cache key does not vary when `$rootPath` changes
Commits
-------
a343c92 fixed the filesystem loader with relative paths
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
* 1.27.0 (2016-XX-XX)
|
||||
|
||||
* fixed the filesystem loader with relative paths
|
||||
* deprecated Twig_Node::getLine() in favor of Twig_Node::getTemplateLine()
|
||||
* deprecated Twig_Template::getSource() in favor of Twig_Template::getSourceContext()
|
||||
* deprecated Twig_Node::getFilename() in favor of Twig_Node::getTemplateName()
|
||||
|
||||
+15
@@ -156,6 +156,9 @@ Here is a list of the built-in loaders Twig provides:
|
||||
.. versionadded:: 1.10
|
||||
The ``prependPath()`` and support for namespaces were added in Twig 1.10.
|
||||
|
||||
.. versionadded:: 1.27
|
||||
Relative paths support was added in Twig 1.27.
|
||||
|
||||
``Twig_Loader_Filesystem`` loads templates from the file system. This loader
|
||||
can find templates in folders on the file system and is the preferred way to
|
||||
load them::
|
||||
@@ -190,6 +193,18 @@ Namespaced templates can be accessed via the special
|
||||
|
||||
$twig->render('@admin/index.html', array());
|
||||
|
||||
``Twig_Loader_Filesystem`` support absolute and relative paths. Using relative
|
||||
paths is preferred as it makes the cache keys independent of the project root
|
||||
directory (for instance, it allows warming the cache from a build server where
|
||||
the directory might be different from the one used on production servers)::
|
||||
|
||||
$loader = new Twig_Loader_Filesystem('templates', getcwd().'/..');
|
||||
|
||||
.. note::
|
||||
|
||||
When not passing the root path as a second argument, Twig uses ``getcwd()``
|
||||
for relative paths.
|
||||
|
||||
``Twig_Loader_Array``
|
||||
.....................
|
||||
|
||||
|
||||
@@ -23,13 +23,21 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
protected $cache = array();
|
||||
protected $errorCache = array();
|
||||
|
||||
private $rootPath;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|array $paths A path or an array of paths where to look for templates
|
||||
* @param string|array $paths A path or an array of paths where to look for templates
|
||||
* @param string|null $rootPath The root path common to all relative paths (null for getcwd())
|
||||
*/
|
||||
public function __construct($paths = array())
|
||||
public function __construct($paths = array(), $rootPath = null)
|
||||
{
|
||||
$this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR;
|
||||
if (false !== $realPath = realpath($rootPath)) {
|
||||
$this->rootPath = $realPath.DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
if ($paths) {
|
||||
$this->setPaths($paths);
|
||||
}
|
||||
@@ -81,7 +89,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
* Adds a path where templates are stored.
|
||||
*
|
||||
* @param string $path A path where to look for templates
|
||||
* @param string $namespace A path name
|
||||
* @param string $namespace A path namespace
|
||||
*
|
||||
* @throws Twig_Error_Loader
|
||||
*/
|
||||
@@ -90,8 +98,9 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
// invalidate the cache
|
||||
$this->cache = $this->errorCache = array();
|
||||
|
||||
if (!is_dir($path)) {
|
||||
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
|
||||
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
|
||||
if (!is_dir($checkPath)) {
|
||||
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
|
||||
}
|
||||
|
||||
$this->paths[$namespace][] = rtrim($path, '/\\');
|
||||
@@ -101,7 +110,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
* Prepends a path where templates are stored.
|
||||
*
|
||||
* @param string $path A path where to look for templates
|
||||
* @param string $namespace A path name
|
||||
* @param string $namespace A path namespace
|
||||
*
|
||||
* @throws Twig_Error_Loader
|
||||
*/
|
||||
@@ -110,8 +119,9 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
// invalidate the cache
|
||||
$this->cache = $this->errorCache = array();
|
||||
|
||||
if (!is_dir($path)) {
|
||||
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
|
||||
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
|
||||
if (!is_dir($checkPath)) {
|
||||
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
|
||||
}
|
||||
|
||||
$path = rtrim($path, '/\\');
|
||||
@@ -146,7 +156,13 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
*/
|
||||
public function getCacheKey($name)
|
||||
{
|
||||
return $this->findTemplate($name);
|
||||
$path = $this->findTemplate($name);
|
||||
$len = strlen($this->rootPath);
|
||||
if (0 === strncmp($this->rootPath, $path, $len)) {
|
||||
return substr($path, $len);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,8 +225,16 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
}
|
||||
|
||||
foreach ($this->paths[$namespace] as $path) {
|
||||
if (!$this->isAbsolutePath($path)) {
|
||||
$path = $this->rootPath.'/'.$path;
|
||||
}
|
||||
|
||||
if (is_file($path.'/'.$shortname)) {
|
||||
return $this->cache[$name] = $this->normalizePath($path.'/'.$shortname);
|
||||
if (false !== $realpath = realpath($path.'/'.$shortname)) {
|
||||
return $this->cache[$name] = $realpath;
|
||||
}
|
||||
|
||||
return $this->cache[$name] = $path.'/'.$shortname;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,19 +290,14 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
|
||||
}
|
||||
}
|
||||
|
||||
private function normalizePath($path)
|
||||
private function isAbsolutePath($file)
|
||||
{
|
||||
$parts = explode('/', str_replace('\\', '/', $path));
|
||||
$hasProto = false !== strpos($path, '://');
|
||||
$new = array();
|
||||
foreach ($parts as $i => $part) {
|
||||
if ('..' === $part) {
|
||||
array_pop($new);
|
||||
} elseif ('.' !== $part && ('' !== $part || 0 === $i || $hasProto && $i < 3)) {
|
||||
$new[] = $part;
|
||||
}
|
||||
}
|
||||
|
||||
return implode('/', $new);
|
||||
return strspn($file, '/\\', 0, 1)
|
||||
|| (strlen($file) > 3 && ctype_alpha($file[0])
|
||||
&& substr($file, 1, 1) === ':'
|
||||
&& strspn($file, '/\\', 2, 1)
|
||||
)
|
||||
|| null !== parse_url($file, PHP_URL_SCHEME)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +62,9 @@ class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase
|
||||
/**
|
||||
* @dataProvider getBasePaths
|
||||
*/
|
||||
public function testPaths($basePath)
|
||||
public function testPaths($basePath, $cacheKey, $rootPath)
|
||||
{
|
||||
$loader = new Twig_Loader_Filesystem(array($basePath.'/normal', $basePath.'/normal_bis'));
|
||||
$loader = new Twig_Loader_Filesystem(array($basePath.'/normal', $basePath.'/normal_bis'), $rootPath);
|
||||
$loader->setPaths(array($basePath.'/named', $basePath.'/named_bis'), 'named');
|
||||
$loader->addPath($basePath.'/named_ter', 'named');
|
||||
$loader->addPath($basePath.'/normal_ter');
|
||||
@@ -87,7 +87,7 @@ class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase
|
||||
), $loader->getPaths('named'));
|
||||
|
||||
// do not use realpath here as it would make the test unuseful
|
||||
$this->assertEquals(str_replace('\\', '/', $basePath.'/named_quater/named_absolute.html'), str_replace('\\', '/', $loader->getCacheKey('@named/named_absolute.html')));
|
||||
$this->assertEquals($cacheKey, str_replace('\\', '/', $loader->getCacheKey('@named/named_absolute.html')));
|
||||
$this->assertEquals("path (final)\n", $loader->getSource('index.html'));
|
||||
$this->assertEquals("path (final)\n", $loader->getSource('@__main__/index.html'));
|
||||
$this->assertEquals("named path (final)\n", $loader->getSource('@named/index.html'));
|
||||
@@ -96,8 +96,31 @@ class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase
|
||||
public function getBasePaths()
|
||||
{
|
||||
return array(
|
||||
array(dirname(__FILE__).'/Fixtures'),
|
||||
array('test/Twig/Tests/Loader/Fixtures'),
|
||||
array(
|
||||
dirname(__FILE__).'/Fixtures',
|
||||
'test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html',
|
||||
null,
|
||||
),
|
||||
array(
|
||||
dirname(__FILE__).'/Fixtures/../Fixtures',
|
||||
'test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html',
|
||||
null,
|
||||
),
|
||||
array(
|
||||
'test/Twig/Tests/Loader/Fixtures',
|
||||
'test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html',
|
||||
getcwd(),
|
||||
),
|
||||
array(
|
||||
'Fixtures',
|
||||
'Fixtures/named_quater/named_absolute.html',
|
||||
getcwd().'/test/Twig/Tests/Loader',
|
||||
),
|
||||
array(
|
||||
'Fixtures',
|
||||
'Fixtures/named_quater/named_absolute.html',
|
||||
getcwd().'/test/../test/Twig/Tests/Loader',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user