* @license http://www.contenido.org/license/LIZENZ.txt * @link http://www.4fb.de * @link http://www.contenido.org * @since file available since contenido release <= 4.6 */ if (!defined('CON_FRAMEWORK')) { die('Illegal call'); } /** * class Template * * Light template mechanism * * @author Jan Lengowski * @copyright four for business * @author Stefan Jelner (Optimizations) * @version 1.0 */ class Template { /** * Needles (static) * @var array */ public $needles = array(); /** * Replacements (static) * @var array */ public $replacements = array(); /** * Dyn_Needles (dynamic) * @var array */ public $Dyn_needles = array(); /** * Dyn_Replacements (dynamic) * @var array */ public $Dyn_replacements = array(); /** * Dynamic counter * @var int */ public $dyn_cnt = 0; /** * Tags array (for dynamic blocks); * @var array */ public $tags = array('static' => '{%s}', 'start' => '', 'end' => ''); /** * gettext domain (default: contenido) * @var string */ protected $_sDomain = "conlite"; var $array_registeredParsers = array(); /** * Constructor * * @param array $tags * @return void */ public function __construct($tags = false, $parser = false) { # Needed to block parsers in ConLite's backend and the module-template editor global $contenido, $changeview; if (is_array($tags)) { $this->tags = $tags; } $this->setEncoding(""); if (is_array($parser)) { $this->array_registeredParsers = $parser; } elseif ((!isset($contenido)) || ($changeview == 'edit') || ($changeview == 'prev')) { $this->array_registeredParsers = array( new clStrAPIFunctionsParser(), new clCounterFunctionParser(), new clIfFunctionParser() ); } } /** * setDomain * * Sets the gettext domain to use for translations in a template * * @param string $sDomain Sets the domain to use for template translations * @return void */ public function setDomain($sDomain) { $this->_sDomain = $sDomain; } /** * Set Templates placeholders and values * * With this method you can replace the placeholders * in the static templates with dynamic data. * * @param string $which String 's' for Static or else dynamic * @param string $needle String Placeholder * @param string $replacement String Replacement String * * @return void */ public function set($which, $needle, $replacement) { if ($which == 's') { // static $this->needles[] = sprintf($this->tags['static'], $needle); $this->replacements[] = $replacement; } else { // dynamic $this->Dyn_needles[$this->dyn_cnt][] = sprintf($this->tags['static'], $needle); $this->Dyn_replacements[$this->dyn_cnt][] = $replacement; } } /** * Sets an encoding for the template's head block. * * @param string $encoding Encoding to set */ public function setEncoding($encoding) { $this->_encoding = $encoding; } /** * Iterate internal counter by one * * @return void */ public function next() { $this->dyn_cnt++; } /** * Reset template data * * @return void */ public function reset() { $this->dyn_cnt = 0; $this->needles = array(); $this->replacements = array(); $this->Dyn_needles = array(); $this->Dyn_replacements = array(); } /** * Generate the template and * print/return it. (do translations sequentially to save memory!!!) * * @param string/file $template Template * @param boolean $return Return or print template * @param boolean $note Echo "Generated by ... " Comment * * @return string complete Template string */ public function generate($template, $return = 0, $note = 0) { global $cCurrentModule; $cfg = cRegistry::getConfig(); $aCfgClient = cRegistry::getClientConfig(cRegistry::getClientId()); $bModTplUsed = FALSE; if (isset($cCurrentModule) && $cfg['dceModEdit']['use']) { cInclude('includes', 'functions.upl.php'); $tmpModule = new cApiModule; $tmpModule->loadByPrimaryKey($cCurrentModule); $sModName = strtolower(uplCreateFriendlyName($tmpModule->get('name'))); $aModFileEditConf = $tmpModule->getModFileEditConf(); unset($tmpModule); $sTmpPath = $aModFileEditConf['modPath'] . $sModName . "/template/" . str_replace('templates/', '', $template); if (is_readable($sTmpPath)) { $template = $sTmpPath; $bModTplUsed = TRUE; } } if (is_file("templates/" . $template) && !$bModTplUsed) { $template = "templates/" . $template; } //check if the template is a file or a string if (!is_file($template)) { $content = & $template; //template is a string (it is a reference to save memory!!!) } else { $content = implode("", file($template)); //template is a file } $content = (($note) ? "\n" : "") . $content; // CEC for template pre processing $content = CEC_Hook::executeAndReturn('Contenido.Template.BeforeParse', $content, $this); $pieces = array(); //replace i18n strings before replacing other placeholders $this->replacei18n($content, "i18n"); $this->replacei18n($content, "trans"); //if content has dynamic blocks if (preg_match("/^.*" . preg_quote($this->tags['start'], "/") . ".*?" . preg_quote($this->tags['end'], "/") . ".*$/s", $content)) { //split everything into an array preg_match_all("/^(.*)" . preg_quote($this->tags['start'], "/") . "(.*?)" . preg_quote($this->tags['end'], "/") . "(.*)$/s", $content, $pieces); //safe memory array_shift($pieces); $content = ""; //now combine pieces together //start block $content .= str_replace($this->needles, $this->replacements, $pieces[0][0]); unset($pieces[0][0]); //generate dynamic blocks for ($a = 0; $a < $this->dyn_cnt; $a ++) { $content .= str_replace($this->Dyn_needles[$a], $this->Dyn_replacements[$a], $pieces[1][0]); } unset($pieces[1][0]); //end block $content .= str_replace($this->needles, $this->replacements, $pieces[2][0]); unset($pieces[2][0]); } else { $content = str_replace($this->needles, $this->replacements, $content); } if ($this->_encoding != "") { $content = str_replace("", '' . "\n" . '', $content); } # ExtendedTemplate if (count($this->array_registeredParsers)) { foreach ($this->array_registeredParsers as $class) { if (is_string($class)) { $classInstance = new $class; } elseif (is_object($class)) { $classInstance = $class; } if (is_object($classInstance)) { if (is_subclass_of($classInstance, "clAbstractTemplateParser")) { $content = $classInstance->parse($content); } else { $content = "TemplateParserKlasse " . get_class($classInstance) . " ist nicht von AbstractTemplateParser abgeleitet!"; break; } } } } if ($return) { return $content; } else { echo $content; } } # end function /** * replacei18n() * * Replaces a named function with the translated variant * * @param string $template Contents of the template to translate (it is reference to save memory!!!) * @param string $functionName Name of the translation function (e.g. i18n) * @return void */ public function replacei18n(& $template, $functionName) { $container = array(); // Be sure that php code stays unchanged $php_matches = array(); if (preg_match_all('/<\?(php)?((.)|(\s))*?\?>/i', $template, $php_matches)) { $x = 0; foreach ($php_matches[0] as $php_match) { $x++; $template = str_replace($php_match, "{PHP#" . $x . "#PHP}", $template); $container[$x] = $php_match; } } // If template contains functionName + parameter store all matches $matches = array(); preg_match_all("/" . preg_quote($functionName, "/") . "\\(([\\\"\\'])(.*?)\\1\\)/s", $template, $matches); // Execute the translation code $matches = array_values(array_unique($matches[2])); for ($a = 0; $a < count($matches); $a ++) { $template = preg_replace("/" . preg_quote($functionName, "/") . "\\([\\\"\\']" . preg_quote($matches[$a], "/") . "[\\\"\\']\\)/s", i18n($matches[$a], $this->_sDomain), $template); } // Change back php placeholder if (count($container)) { foreach ($container as $x => $php_match) { // If php code contains functionName + parameter store all matches $matches = array(); preg_match_all("/" . preg_quote($functionName, "/") . "\\(([\\\"\\'])(.*?)\\1\\)/s", $php_match, $matches); // Execute the translation code $matches = array_values(array_unique($matches[2])); for ($a = 0; $a < count($matches); $a ++) { $php_match = preg_replace("/" . preg_quote($functionName, "/") . "\\([\\\"\\']" . preg_quote($matches[$a], "/") . "[\\\"\\']\\)/s", '"' . i18n($matches[$a] . '"', $this->_sDomain), $php_match); } $template = str_replace("{PHP#" . $x . "#PHP}", $php_match, $template); } } } } class cTemplate extends Template { }