diff --git a/src/Twig/FileLoader.php b/src/Twig/FileLoader.php index 5466efe..4852e7d 100644 --- a/src/Twig/FileLoader.php +++ b/src/Twig/FileLoader.php @@ -18,8 +18,8 @@ namespace Cake\TwigView\Twig; -use Cake\TwigView\View\TwigView; -use Cake\View\Exception\MissingTemplateException; +use Cake\Core\App; +use Cake\Core\Plugin; use Twig\Error\LoaderError; use Twig\Loader\LoaderInterface; use Twig\Source; @@ -32,16 +32,16 @@ class FileLoader implements LoaderInterface { /** - * @var \Cake\TwigView\View\TwigView + * @var string[] */ - protected $twigView; + protected $extensions; /** - * @param \Cake\TwigView\View\TwigView $twigView TwigView instance. + * @param string[] $extensions Template file extensions */ - public function __construct(TwigView $twigView) + public function __construct(array $extensions) { - $this->twigView = $twigView; + $this->extensions = $extensions; } /** @@ -79,7 +79,7 @@ public function exists(string $name) { try { $this->findTemplate($name); - } catch (MissingTemplateException $e) { + } catch (LoaderError $e) { return false; } @@ -96,12 +96,48 @@ public function findTemplate(string $name): string return $name; } - try { - $path = $this->twigView->resolveTemplatePath($name); - } catch (MissingTemplateException $e) { - throw new LoaderError($e->getMessage()); + [$plugin, $name] = pluginSplit($name); + $name = str_replace('/', DIRECTORY_SEPARATOR, $name); + + if ($plugin !== null) { + $path = $this->checkExtensions(Plugin::templatePath($plugin) . $name); + if ($path !== null) { + return $path; + } + + throw new LoaderError("Could not find template `{$name}` in plugin `{$plugin}`."); + } + + foreach (App::path('templates') as $templatePath) { + $path = $this->checkExtensions($templatePath . $name); + if ($path !== null) { + return $path; + } + } + + $error = "Could not find template `{$name}`.\nThese paths were searched:\n\n"; + foreach (App::path('templates') as $templatePath) { + $error .= "- `{$templatePath}`\n"; + } + throw new LoaderError($error); + } + + /** + * Check partial path with all template file extensions to see + * which file exists. + * + * @param string $partial Template path excluding extension + * @return string|null + */ + public function checkExtensions(string $partial): ?string + { + foreach ($this->extensions as $extension) { + $path = $partial . $extension; + if (file_exists($path)) { + return $path; + } } - return $path; + return null; } } diff --git a/src/View/TwigView.php b/src/View/TwigView.php index c345e3a..0e0a990 100644 --- a/src/View/TwigView.php +++ b/src/View/TwigView.php @@ -150,18 +150,6 @@ public function getExtensions(): array return $this->extensions; } - /** - * Gets the full path for template. - * - * @param string $name Template name - * @return string - * @throws \Cake\View\Exception\MissingTemplateException When template is not found - */ - public function resolveTemplatePath(string $name): string - { - return $this->_getTemplateFileName($name); - } - /** * Creates the Twig LoaderInterface instance. * @@ -169,7 +157,7 @@ public function resolveTemplatePath(string $name): string */ protected function createLoader(): LoaderInterface { - return new FileLoader($this); + return new FileLoader($this->extensions); } /** diff --git a/tests/TestCase/Twig/FileLoaderTest.php b/tests/TestCase/Twig/FileLoaderTest.php index dfd4225..c017af9 100644 --- a/tests/TestCase/Twig/FileLoaderTest.php +++ b/tests/TestCase/Twig/FileLoaderTest.php @@ -20,7 +20,6 @@ use Cake\TestSuite\TestCase; use Cake\TwigView\Twig\FileLoader; -use Cake\TwigView\View\TwigView; use Twig\Error\LoaderError; /** @@ -39,7 +38,7 @@ public function setUp(): void $this->loadPlugins(['TestTwigView']); - $this->loader = new FileLoader(new TwigView()); + $this->loader = new FileLoader(['.twig']); } public function tearDown(): void @@ -93,7 +92,12 @@ public function testIsFresh() public function testIsFreshNonExistingFile() { $this->expectException(LoaderError::class); - $this->loader->isFresh(TMP . 'foobar' . time(), time()); } + + public function testExistsNonExistingFile() + { + $exists = $this->loader->exists(TMP . 'foobar' . time(), time()); + $this->assertSame(false, $exists); + } } diff --git a/tests/TestCase/View/TwigViewTest.php b/tests/TestCase/View/TwigViewTest.php index c3a23fd..0540144 100644 --- a/tests/TestCase/View/TwigViewTest.php +++ b/tests/TestCase/View/TwigViewTest.php @@ -169,6 +169,18 @@ public function testTwigInclude() $this->removePlugins(['TestTwigView']); } + /** + * Tests extends loads templates from root templates paths. + * + * @return void + */ + public function testTwigExtendsRootPath() + { + $view = new AppView(null, null, null, ['templatePath' => 'Blog']); + $output = $view->render('blog_with_extends'); + $this->assertSame('base from subdir/base', $output); + } + /** * Tests deprecated element and cell tags render. * diff --git a/tests/test_app/templates/Blog/blog_with_extends.twig b/tests/test_app/templates/Blog/blog_with_extends.twig new file mode 100644 index 0000000..476c236 --- /dev/null +++ b/tests/test_app/templates/Blog/blog_with_extends.twig @@ -0,0 +1 @@ +{% extends 'subdir_with_base/base' %} \ No newline at end of file diff --git a/tests/test_app/templates/subdir_with_base/base.twig b/tests/test_app/templates/subdir_with_base/base.twig new file mode 100644 index 0000000..54ce737 --- /dev/null +++ b/tests/test_app/templates/subdir_with_base/base.twig @@ -0,0 +1 @@ +base from subdir/base \ No newline at end of file