summaryrefslogtreecommitdiffstats
path: root/lib/SimpleSAML/XHTML/Template.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/SimpleSAML/XHTML/Template.php')
-rw-r--r--lib/SimpleSAML/XHTML/Template.php286
1 files changed, 263 insertions, 23 deletions
diff --git a/lib/SimpleSAML/XHTML/Template.php b/lib/SimpleSAML/XHTML/Template.php
index 8214ac1..1172b0f 100644
--- a/lib/SimpleSAML/XHTML/Template.php
+++ b/lib/SimpleSAML/XHTML/Template.php
@@ -38,6 +38,11 @@ class SimpleSAML_XHTML_Template
*/
private $template = 'default.php';
+ /*
+ * Main Twig namespace, to avoid misspelling it *again*
+ */
+ private $twig_namespace = \Twig_Loader_Filesystem::MAIN_NAMESPACE;
+
/**
* Constructor
@@ -46,24 +51,229 @@ class SimpleSAML_XHTML_Template
* @param string $template Which template file to load
* @param string|null $defaultDictionary The default dictionary where tags will come from.
*/
- public function __construct(SimpleSAML_Configuration $configuration, $template, $defaultDictionary = null)
+ public function __construct(\SimpleSAML_Configuration $configuration, $template, $defaultDictionary = null)
{
$this->configuration = $configuration;
$this->template = $template;
// TODO: do not remove the slash from the beginning, change the templates instead!
$this->data['baseurlpath'] = ltrim($this->configuration->getBasePath(), '/');
$this->translator = new SimpleSAML\Locale\Translate($configuration, $defaultDictionary);
+ $this->twig = $this->setupTwig();
}
/**
- * Return the internal translator object used by this template.
+ * Normalize the name of the template to one of the possible alternatives.
*
- * @return \SimpleSAML\Locale\Translate The translator that will be used with this template.
+ * @param string $templateName The template name to normalize.
+ * @return string The filename we need to look for.
*/
- public function getTranslator()
+ private function normalizeTemplateName($templateName)
{
- return $this->translator;
+ if (strripos($templateName, '.twig.html')) {
+ return $templateName;
+ }
+ $phppos = strripos($templateName, '.php');
+ if ($phppos) {
+ $templateName = substr($templateName, 0, $phppos);
+ }
+ $tplpos = strripos($templateName, '.tpl');
+ if ($tplpos) {
+ $templateName = substr($templateName, 0, $tplpos);
+ }
+ return $templateName.'.twig.html';
+ }
+
+
+ /**
+ * Set up the places where twig can look for templates.
+ *
+ * @return Twig_Loader_Filesystem|false The twig template loader or false if the template does not exist.
+ * @throws Twig_Error_Loader In case a failure occurs.
+ */
+ private function setupTwigTemplatepaths()
+ {
+ $filename = $this->normalizeTemplateName($this->template);
+
+ // get namespace if any
+ $namespace = '';
+ $split = explode(':', $filename, 2);
+ if (count($split) === 2) {
+ $namespace = $split[0];
+ $filename = $split[1];
+ }
+ $this->twig_template = $namespace ? '@'.$namespace.'/'.$filename : $filename;
+ $loader = new \Twig_Loader_Filesystem();
+ $templateDirs = array_merge(
+ $this->findThemeTemplateDirs(),
+ $this->findModuleTemplateDirs()
+ );
+ // default, themeless templates are checked last
+ $templateDirs[] = array(
+ $this->twig_namespace => $this->configuration->resolvePath('templates')
+ );
+ foreach ($templateDirs as $entry) {
+ $loader->addPath($entry[key($entry)], key($entry));
+ }
+ if (!$loader->exists($this->twig_template)) {
+ return false;
+ }
+ return $loader;
+ }
+
+
+ /**
+ * Setup twig.
+ */
+ private function setupTwig()
+ {
+ $auto_reload = $this->configuration->getBoolean('template.auto_reload', true);
+ $cache = false;
+ if (!$auto_reload) {
+ // Cache only used if auto_reload = false
+ $cache = $this->configuration->getString('template.cache', $this->configuration->resolvePath('cache'));
+ }
+ // set up template paths
+ $loader = $this->setupTwigTemplatepaths();
+ if (!$loader) {
+ return null;
+ }
+
+ return new \Twig_Environment($loader, array('cache' => $cache, 'auto_reload' => $auto_reload));
+ }
+
+ /*
+ * Add overriding templates in configured theme
+ *
+ * @return array an array of module => templatedir lookups
+ */
+ private function findThemeTemplateDirs()
+ {
+ // parse config to find theme and module theme is in, if any
+ $tmp = explode(':', $this->configuration->getString('theme.use', 'default'), 2);
+ if (count($tmp) === 2) {
+ $themeModule = $tmp[0];
+ $themeName = $tmp[1];
+ } else {
+ $themeModule = null;
+ $themeName = $tmp[0];
+ }
+ // default theme in use, abort
+ if ($themeName == 'default') {
+ return array();
+ }
+ if ($themeModule !== null) {
+ $moduleDir = \SimpleSAML\Module::getModuleDir($themeModule);
+ $themeDir = $moduleDir.'/themes/'.$themeName;
+ $files = scandir($themeDir);
+ if ($files) {
+ $themeTemplateDirs = array();
+ foreach ($files as $file) {
+ if ($file == '.' || $file == '..') {
+ continue;
+ }
+ // set correct name for default namespace
+ $ns = $file == 'default' ? $this->twig_namespace : $file;
+ $themeTemplateDirs[] = array($ns => $themeDir.'/'.$file);
+ }
+ return $themeTemplateDirs;
+ }
+ }
+ // theme not found
+ return array();
+ }
+
+ /*
+ * Which enabled modules have templates?
+ *
+ * @return array an array of module => templatedir lookups
+ */
+ private function findModuleTemplateDirs()
+ {
+ $all_modules = \SimpleSAML\Module::getModules();
+ $modules = array();
+ foreach ($all_modules as $module) {
+ if (!\SimpleSAML\Module::isModuleEnabled($module)) {
+ continue;
+ }
+ $moduledir = \SimpleSAML\Module::getModuleDir($module);
+ // check if module has a /templates dir, if so, append
+ $templatedir = $moduledir.'/templates';
+ if (is_dir($templatedir)) {
+ $modules[] = array($module => $templatedir);
+ }
+ }
+ return $modules;
+ }
+
+
+ /**
+ * Generate an array for its use in the language bar, indexed by the ISO 639-2 codes of the languages available,
+ * containing their localized names and the URL that should be used in order to change to that language.
+ *
+ * @return array The array containing information of all available languages.
+ */
+ private function generateLanguageBar()
+ {
+ $languages = $this->translator->getLanguage()->getLanguageList();
+ $langmap = null;
+ if (count($languages) > 1) {
+ $parameterName = $this->getTranslator()->getLanguage()->getLanguageParameterName();
+ $langmap = array();
+ foreach ($languages as $lang => $current) {
+ $lang = strtolower($lang);
+ $langname = $this->translator->getLanguage()->getLanguageLocalizedName($lang);
+ $url = false;
+ if (!$current) {
+ $url = htmlspecialchars(\SimpleSAML\Utils\HTTP::addURLParameters(
+ '',
+ array($parameterName => $lang)
+ ));
+ }
+ $langmap[$lang] = array(
+ 'name' => $langname,
+ 'url' => $url,
+ );
+ }
+ }
+ return $langmap;
+ }
+
+
+ /**
+ * Set some default context
+ */
+ private function twigDefaultContext()
+ {
+ $this->data['currentLanguage'] = $this->translator->getLanguage()->getLanguage();
+ // show language bar by default
+ if (!isset($this->data['hideLanguageBar'])) {
+ $this->data['hideLanguageBar'] = false;
+ }
+ // get languagebar
+ $this->data['languageBar'] = null;
+ if ($this->data['hideLanguageBar'] === false) {
+ $languageBar = $this->generateLanguageBar();
+ if (is_null($languageBar)) {
+ $this->data['hideLanguageBar'] = true;
+ } else {
+ $this->data['languageBar'] = $languageBar;
+ }
+ }
+
+ // assure that there is a <title> and <h1>
+ if (isset($this->data['header']) && !isset($this->data['pagetitle'])) {
+ $this->data['pagetitle'] = $this->data['header'];
+ }
+ if (!isset($this->data['pagetitle'])) {
+ $this->data['pagetitle'] = 'SimpleSAMLphp';
+ }
+
+ // set RTL
+ $this->data['isRTL'] = false;
+ if ($this->translator->getLanguage()->isLanguageRTL()) {
+ $this->data['isRTL'] = true;
+ }
}
@@ -72,8 +282,13 @@ class SimpleSAML_XHTML_Template
*/
public function show()
{
- $filename = $this->findTemplatePath($this->template);
- require($filename);
+ if ($this->twig) {
+ $this->twigDefaultContext();
+ echo $this->twig->render($this->twig_template, $this->data);
+ } else {
+ $filename = $this->findTemplatePath($this->template);
+ require($filename);
+ }
}
@@ -92,7 +307,7 @@ class SimpleSAML_XHTML_Template
*
* @throws Exception If the template file couldn't be found.
*/
- private function findTemplatePath($template)
+ private function findTemplatePath($template, $throw_exception = true)
{
assert('is_string($template)');
@@ -118,11 +333,11 @@ class SimpleSAML_XHTML_Template
if ($themeModule !== null) {
// .../module/<themeModule>/themes/<themeName>/<templateModule>/<templateName>
- $filename = SimpleSAML_Module::getModuleDir($themeModule).
+ $filename = \SimpleSAML\Module::getModuleDir($themeModule).
'/themes/'.$themeName.'/'.$templateModule.'/'.$templateName;
} elseif ($templateModule !== 'default') {
- // .../module/<templateModule>/templates/<themeName>/<templateName>
- $filename = SimpleSAML_Module::getModuleDir($templateModule).'/templates/'.$templateName;
+ // .../module/<templateModule>/templates/<templateName>
+ $filename = \SimpleSAML\Module::getModuleDir($templateModule).'/templates/'.$templateName;
} else {
// .../templates/<theme>/<templateName>
$filename = $this->configuration->getPathValue('templatedir', 'templates/').$templateName;
@@ -133,15 +348,15 @@ class SimpleSAML_XHTML_Template
}
// not found in current theme
- SimpleSAML_Logger::debug(
- $_SERVER['PHP_SELF'].' - Template: Could not find template file ['. $template.'] at ['.
+ \SimpleSAML_Logger::debug(
+ $_SERVER['PHP_SELF'].' - Template: Could not find template file ['.$template.'] at ['.
$filename.'] - now trying the base template'
);
// try default theme
if ($templateModule !== 'default') {
// .../module/<templateModule>/templates/<templateName>
- $filename = SimpleSAML_Module::getModuleDir($templateModule).'/templates/'.$templateName;
+ $filename = \SimpleSAML\Module::getModuleDir($templateModule).'/templates/'.$templateName;
} else {
// .../templates/<templateName>
$filename = $this->configuration->getPathValue('templatedir', 'templates/').'/'.$templateName;
@@ -151,11 +366,28 @@ class SimpleSAML_XHTML_Template
return $filename;
}
- // not found in default template - log error and throw exception
- $error = 'Template: Could not find template file ['.$template.'] at ['.$filename.']';
- SimpleSAML_Logger::critical($_SERVER['PHP_SELF'].' - '.$error);
+ // not found in default template
+ if ($throw_exception) {
+ // log error and throw exception
+ $error = 'Template: Could not find template file ['.$template.'] at ['.$filename.']';
+ \SimpleSAML_Logger::critical($_SERVER['PHP_SELF'].' - '.$error);
- throw new Exception($error);
+ throw new Exception($error);
+ } else {
+ // missing template expected, return NULL
+ return null;
+ }
+ }
+
+
+ /**
+ * Return the internal translator object used by this template.
+ *
+ * @return \SimpleSAML\Locale\Translate The translator that will be used with this template.
+ */
+ public function getTranslator()
+ {
+ return $this->translator;
}
@@ -191,6 +423,7 @@ class SimpleSAML_XHTML_Template
/**
* @param $language
* @param bool $setLanguageCookie
+ *
* @deprecated This method will be removed in SSP 2.0. Please use \SimpleSAML\Locale\Language::setLanguage()
* instead.
*/
@@ -213,6 +446,7 @@ class SimpleSAML_XHTML_Template
/**
* @param $language
+ *
* @deprecated This method will be removed in SSP 2.0. Please use \SimpleSAML\Locale\Language::setLanguageCookie()
* instead.
*/
@@ -221,10 +455,12 @@ class SimpleSAML_XHTML_Template
\SimpleSAML\Locale\Language::setLanguageCookie($language);
}
+
/**
* Wraps Language->getLanguageList
*/
- private function getLanguageList() {
+ private function getLanguageList()
+ {
return $this->translator->getLanguage()->getLanguageList();
}
@@ -242,10 +478,10 @@ class SimpleSAML_XHTML_Template
/**
- * Temporary wrapper for SimpleSAML\Locale\Translate::getPreferredTranslation().
+ * Temporary wrapper for \SimpleSAML\Locale\Translate::getPreferredTranslation().
*
* @deprecated This method will be removed in SSP 2.0. Please use
- * SimpleSAML\Locale\Translate::getPreferredTranslation() instead.
+ * \SimpleSAML\Locale\Translate::getPreferredTranslation() instead.
*/
public function getTranslation($translations)
{
@@ -258,7 +494,8 @@ class SimpleSAML_XHTML_Template
* This function can be used to include headers and footers etc.
*
*/
- private function includeAtTemplateBase($file) {
+ private function includeAtTemplateBase($file)
+ {
$data = $this->data;
$filename = $this->findTemplatePath($file);
@@ -283,6 +520,7 @@ class SimpleSAML_XHTML_Template
/**
* @param $file
* @param null $otherConfig
+ *
* @deprecated This method will be removed in SSP 2.0. Please use
* \SimpleSAML\Locale\Translate::includeLanguageFile() instead.
*/
@@ -295,7 +533,8 @@ class SimpleSAML_XHTML_Template
/**
* Wrap Language->isLanguageRTL
*/
- private function isLanguageRTL() {
+ private function isLanguageRTL()
+ {
return $this->translator->getLanguage()->isLanguageRTL();
}
@@ -305,6 +544,7 @@ class SimpleSAML_XHTML_Template
*
* @param array $def The array holding string definitions.
* @param array $lang The array holding translations for every string.
+ *
* @return array The recursive merge of both arrays.
* @deprecated This method will be removed in SimpleSAMLphp 2.0. Please use array_merge_recursive() instead.
*/