Skip to content
Snippets Groups Projects
Commit 004d7021 authored by Tim van Dijen's avatar Tim van Dijen
Browse files

Rewrite Template using symfony/filesystem

parent 2bf90ac5
No related branches found
No related tags found
No related merge requests found
...@@ -10,8 +10,11 @@ declare(strict_types=1); ...@@ -10,8 +10,11 @@ declare(strict_types=1);
namespace SimpleSAML\XHTML; namespace SimpleSAML\XHTML;
use Exception;
use InvalidArgumentException;
use SimpleSAML\Assert\Assert; use SimpleSAML\Assert\Assert;
use SimpleSAML\Configuration; use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\Locale\Language; use SimpleSAML\Locale\Language;
use SimpleSAML\Locale\Localization; use SimpleSAML\Locale\Localization;
use SimpleSAML\Locale\Translate; use SimpleSAML\Locale\Translate;
...@@ -20,12 +23,32 @@ use SimpleSAML\Logger; ...@@ -20,12 +23,32 @@ use SimpleSAML\Logger;
use SimpleSAML\Module; use SimpleSAML\Module;
use SimpleSAML\Utils; use SimpleSAML\Utils;
use Symfony\Bridge\Twig\Extension\TranslationExtension; use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Twig\Environment; use Twig\Environment;
use Twig\Error\RuntimeError;
use Twig\Extra\Intl\IntlExtension;
use Twig\Loader\FilesystemLoader; use Twig\Loader\FilesystemLoader;
use Twig\TwigFilter; use Twig\TwigFilter;
use Twig\TwigFunction; use Twig\TwigFunction;
use function class_exists;
use function count;
use function date;
use function explode;
use function hash;
use function htmlspecialchars;
use function in_array;
use function is_null;
use function key;
use function ksort;
use function strripos;
use function strtolower;
use function strval;
use function substr;
/** /**
* The content-property is set upstream, but this is not recognized by Psalm * The content-property is set upstream, but this is not recognized by Psalm
* @psalm-suppress PropertyNotSetInConstructor * @psalm-suppress PropertyNotSetInConstructor
...@@ -110,6 +133,11 @@ class Template extends Response ...@@ -110,6 +133,11 @@ class Template extends Response
*/ */
private array $theme = ['module' => null, 'name' => 'default']; private array $theme = ['module' => null, 'name' => 'default'];
/**
* @var \Symfony\Component\Filesystem\Filesystem;
*/
private Filesystem $fileSystem;
/** /**
* Constructor * Constructor
...@@ -150,6 +178,7 @@ class Template extends Response ...@@ -150,6 +178,7 @@ class Template extends Response
$this->twig = $this->setupTwig(); $this->twig = $this->setupTwig();
$this->charset = 'UTF-8'; $this->charset = 'UTF-8';
$this->fileSystem = new Filesystem();
parent::__construct(); parent::__construct();
} }
...@@ -173,14 +202,15 @@ class Template extends Response ...@@ -173,14 +202,15 @@ class Template extends Response
$path = Module::getModuleUrl($module . '/assets/' . $asset); $path = Module::getModuleUrl($module . '/assets/' . $asset);
} }
if (!file_exists($file)) { if (!$this->fileSystem->exists($file)) {
// don't be too harsh if an asset is missing, just pretend it's there... // don't be too harsh if an asset is missing, just pretend it's there...
return $path; return $path;
} }
$file = new File($file);
$tag = $this->configuration->getVersion(); $tag = $this->configuration->getVersion();
if ($tag === 'master') { if ($tag === 'master') {
$tag = strval(filemtime($file)); $tag = strval($file->getMtime());
} }
$tag = substr(hash('md5', $tag), 0, 5); $tag = substr(hash('md5', $tag), 0, 5);
...@@ -240,7 +270,7 @@ class Template extends Response ...@@ -240,7 +270,7 @@ class Template extends Response
$templateDirs[] = [ $templateDirs[] = [
$this->theme['module'] => TemplateLoader::getModuleTemplateDir($this->theme['module']) $this->theme['module'] => TemplateLoader::getModuleTemplateDir($this->theme['module'])
]; ];
} catch (\InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
// either the module is not enabled or it has no "templates" directory, ignore // either the module is not enabled or it has no "templates" directory, ignore
} }
} }
...@@ -273,7 +303,7 @@ class Template extends Response ...@@ -273,7 +303,7 @@ class Template extends Response
// abort if twig template does not exist // abort if twig template does not exist
if (!$loader->exists($this->twig_template)) { if (!$loader->exists($this->twig_template)) {
throw new \Exception('Template-file \"' . $this->getTemplateName() . '\" does not exist.'); throw new Exception('Template-file \"' . $this->getTemplateName() . '\" does not exist.');
} }
// load extra i18n domains // load extra i18n domains
...@@ -294,7 +324,7 @@ class Template extends Response ...@@ -294,7 +324,7 @@ class Template extends Response
$twig = new Environment($loader, $options); $twig = new Environment($loader, $options);
$twigTranslator = new TwigTranslator([Translate::class, 'translateSingularGettext']); $twigTranslator = new TwigTranslator([Translate::class, 'translateSingularGettext']);
$twig->addExtension(new TranslationExtension($twigTranslator)); $twig->addExtension(new TranslationExtension($twigTranslator));
$twig->addExtension(new \Twig\Extra\Intl\IntlExtension()); $twig->addExtension(new IntlExtension());
$twig->addFunction(new TwigFunction('moduleURL', [Module::class, 'getModuleURL'])); $twig->addFunction(new TwigFunction('moduleURL', [Module::class, 'getModuleURL']));
...@@ -356,28 +386,30 @@ class Template extends Response ...@@ -356,28 +386,30 @@ class Template extends Response
// setup directories & namespaces // setup directories & namespaces
$themeDir = Module::getModuleDir($this->theme['module']) . '/themes/' . $this->theme['name']; $themeDir = Module::getModuleDir($this->theme['module']) . '/themes/' . $this->theme['name'];
$subdirs = @scandir($themeDir);
if (empty($subdirs)) { if (!$this->fileSystem->exists($themeDir)) {
Logger::warning( Logger::warning(
sprintf( sprintf('Theme directory for theme "%s" (%s) does not exist.', $this->theme['name'], $themeDir),
'Theme directory for theme "%s" (%s) is not readable or is empty.',
$this->theme['name'],
$themeDir
)
); );
return []; return [];
} }
$themeTemplateDirs = []; $finder = new Finder();
foreach ($subdirs as $entry) { $finder->directories()->in($themeDir)->depth(0);
// discard anything that's not a directory. Expression is negated to profit from lazy evaluation if (!$finder->hasResults()) {
if (!($entry !== '.' && $entry !== '..' && is_dir($themeDir . '/' . $entry))) { Logger::warning(sprintf(
continue; 'Theme directory for theme "%s" (%s) is not readable or is empty.',
} $this->theme['name'],
$themeDir,
));
return [];
}
$themeTemplateDirs = [];
foreach ($finder as $entry) {
// set correct name for the default namespace // set correct name for the default namespace
$ns = ($entry === 'default') ? FilesystemLoader::MAIN_NAMESPACE : $entry; $ns = ($entry->getFileName() === 'default') ? FilesystemLoader::MAIN_NAMESPACE : $entry->getFileName();
$themeTemplateDirs[] = [$ns => $themeDir . '/' . $entry]; $themeTemplateDirs[] = [$ns => strval($entry)];
} }
return $themeTemplateDirs; return $themeTemplateDirs;
} }
...@@ -394,15 +426,16 @@ class Template extends Response ...@@ -394,15 +426,16 @@ class Template extends Response
private function getModuleTemplateDir(string $module): string private function getModuleTemplateDir(string $module): string
{ {
if (!Module::isModuleEnabled($module)) { if (!Module::isModuleEnabled($module)) {
throw new \InvalidArgumentException('The module \'' . $module . '\' is not enabled.'); throw new InvalidArgumentException('The module \'' . $module . '\' is not enabled.');
} }
$moduledir = Module::getModuleDir($module); $moduledir = Module::getModuleDir($module);
// check if module has a /templates dir, if so, append // check if module has a /templates dir, if so, append
$templatedir = $moduledir . '/templates'; $templateDir = $moduledir . '/templates';
if (!is_dir($templatedir)) { $file = new File($templateDir);
throw new \InvalidArgumentException('The module \'' . $module . '\' has no templates directory.'); if (!$file->isDir()) {
throw new InvalidArgumentException('The module \'' . $module . '\' has no templates directory.');
} }
return $templatedir; return $templateDir;
} }
...@@ -515,8 +548,8 @@ class Template extends Response ...@@ -515,8 +548,8 @@ class Template extends Response
} }
try { try {
return $this->twig->render($this->twig_template, $this->data); return $this->twig->render($this->twig_template, $this->data);
} catch (\Twig\Error\RuntimeError $e) { } catch (RuntimeError $e) {
throw new \SimpleSAML\Error\Exception(substr($e->getMessage(), 0, -1) . ' in ' . $this->template, 0, $e); throw new Error\Exception(substr($e->getMessage(), 0, -1) . ' in ' . $this->template, 0, $e);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment