diff options
Diffstat (limited to 'libs/sysplugins/smarty_internal_template.php')
| -rw-r--r-- | libs/sysplugins/smarty_internal_template.php | 1159 |
1 files changed, 396 insertions, 763 deletions
diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index 4ddf2986..8efb95d0 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -1,87 +1,120 @@ <?php - /** * Smarty Internal Plugin Template * * This file contains the Smarty template engine * * @package Smarty - * @subpackage Templates + * @subpackage Template * @author Uwe Tews */ /** * Main class with template data structures and methods + * + * @package Smarty + * @subpackage Template + * + * @property Smarty_Template_Source $source + * @property Smarty_Template_Compiled $compiled + * @property Smarty_Template_Cached $cached */ -class Smarty_Internal_Template extends Smarty_Internal_Data { - // object cache - public $compiler_object = null; - public $cacher_object = null; - // Smarty parameter +class Smarty_Internal_Template extends Smarty_Internal_TemplateBase { + + /** + * cache_id + * @var string + */ public $cache_id = null; + /** + * $compile_id + * @var string + */ public $compile_id = null; + /** + * caching enabled + * @var boolean + */ public $caching = null; + /** + * cache lifetime in seconds + * @var integer + */ public $cache_lifetime = null; + /** + * Class name + * @var string + */ public $cacher_class = null; + /** + * caching type + * + * Must be an element of $cache_resource_types. + * + * @var string + */ public $caching_type = null; - public $forceNocache = false; - // Template resource + /** + * Template resource + * @var string + */ public $template_resource = null; - public $resource_type = null; - public $resource_name = null; -// public $resource_object = null; - private $isExisting = null; - public $templateUid = ''; - // Template source - public $template_filepath = null; - public $template_source = null; - private $template_timestamp = null; - // Compiled template - private $compiled_filepath = null; - public $compiled_template = null; - private $compiled_timestamp = null; + /** + * flag if compiled template is invalid and must be (re)compiled + * @var bool + */ public $mustCompile = null; - public $suppressHeader = false; - public $suppressFileDependency = false; + /** + * flag if template does contain nocache code sections + * @var bool + */ public $has_nocache_code = false; - public $write_compiled_code = true; - // Rendered content - public $rendered_content = null; - // Cache file - private $cached_filepath = null; - public $cached_timestamp = null; - private $isCached = null; -// private $cache_resource_object = null; - private $cacheFileChecked = false; - // template variables - public $tpl_vars = array(); - public $parent = null; - public $config_vars = array(); - // storage for plugin - public $plugin_data = array(); - // special properties - public $properties = array ('file_dependency' => array(), + /** + * special compiled and cached template properties + * @var array + */ + public $properties = array('file_dependency' => array(), 'nocache_hash' => '', 'function' => array()); - // required plugins + /** + * required plugins + * @var array + */ public $required_plugins = array('compiled' => array(), 'nocache' => array()); - public $saved_modifier = null; + /** + * Global smarty instance + * @var Smarty + */ public $smarty = null; - // blocks for template inheritance + /** + * blocks for template inheritance + * @var array + */ public $block_data = array(); - public $wrapper = null; - // optional log of tag/attributes + /** + * variable filters + * @var array + */ + public $variable_filters = array(); + /** + * optional log of tag/attributes + * @var array + */ public $used_tags = array(); + /** * Create template data object * * Some of the global Smarty settings copied to template scope * It load the required template resources and cacher plugins * - * @param string $template_resource template resource string - * @param object $_parent back pointer to parent object with variables or null - * @param mixed $_cache_id cache id or null - * @param mixed $_compile_id compile id or null + * @param string $template_resource template resource string + * @param Smarty $smarty Smarty instance + * @param Smarty_Internal_Template $_parent back pointer to parent object with variables or null + * @param mixed $_cache_id cache id or null + * @param mixed $_compile_id compile id or null + * @param bool $_caching use caching? + * @param int $_cache_lifetime cache life-time in seconds */ public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null) { @@ -90,81 +123,16 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { $this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id; $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id; $this->caching = $_caching === null ? $this->smarty->caching : $_caching; - if ($this->caching === true) $this->caching = Smarty::CACHING_LIFETIME_CURRENT; - $this->cache_lifetime = $_cache_lifetime === null ?$this->smarty->cache_lifetime : $_cache_lifetime; + if ($this->caching === true) + $this->caching = Smarty::CACHING_LIFETIME_CURRENT; + $this->cache_lifetime = $_cache_lifetime === null ? $this->smarty->cache_lifetime : $_cache_lifetime; $this->parent = $_parent; - // dummy local smarty variable - $this->tpl_vars['smarty'] = new Smarty_Variable; // Template resource $this->template_resource = $template_resource; // copy block data of template inheritance if ($this->parent instanceof Smarty_Internal_Template) { - $this->block_data = $this->parent->block_data; + $this->block_data = $this->parent->block_data; } - - } - - /** - * Returns the template filepath - * - * The template filepath is determined by the actual resource handler - * - * @return string the template filepath - */ - public function getTemplateFilepath () - { - return $this->template_filepath === null ? - $this->template_filepath = $this->resource_object->getTemplateFilepath($this) : - $this->template_filepath; - } - - /** - * Returns the timpestamp of the template source - * - * The template timestamp is determined by the actual resource handler - * - * @return integer the template timestamp - */ - public function getTemplateTimestamp () - { - return $this->template_timestamp === null ? - $this->template_timestamp = $this->resource_object->getTemplateTimestamp($this) : - $this->template_timestamp; - } - - /** - * Returns the template source code - * - * The template source is being read by the actual resource handler - * - * @return string the template source - */ - public function getTemplateSource () - { - if ($this->template_source === null) { - if (!$this->resource_object->getTemplateSource($this)) { - throw new SmartyException("Unable to read template {$this->resource_type} '{$this->resource_name}'"); - } - } - return $this->template_source; - } - - /** - * Returns if the template is existing - * - * The status is determined by the actual resource handler - * - * @return boolean true if the template exists - */ - public function isExisting ($error = false) - { - if ($this->isExisting === null) { - $this->isExisting = $this->resource_object->isExisting($this); - } - if (!$this->isExisting && $error) { - throw new SmartyException("Unable to load template {$this->resource_type} '{$this->resource_name}'"); - } - return $this->isExisting; } /** @@ -174,609 +142,195 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { * * @return boolean true if the template must be compiled */ - public function mustCompile () + public function mustCompile() { - $this->isExisting(true); + if (!$this->source->exists) { + throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'"); + } if ($this->mustCompile === null) { - $this->mustCompile = ($this->resource_object->usesCompiler && ($this->smarty->force_compile || $this->resource_object->isEvaluated || $this->getCompiledTimestamp () === false || - // ($this->smarty->compile_check && $this->getCompiledTimestamp () !== $this->getTemplateTimestamp ()))); - ($this->smarty->compile_check && $this->getCompiledTimestamp () < $this->getTemplateTimestamp ()))); + $this->mustCompile = (!$this->source->uncompiled && ($this->smarty->force_compile || $this->source->recompiled || $this->compiled->timestamp === false || + ($this->smarty->compile_check && $this->compiled->timestamp < $this->source->timestamp))); } return $this->mustCompile; } /** - * Returns the compiled template filepath - * - * @return string the template filepath - */ - public function getCompiledFilepath () - { - return $this->compiled_filepath === null ? - ($this->compiled_filepath = !$this->resource_object->isEvaluated ? $this->resource_object->getCompiledFilepath($this) : false) : - $this->compiled_filepath; - } - - /** - * Returns the timpestamp of the compiled template - * - * @return integer the template timestamp - */ - public function getCompiledTimestamp () - { - return $this->compiled_timestamp === null ? - ($this->compiled_timestamp = (!$this->resource_object->isEvaluated && file_exists($this->getCompiledFilepath())) ? filemtime($this->getCompiledFilepath()) : false) : - $this->compiled_timestamp; - } - - /** - * Returns the compiled template - * - * It checks if the template must be compiled or just read from the template resource - * - * @return string the compiled template - */ - public function getCompiledTemplate () - { - if ($this->compiled_template === null) { - // see if template needs compiling. - if ($this->mustCompile()) { - $this->compileTemplateSource(); - } else { - if ($this->compiled_template === null) { - $this->compiled_template = !$this->resource_object->isEvaluated && $this->resource_object->usesCompiler ? file_get_contents($this->getCompiledFilepath()) : false; - } - } - } - return $this->compiled_template; - } - - /** * Compiles the template * * If the template is not evaluated the compiled template is saved on disk */ - public function compileTemplateSource () + public function compileTemplateSource() { - if (!$this->resource_object->isEvaluated) { + if (!$this->source->recompiled) { $this->properties['file_dependency'] = array(); - $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type); + if ($this->source->components) { + // uses real resource for file dependency + $source = end($this->source->components); + $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $source->type); + } else { + $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type); + } } if ($this->smarty->debugging) { Smarty_Internal_Debug::start_compile($this); } - // compile template - if (!is_object($this->compiler_object)) { - // load compiler - $this->smarty->loadPlugin($this->resource_object->compiler_class); - $this->compiler_object = new $this->resource_object->compiler_class($this->resource_object->template_lexer_class, $this->resource_object->template_parser_class, $this->smarty); - } // compile locking - if ($this->smarty->compile_locking && !$this->resource_object->isEvaluated) { - if ($saved_timestamp = $this->getCompiledTimestamp()) { - touch($this->getCompiledFilepath()); + if ($this->smarty->compile_locking && !$this->source->recompiled) { + if ($saved_timestamp = $this->compiled->timestamp) { + touch($this->compiled->filepath); } } // call compiler try { - $this->compiler_object->compileTemplate($this); - } - catch (Exception $e) { + $code = $this->compiler->compileTemplate($this); + } catch (Exception $e) { // restore old timestamp in case of error - if ($this->smarty->compile_locking && !$this->resource_object->isEvaluated && $saved_timestamp) { - touch($this->getCompiledFilepath(), $saved_timestamp); + if ($this->smarty->compile_locking && !$this->source->recompiled && $saved_timestamp) { + touch($this->compiled->filepath, $saved_timestamp); } throw $e; } // compiling succeded - if (!$this->resource_object->isEvaluated && $this->write_compiled_code) { + if (!$this->source->recompiled && $this->compiler->write_compiled_code) { // write compiled template - Smarty_Internal_Write_File::writeFile($this->getCompiledFilepath(), $this->compiled_template, $this->smarty); + $_filepath = $this->compiled->filepath; + if ($_filepath === false) + throw new SmartyException('getCompiledFilepath() did not return a destination to save the compiled template to'); + Smarty_Internal_Write_File::writeFile($_filepath, $code, $this->smarty); + $this->compiled->exists = true; + $this->compiled->isCompiled = true; } if ($this->smarty->debugging) { Smarty_Internal_Debug::end_compile($this); } - // release objects to free memory - Smarty_Internal_TemplateCompilerBase::$_tag_objects = array(); - unset($this->compiler_object->parser->root_buffer, - $this->compiler_object->parser->current_buffer, - $this->compiler_object->parser, - $this->compiler_object->lex, - $this->compiler_object->template - ); - $this->compiler_object = null; - } - - /** - * Returns the filepath of the cached template output - * - * The filepath is determined by the actual cache resource - * - * @return string the cache filepath - */ - public function getCachedFilepath () - { - return $this->cached_filepath === null ? - $this->cached_filepath = ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) ? false : $this->cache_resource_object->getCachedFilepath($this) : - $this->cached_filepath; - } - - /** - * Returns the timpestamp of the cached template output - * - * The timestamp is determined by the actual cache resource - * - * @return integer the template timestamp - */ - public function getCachedTimestamp () - { - return $this->cached_timestamp === null ? - $this->cached_timestamp = ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) ? false : $this->cache_resource_object->getCachedTimestamp($this) : - $this->cached_timestamp; - } - - /** - * Returns the cached template output - * - * @return string |booelan the template content or false if the file does not exist - */ - public function getCachedContent () - { - return $this->rendered_content === null ? - $this->rendered_content = ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) ? false : $this->cache_resource_object->getCachedContents($this) : - $this->rendered_content; + // release compiler object to free memory + unset($this->compiler); } /** * Writes the cached template output + * + * @return bool */ - public function writeCachedContent ($content) + public function writeCachedContent($content) { - if ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) { + if ($this->source->recompiled || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) { // don't write cache file return false; } $this->properties['cache_lifetime'] = $this->cache_lifetime; - return $this->cache_resource_object->writeCachedContent($this, $this->createPropertyHeader(true) .$content); + $this->properties['unifunc'] = 'content_' . uniqid(); + $content = $this->createTemplateCodeFrame($content, true); + $_smarty_tpl = $this; + eval("?>" . $content); + $this->cached->valid = true; + $this->cached->processed = true; + return $this->cached->write($this, $content); } /** - * Checks of a valid version redered HTML output is in the cache - * - * If the cache is valid the contents is stored in the template object + * Template code runtime function to get subtemplate content * - * @return boolean true if cache is valid + * @param string $template the resource handle of the template file + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + * @param integer $caching cache mode + * @param integer $cache_lifetime life time of cache data + * @param array $vars optional variables to assign + * @param int $parent_scope scope in which {include} should execute + * @returns string template content */ - public function isCached ($template = null, $cache_id = null, $compile_id = null, $parent = null) + public function getSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope) { - if ($template === null) { - $no_render = true; - } elseif ($template === false) { - $no_render = false; - } else { - if ($parent === null) { - $parent = $this; - } - $this->smarty->isCached ($template, $cache_id, $compile_id, $parent); - } - if ($this->isCached === null) { - $this->isCached = false; - if (($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED) && !$this->resource_object->isEvaluated) { - $cachedTimestamp = $this->getCachedTimestamp(); - if ($cachedTimestamp === false || $this->smarty->force_compile || $this->smarty->force_cache) { - return $this->isCached; - } - if ($this->caching === Smarty::CACHING_LIFETIME_SAVED || ($this->caching == Smarty::CACHING_LIFETIME_CURRENT && (time() <= ($cachedTimestamp + $this->cache_lifetime) || $this->cache_lifetime < 0))) { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_cache($this); - } - $this->rendered_content = $this->cache_resource_object->getCachedContents($this, $no_render); - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_cache($this); - } - if ($this->cacheFileChecked) { - $this->isCached = true; - return $this->isCached; - } - $this->cacheFileChecked = true; - if ($this->caching === Smarty::CACHING_LIFETIME_SAVED && $this->properties['cache_lifetime'] >= 0 && (time() > ($this->getCachedTimestamp() + $this->properties['cache_lifetime']))) { - $this->tpl_vars = array(); - $this->tpl_vars['smarty'] = new Smarty_Variable; - $this->rendered_content = null; - return $this->isCached; - } - if (!empty($this->properties['file_dependency']) && $this->smarty->compile_check) { - $resource_type = null; - $resource_name = null; - foreach ($this->properties['file_dependency'] as $_file_to_check) { - If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') { - $mtime = filemtime($_file_to_check[0]); - } else { - $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name); - $resource_handler = $this->loadTemplateResourceHandler($resource_type); - $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name); - } - // If ($mtime > $this->getCachedTimestamp()) { - If ($mtime > $_file_to_check[1]) { - $this->tpl_vars = array(); - $this->tpl_vars['smarty'] = new Smarty_Variable; - $this->rendered_content = null; - return $this->isCached; - } - } - } - $this->isCached = true; - } - } - } - return $this->isCached; - } - - /** - * Render the output using the compiled template or the PHP template source - * - * The rendering process is accomplished by just including the PHP files. - * The only exceptions are evaluated templates (string template). Their code has - * to be evaluated - */ - public function renderTemplate () - { - if ($this->resource_object->usesCompiler) { - if ($this->mustCompile() && $this->compiled_template === null) { - $this->compileTemplateSource(); - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_render($this); - } - $_smarty_tpl = $this; - ob_start(); - if ($this->resource_object->isEvaluated) { - eval("?>" . $this->compiled_template); - } else { - include($this->getCompiledFilepath ()); - // check file dependencies at compiled code - if ($this->smarty->compile_check) { - if (!empty($this->properties['file_dependency'])) { - $this->mustCompile = false; - $resource_type = null; - $resource_name = null; - foreach ($this->properties['file_dependency'] as $_file_to_check) { - If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') { - $mtime = filemtime($_file_to_check[0]); - } else { - $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name); - $resource_handler = $this->loadTemplateResourceHandler($resource_type); - $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name); - } - // If ($mtime != $_file_to_check[1]) { - If ($mtime > $_file_to_check[1]) { - $this->mustCompile = true; - break; - } - } - if ($this->mustCompile) { - // recompile and render again - ob_get_clean(); - $this->compileTemplateSource(); - ob_start(); - include($this->getCompiledFilepath ()); - } - } - } - } + // already in template cache? + $_templateId = sha1($template . $cache_id . $compile_id); + if (isset($this->smarty->template_objects[$_templateId])) { + // clone cached template object because of possible recursive call + $tpl = clone $this->smarty->template_objects[$_templateId]; + $tpl->parent = $this; + $tpl->caching = $caching; + $tpl->cache_lifetime = $cache_lifetime; } else { - if (is_callable(array($this->resource_object, 'renderUncompiled'))) { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_render($this); - } - ob_start(); - $this->resource_object->renderUncompiled($this); - } else { - throw new SmartyException("Resource '$this->resource_type' must have 'renderUncompiled' methode"); - } - } - $this->rendered_content = ob_get_clean(); - if (!$this->resource_object->isEvaluated && empty($this->properties['file_dependency'][$this->templateUid])) { - $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type); + $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime); } - if ($this->parent instanceof Smarty_Internal_Template) { - $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']); - foreach($this->required_plugins as $code => $tmp1) { - foreach($tmp1 as $name => $tmp) { - foreach($tmp as $type => $data) { - $this->parent->required_plugins[$code][$name][$type] = $data; - } - } - } - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_render($this); - } - // write to cache when nessecary - if (!$this->resource_object->isEvaluated && ($this->caching == Smarty::CACHING_LIFETIME_SAVED || $this->caching == Smarty::CACHING_LIFETIME_CURRENT)) { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_cache($this); - } - $this->properties['has_nocache_code'] = false; - // get text between non-cached items - $cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content); - // get non-cached items - preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content, $cache_parts); - $output = ''; - // loop over items, stitch back together - foreach($cache_split as $curr_idx => $curr_split) { - // escape PHP tags in template content - $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php echo \'$1\'; ?>', $curr_split); - if (isset($cache_parts[0][$curr_idx])) { - $this->properties['has_nocache_code'] = true; - // remove nocache tags from cache output - $output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]); - } - } - if (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output'])) { - $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $this); - } - // rendering (must be done before writing cache file because of {function} nocache handling) - $_smarty_tpl = $this; - ob_start(); - eval("?>" . $output); - $this->rendered_content = ob_get_clean(); - // write cache file content - $this->writeCachedContent('<?php if (!$no_render) {?>'. $output. '<?php } ?>'); - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_cache($this); - } + // get variables from calling scope + if ($parent_scope == Smarty::SCOPE_LOCAL) { + $tpl->tpl_vars = $this->tpl_vars; + } elseif ($parent_scope == Smarty::SCOPE_PARENT) { + $tpl->tpl_vars = &$this->tpl_vars; + } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) { + $tpl->tpl_vars = &Smarty::$global_tpl_vars; + } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) { + $tpl->tpl_vars = &$this->tpl_vars; } else { - // var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content); - if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) { - // replace nocache_hash - $this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content); - $this->parent->has_nocache_code = $this->has_nocache_code; - } + $tpl->tpl_vars = &$scope_ptr->tpl_vars; } - } - - /** - * Returns the rendered HTML output - * - * If the cache is valid the cached content is used, otherwise - * the output is rendered from the compiled template or PHP template source - * - * @return string rendered HTML output - */ - public function getRenderedTemplate () - { - // disable caching for evaluated code - if ($this->resource_object->isEvaluated) { - $this->caching = false; - } - // checks if template exists - $this->isExisting(true); - // read from cache or render - if ($this->rendered_content === null) { - if ($this->isCached) { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_cache($this); - } - $this->rendered_content = $this->cache_resource_object->getCachedContents($this, false); - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_cache($this); + $tpl->config_vars = $this->config_vars; + if (!empty($data)) { + // set up variable values + foreach ($data as $_key => $_val) { + $tpl->tpl_vars[$_key] = new Smarty_variable($_val); } - } - if ($this->isCached === null) { - $this->isCached(false); - } - if (!$this->isCached) { - // render template (not loaded and not in cache) - $this->renderTemplate(); - } } - $this->updateParentVariables(); - $this->isCached = null; - return $this->rendered_content; + return $tpl->fetch(null, null, null, null, false, false); } /** - * Parse a template resource in its name and type - * Load required resource handler + * Template code runtime function to set up an inline subtemplate * - * @param string $template_resource template resource specification - * @param string $resource_type return resource type - * @param string $resource_name return resource name - * @param object $resource_handler return resource handler object + * @param string $template the resource handle of the template file + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + * @param integer $caching cache mode + * @param integer $cache_lifetime life time of cache data + * @param array $vars optional variables to assign + * @param int $parent_scope scope in which {include} should execute + * @param string $hash nocache hash code + * @returns string template content */ - public function parseResourceName($template_resource, &$resource_type, &$resource_name, &$resource_handler) + public function setupInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash) { - if (empty($template_resource)) - return false; - $this->getResourceTypeName($template_resource, $resource_type, $resource_name); - $resource_handler = $this->loadTemplateResourceHandler($resource_type); - // cache template object under a unique ID - // do not cache eval resources - if ($resource_type != 'eval') { - $this->smarty->template_objects[sha1($this->template_resource . $this->cache_id . $this->compile_id)] = $this; - } - return true; - } - - /** - * get system filepath to template - */ - public function buildTemplateFilepath ($file = null) - { - if ($file == null) { - $file = $this->resource_name; - } - // relative file name? - if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) { - foreach((array)$this->smarty->template_dir as $_template_dir) { - if (strpos('/\\', substr($_template_dir, -1)) === false) { - $_template_dir .= DS; - } - $_filepath = $_template_dir . $file; - if (file_exists($_filepath)) { - return $_filepath; - } - if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_template_dir)) { - // try PHP include_path - if (($_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath)) !== false) { - return $_filepath; - } - } - } - } - // try absolute filepath - if (file_exists($file)) return $file; - // no tpl file found - if (!empty($this->smarty->default_template_handler_func)) { - if (!is_callable($this->smarty->default_template_handler_func)) { - throw new SmartyException("Default template handler not callable"); - } else { - $_return = call_user_func_array($this->smarty->default_template_handler_func, - array($this->resource_type, $this->resource_name, &$this->template_source, &$this->template_timestamp, $this)); - if (is_string($_return)) { - return $_return; - } elseif ($_return === true) { - return $file; - } - } + $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime); + $tpl->properties['nocache_hash'] = $hash; + // get variables from calling scope + if ($parent_scope == Smarty::SCOPE_LOCAL ) { + $tpl->tpl_vars = $this->tpl_vars; + } elseif ($parent_scope == Smarty::SCOPE_PARENT) { + $tpl->tpl_vars = &$this->tpl_vars; + } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) { + $tpl->tpl_vars = &Smarty::$global_tpl_vars; + } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) { + $tpl->tpl_vars = &$this->tpl_vars; + } else { + $tpl->tpl_vars = &$scope_ptr->tpl_vars; } - return false; - } - - /** - * Update Smarty variables in other scopes - */ - public function updateParentVariables ($scope = Smarty::SCOPE_LOCAL) - { - $has_root = false; - foreach ($this->tpl_vars as $_key => $_variable) { - $_variable_scope = $this->tpl_vars[$_key]->scope; - if (($scope == Smarty::SCOPE_LOCAL && $_variable_scope == Smarty::SCOPE_LOCAL) || $_key == 'smarty') { - continue; - } - if (isset($this->parent) && ($scope == Smarty::SCOPE_PARENT || $_variable_scope == Smarty::SCOPE_PARENT)) { - if (isset($this->parent->tpl_vars[$_key])) { - // variable is already defined in parent, copy value - $this->parent->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value; - } else { - // create variable in parent - $this->parent->tpl_vars[$_key] = clone $_variable; - $this->parent->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL; - } - } - if ($scope == Smarty::SCOPE_ROOT || $_variable_scope == Smarty::SCOPE_ROOT) { - if ($this->parent == null) { - continue; - } - if (!$has_root) { - // find root - $root_ptr = $this; - while ($root_ptr->parent != null) { - $root_ptr = $root_ptr->parent; - $has_root = true; - } - } - if (isset($root_ptr->tpl_vars[$_key])) { - // variable is already defined in root, copy value - $root_ptr->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value; - } else { - // create variable in root - $root_ptr->tpl_vars[$_key] = clone $_variable; - $root_ptr->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL; - } - } - if ($scope == Smarty::SCOPE_GLOBAL || $_variable_scope == Smarty::SCOPE_GLOBAL) { - if (isset(Smarty::$global_tpl_vars[$_key])) { - // variable is already defined in root, copy value - Smarty::$global_tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value; - } else { - // create global variable - Smarty::$global_tpl_vars[$_key] = clone $_variable; - } - Smarty::$global_tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL; + $tpl->config_vars = $this->config_vars; + if (!empty($data)) { + // set up variable values + foreach ($data as $_key => $_val) { + $tpl->tpl_vars[$_key] = new Smarty_variable($_val); } } + return $tpl; } - /** - * Split a template resource in its name and type - * - * @param string $template_resource template resource specification - * @param string $resource_type return resource type - * @param string $resource_name return resource name - */ - protected function getResourceTypeName ($template_resource, &$resource_type, &$resource_name) - { - if (strpos($template_resource, ':') === false) { - // no resource given, use default - $resource_type = $this->smarty->default_resource_type; - $resource_name = $template_resource; - } else { - // get type and name from path - list($resource_type, $resource_name) = explode(':', $template_resource, 2); - if (strlen($resource_type) == 1) { - // 1 char is not resource type, but part of filepath - $resource_type = 'file'; - $resource_name = $template_resource; - } - } - } /** - * Load template resource handler by type + * Create code frame for compiled and cached templates * - * @param string $resource_type template resource type - * @return object resource handler object - */ - protected function loadTemplateResourceHandler ($resource_type) - { - // try registered resource - if (isset($this->smarty->registered_resources[$resource_type])) { - return new Smarty_Internal_Resource_Registered($this); - } else { - // try sysplugins dir - if (in_array($resource_type, array('file', 'string', 'extends', 'php', 'stream', 'eval'))) { - $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($resource_type); - return new $_resource_class($this->smarty); - } else { - // try plugins dir - $_resource_class = 'Smarty_Resource_' . ucfirst($resource_type); - if ($this->smarty->loadPlugin($_resource_class)) { - if (class_exists($_resource_class, false)) { - return new $_resource_class($this->smarty); - } else { - return new Smarty_Internal_Resource_Registered($this, $resource_type); - } - } else { - // try streams - $_known_stream = stream_get_wrappers(); - if (in_array($resource_type, $_known_stream)) { - // is known stream - if (is_object($this->smarty->security_policy)) { - $this->smarty->security_policy->isTrustedStream($resource_type); - } - return new Smarty_Internal_Resource_Stream($this->smarty); - } else { - throw new SmartyException('Unkown resource type \'' . $resource_type . '\''); - } - } - } - } - } - - /** - * Create property header + * @param string $content optional template content + * @param bool $cache flag for cache file + * @return string */ - public function createPropertyHeader ($cache = false) + public function createTemplateCodeFrame($content = '', $cache = false) { $plugins_string = ''; // include code for plugins if (!$cache) { if (!empty($this->required_plugins['compiled'])) { $plugins_string = '<?php '; - foreach($this->required_plugins['compiled'] as $tmp) { - foreach($tmp as $data) { + foreach ($this->required_plugins['compiled'] as $tmp) { + foreach ($tmp as $data) { $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n"; } } @@ -784,9 +338,9 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { } if (!empty($this->required_plugins['nocache'])) { $this->has_nocache_code = true; - $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php "; - foreach($this->required_plugins['nocache'] as $tmp) { - foreach($tmp as $data) { + $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php \$_smarty = \$_smarty_tpl->smarty; "; + foreach ($this->required_plugins['nocache'] as $tmp) { + foreach ($tmp as $data) { $plugins_string .= "if (!is_callable(\'{$data['function']}\')) include \'{$data['file']}\';\n"; } } @@ -795,9 +349,12 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { } // build property code $this->properties['has_nocache_code'] = $this->has_nocache_code; - $properties_string = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/" ; - if ($this->smarty->direct_access_security) { - $properties_string .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n"; + $output = ''; + if (!$this->source->recompiled) { + $output = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/"; + if ($this->smarty->direct_access_security) { + $output .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n"; + } } if ($cache) { // remove compiled code of{function} definition @@ -812,14 +369,35 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { } } } - $properties_string .= "\$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n"; - return $properties_string . $plugins_string; + $this->properties['version'] = Smarty::SMARTY_VERSION; + if (!isset($this->properties['unifunc'])) { + $this->properties['unifunc'] = 'content_' . uniqid(); + } + if (!$this->source->recompiled) { + $output .= "\$_valid = \$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . ',' . ($cache ? 'true' : 'false') . "); /*/%%SmartyHeaderCode%%*/?>\n"; + } + if (!$this->source->recompiled) { + $output .= '<?php if ($_valid && !is_callable(\'' . $this->properties['unifunc'] . '\')) {function ' . $this->properties['unifunc'] . '($_smarty_tpl) {?>'; + } + $output .= $plugins_string; + $output .= $content; + if (!$this->source->recompiled) { + $output .= '<?php }} ?>'; + } + return $output; } /** - * Decode saved properties from compiled template and cache files + * This function is executed automatically when a compiled or cached template file is included + * + * - Decode saved properties from compiled template and cache files + * - Check if compiled or cache file is valid + * + * @param array $properties special template properties + * @param bool $cache flag if called from cache file + * @return bool flag if compiled or cache file is valid */ - public function decodeProperties ($properties) + public function decodeProperties($properties, $cache = false) { $this->has_nocache_code = $properties['has_nocache_code']; $this->properties['nocache_hash'] = $properties['nocache_hash']; @@ -833,31 +411,114 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { $this->properties['function'] = array_merge($this->properties['function'], $properties['function']); $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']); } + $this->properties['version'] = (isset($properties['version'])) ? $properties['version'] : ''; + $this->properties['unifunc'] = $properties['unifunc']; + // check file dependencies at compiled code + $is_valid = true; + if ($this->properties['version'] != Smarty::SMARTY_VERSION) { + $is_valid = false; + } else if (((!$cache && $this->smarty->compile_check && empty($this->compiled->_properties)) || $cache && ($this->smarty->compile_check === true || $this->smarty->compile_check === Smarty::COMPILECHECK_ON)) && !empty($this->properties['file_dependency'])) { + foreach ($this->properties['file_dependency'] as $_file_to_check) { + if ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'php') { + if ($this->source->filepath == $_file_to_check[0] && isset($this->source->timestamp)) { + // do not recheck current template + $mtime = $this->source->timestamp; + } else { + // file and php types can be checked without loading the respective resource handlers + $mtime = filemtime($_file_to_check[0]); + } + } elseif ($_file_to_check[2] == 'string') { + continue; + } else { + $source = Smarty_Resource::source($this, $this->smarty, $_file_to_check[0]); + $mtime = $source->timestamp; + } + if ($mtime > $_file_to_check[1]) { + $is_valid = false; + break; + } + } + } + if ($cache) { + $this->cached->valid = $is_valid; + } else { + $this->mustCompile = !$is_valid; + } + // store data in reusable Smarty_Template_Compiled + if (!$cache) { + $this->compiled->_properties = $properties; + } + return $is_valid; } /** - * creates a local Smarty variable for array assignments + * Template code runtime function to create a local Smarty variable for array assignments + * + * @param string $tpl_var tempate variable name + * @param bool $nocache cache mode of variable + * @param int $scope scope of variable */ public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL) { if (!isset($this->tpl_vars[$tpl_var])) { - $tpl_var_inst = $this->getVariable($tpl_var, null, true, false); - if ($tpl_var_inst instanceof Undefined_Smarty_Variable) { - $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope); - } else { - $this->tpl_vars[$tpl_var] = clone $tpl_var_inst; - if ($scope != Smarty::SCOPE_LOCAL) { - $this->tpl_vars[$tpl_var]->scope = $scope; - } + $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope); + } else { + $this->tpl_vars[$tpl_var] = clone $this->tpl_vars[$tpl_var]; + if ($scope != Smarty::SCOPE_LOCAL) { + $this->tpl_vars[$tpl_var]->scope = $scope; + } + if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) { + settype($this->tpl_vars[$tpl_var]->value, 'array'); } } - if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) { - settype($this->tpl_vars[$tpl_var]->value, 'array'); + } + + /** + * Template code runtime function to get pointer to template variable array of requested scope + * + * @param int $scope requested variable scope + * @return array array of template variables + */ + public function &getScope($scope) + { + if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) { + return $this->parent->tpl_vars; + } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) { + $ptr = $this->parent; + while (!empty($ptr->parent)) { + $ptr = $ptr->parent; + } + return $ptr->tpl_vars; + } elseif ($scope == Smarty::SCOPE_GLOBAL) { + return Smarty::$global_tpl_vars; } + $null = null; + return $null; + } + + /** + * Get parent or root of template parent chain + * + * @param int $scope pqrent or root scope + * @return mixed object + */ + public function getScopePointer($scope) + { + if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) { + return $this->parent; + } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) { + $ptr = $this->parent; + while (!empty($ptr->parent)) { + $ptr = $ptr->parent; + } + return $ptr; + } + return null; } /** * [util function] counts an array, arrayaccess/traversable or PDOStatement object + * * @param mixed $value * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 for empty elements */ @@ -865,11 +526,12 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { { if (is_array($value) === true || $value instanceof Countable) { return count($value); + } elseif ($value instanceof IteratorAggregate) { + // Note: getIterator() returns a Traversable, not an Iterator + // thus rewind() and valid() methods may not be present + return iterator_count($value->getIterator()); } elseif ($value instanceof Iterator) { - $value->rewind(); - if ($value->valid()) { - return iterator_count($value); - } + return iterator_count($value); } elseif ($value instanceof PDOStatement) { return $value->rowCount(); } elseif ($value instanceof Traversable) { @@ -878,125 +540,96 @@ class Smarty_Internal_Template extends Smarty_Internal_Data { if ($value->offsetExists(0)) { return 1; } - } elseif (is_object($value)) { + } elseif (is_object($value)) { return count($value); - } - return 0; - } - - /** - * wrapper for fetch - */ - public function fetch ($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false) - { - if ($template == null) { - return $this->smarty->fetch($this); - } else { - if (!isset($parent)) { - $parent = $this; - } - return $this->smarty->fetch($template, $cache_id, $compile_id, $parent, $display); } - - } - - /** - * wrapper for display - */ - public function display ($template = null, $cache_id = null, $compile_id = null, $parent = null) - { - if ($template == null) { - return $this->smarty->display($this); - } else { - if (!isset($parent)) { - $parent = $this; - } - return $this->smarty->display($template, $cache_id, $compile_id, $parent); - } - + return 0; } /** * set Smarty property in template context + * * @param string $property_name property name - * @param mixed $value value + * @param mixed $value value */ public function __set($property_name, $value) { - if ($property_name == 'resource_object' || $property_name == 'cache_resource_object') { - $this->$property_name = $value; - } elseif (property_exists($this->smarty, $property_name)) { - $this->smarty->$property_name = $value; - } else { - throw new SmartyException("invalid template property '$property_name'."); + switch ($property_name) { + case 'source': + case 'compiled': + case 'cached': + case 'compiler': + $this->$property_name = $value; + return; + + // FIXME: routing of template -> smarty attributes + default: + if (property_exists($this->smarty, $property_name)) { + $this->smarty->$property_name = $value; + return; + } } + + throw new SmartyException("invalid template property '$property_name'."); } /** * get Smarty property in template context + * * @param string $property_name property name */ public function __get($property_name) { - if ($property_name == 'resource_object') { - // load template resource - $this->resource_object = null; - if (!$this->parseResourceName ($this->template_resource, $this->resource_type, $this->resource_name, $this->resource_object)) { - throw new SmartyException ("Unable to parse resource name \"{$this->template_resource}\""); - } - return $this->resource_object; - } - if ($property_name == 'cache_resource_object') { - // load cache resource - $this->cache_resource_object = $this->loadCacheResource(); - return $this->cache_resource_object; - } - if (property_exists($this->smarty, $property_name)) { - return $this->smarty->$property_name; - } else { - throw new SmartyException("template property '$property_name' does not exist."); + switch ($property_name) { + case 'source': + if (empty($this->template_resource)) { + throw new SmartyException("Unable to parse resource name \"{$this->template_resource}\""); + } + $this->source = Smarty_Resource::source($this); + // cache template object under a unique ID + // do not cache eval resources + if ($this->source->type != 'eval') { + $this->smarty->template_objects[sha1($this->template_resource . $this->cache_id . $this->compile_id)] = $this; + } + return $this->source; + + case 'compiled': + $this->compiled = $this->source->getCompiled($this); + return $this->compiled; + + case 'cached': + if (!class_exists('Smarty_Template_Cached')) { + include SMARTY_SYSPLUGINS_DIR . 'smarty_cacheresource.php'; + } + $this->cached = new Smarty_Template_Cached($this); + return $this->cached; + + case 'compiler': + $this->smarty->loadPlugin($this->source->compiler_class); + $this->compiler = new $this->source->compiler_class($this->source->template_lexer_class, $this->source->template_parser_class, $this->smarty); + return $this->compiler; + + // FIXME: routing of template -> smarty attributes + default: + if (property_exists($this->smarty, $property_name)) { + return $this->smarty->$property_name; + } } - } + throw new SmartyException("template property '$property_name' does not exist."); + } /** - * Takes unknown class methods and lazy loads sysplugin files for them - * class name format: Smarty_Method_MethodName - * plugin filename format: method.methodname.php + * Template data object destrutor * - * @param string $name unknown methode name - * @param array $args aurgument array */ - public function __call($name, $args) + public function __destruct() { - static $camel_func; - if (!isset($camel_func)) - $camel_func = create_function('$c', 'return "_" . strtolower($c[1]);'); - // see if this is a set/get for a property - $first3 = strtolower(substr($name, 0, 3)); - if (in_array($first3, array('set', 'get')) && substr($name, 3, 1) !== '_') { - // try to keep case correct for future PHP 6.0 case-sensitive class methods - // lcfirst() not available < PHP 5.3.0, so improvise - $property_name = strtolower(substr($name, 3, 1)) . substr($name, 4); - // convert camel case to underscored name - $property_name = preg_replace_callback('/([A-Z])/', $camel_func, $property_name); - if (property_exists($this, $property_name)) { - if ($first3 == 'get') - return $this->$property_name; - else - return $this->$property_name = $args[0]; - } + if ($this->smarty->cache_locking && isset($this->cached) && $this->cached->is_locked) { + $this->cached->handler->releaseLock($this->smarty, $this->cached); } - // Smarty Backward Compatible wrapper - if (strpos($name,'_') !== false) { - if (!isset($this->wrapper)) { - $this->wrapper = new Smarty_Internal_Wrapper($this); - } - return $this->wrapper->convert($name, $args); - } - // pass call to Smarty object - return call_user_func_array(array($this->smarty,$name),$args); } } + ?>
\ No newline at end of file |
