From 55c9ee092e952f663573fcb95cbd785f1c0c7041 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 5 Jul 2019 21:28:11 -0400 Subject: [PATCH] Fixing theme bug where theme directory had to exist in core And also adding the "default" fallback mechanism everywhere. --- docs/en/themes.rst | 4 + lib/Templates/TwigEnvironmentFactory.php | 45 ++++----- .../Templates/TwigEnvironmentFactoryTest.php | 92 +++++++++++++++++++ 3 files changed, 119 insertions(+), 22 deletions(-) create mode 100644 tests/Templates/TwigEnvironmentFactoryTest.php diff --git a/docs/en/themes.rst b/docs/en/themes.rst index 17e90172..3efd6d41 100644 --- a/docs/en/themes.rst +++ b/docs/en/themes.rst @@ -30,3 +30,7 @@ named ``layout.html.twig`` and you can customize the layout that wraps all gener {% block body '' %} + +Even with a theme, the rendering engine will continue to +use a ``default`` directory (e.g. ``/path/to/custom/templates/default/html`` +as a fallback for any templates (see :doc:`/customizing-rendering`). diff --git a/lib/Templates/TwigEnvironmentFactory.php b/lib/Templates/TwigEnvironmentFactory.php index 2d8c5d7c..01065586 100644 --- a/lib/Templates/TwigEnvironmentFactory.php +++ b/lib/Templates/TwigEnvironmentFactory.php @@ -7,13 +7,14 @@ use Doctrine\RST\Configuration; use Twig\Environment as TwigEnvironment; use Twig\Loader\FilesystemLoader; +use function file_exists; use function sprintf; class TwigEnvironmentFactory { public static function createTwigEnvironment(Configuration $configuration) : TwigEnvironment { - $loader = new FilesystemLoader(self::getTemplatesDirs($configuration)); + $loader = new FilesystemLoader(self::getTemplateDirs($configuration)); return new TwigEnvironment($loader, [ 'strict_variables' => true, @@ -22,37 +23,37 @@ public static function createTwigEnvironment(Configuration $configuration) : Twi ]); } - private static function getThemeDir(Configuration $configuration, string $templatesDir, ?string $theme = null) : string - { - $theme = $theme ?? $configuration->getTheme(); - $fileExtension = $configuration->getFileExtension(); - - return $templatesDir . '/' . $theme . '/' . $fileExtension; - } - /** * @return string[] */ - private static function getTemplatesDirs(Configuration $configuration) : array + private static function getTemplateDirs(Configuration $configuration) : array { - $themeDirs = []; + $themeDirs = []; + $fileExtension = $configuration->getFileExtension(); - // check custom template directories first - $customTemplateDirs = $configuration->getCustomTemplateDirs(); + $templateDirectories = $configuration->getCustomTemplateDirs(); + // add the fallback directory + $templateDirectories[] = __DIR__; - if ($customTemplateDirs !== []) { - foreach ($customTemplateDirs as $customTemplateDir) { - $themeDirs[] = self::getThemeDir($configuration, $customTemplateDir); + foreach ($templateDirectories as $templateDir) { + $themePath = $templateDir . '/' . $configuration->getTheme() . '/' . $fileExtension; + if (! file_exists($themePath)) { + continue; } - } - // fallback to core templates for the configured theme - $themeDirs[] = self::getThemeDir($configuration, __DIR__); + $themeDirs[] = $themePath; + } - // fallback to core templates for the default theme - // if the configured theme is not the default + // look for the fallback "default" in all directories if ($configuration->getTheme() !== Configuration::THEME_DEFAULT) { - $themeDirs[] = self::getThemeDir($configuration, __DIR__, Configuration::THEME_DEFAULT); + foreach ($templateDirectories as $templateDir) { + $themePath = $templateDir . '/' . Configuration::THEME_DEFAULT . '/' . $fileExtension; + if (! file_exists($themePath)) { + continue; + } + + $themeDirs[] = $themePath; + } } return $themeDirs; diff --git a/tests/Templates/TwigEnvironmentFactoryTest.php b/tests/Templates/TwigEnvironmentFactoryTest.php new file mode 100644 index 00000000..a6701178 --- /dev/null +++ b/tests/Templates/TwigEnvironmentFactoryTest.php @@ -0,0 +1,92 @@ +setFileExtension('html'); + + // no theme, no custom dirs + self::assertLoaderPaths( + [(string) realpath(__DIR__ . '/../../lib/Templates/default/html')], + TwigEnvironmentFactory::createTwigEnvironment($configuration) + ); + } + + public function testTemplateDirectoriesThemeAndDirectories() : void + { + $configuration = new Configuration(); + $configuration->setFileExtension('html'); + $configuration->setTheme('cool_theme'); + + $dir1 = $this->tmpPath . '/dir1'; + $dir2 = $this->tmpPath . '/dir2'; + $nonExistentDir = $this->tmpPath . '/dir3'; + + // dir1 has all directories + $this->filesystem->mkdir($dir1); + $this->filesystem->mkdir($dir1 . '/default/html'); + $this->filesystem->mkdir($dir1 . '/cool_theme/html'); + + // dir2 has just the theme + $this->filesystem->mkdir($dir2); + $this->filesystem->mkdir($dir2 . '/cool_theme/html'); + + $configuration->setCustomTemplateDirs([$dir1, $dir2, $nonExistentDir]); + + // no theme, no custom dirs + self::assertLoaderPaths( + [ + $dir1 . '/cool_theme/html', + $dir2 . '/cool_theme/html', + $dir1 . '/default/html', + (string) realpath(__DIR__ . '/../../lib/Templates/default/html'), + ], + TwigEnvironmentFactory::createTwigEnvironment($configuration) + ); + } + + /** + * @param string[] $expectedPaths + */ + private static function assertLoaderPaths(array $expectedPaths, Environment $twig) : void + { + $loader = $twig->getLoader(); + if (! $loader instanceof FilesystemLoader) { + throw new Exception('Wrong loader instance'); + } + + self::assertSame($expectedPaths, $loader->getPaths()); + } + + protected function setUp() : void + { + $this->tmpPath = sys_get_temp_dir() . '/_rst_twig_tests'; + $this->filesystem = new Filesystem(); + } + + protected function tearDown() : void + { + $this->filesystem->remove($this->tmpPath); + } +}