Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing theme bug where dir must exist in core + expanded "default" fallback #114

Merged
merged 1 commit into from
Aug 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/en/themes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ named ``layout.html.twig`` and you can customize the layout that wraps all gener
{% block body '' %}
</body>
</html>

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`).
45 changes: 23 additions & 22 deletions lib/Templates/TwigEnvironmentFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
92 changes: 92 additions & 0 deletions tests/Templates/TwigEnvironmentFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\RST\Templates;

use Doctrine\RST\Configuration;
use Doctrine\RST\Templates\TwigEnvironmentFactory;
use Exception;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Filesystem\Filesystem;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use function realpath;
use function sys_get_temp_dir;

class TwigEnvironmentFactoryTest extends TestCase
{
/** @var string */
private $tmpPath;
/** @var Filesystem */
private $filesystem;

public function testTemplateDirectoriesNothingCustom() : void
{
$configuration = new Configuration();
$configuration->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);
}
}