diff options
Diffstat (limited to 'lib/SimpleSAML/XHTML')
-rw-r--r-- | lib/SimpleSAML/XHTML/Template.php | 286 |
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. */ |