4 * Smarty Internal Plugin Template
6 * This file contains the Smarty template engine
9 * @subpackage Templates
14 * Main class with template data structures and methods
16 class Smarty_Internal_Template extends Smarty_Internal_Data {
18 public $compiler_object = null;
19 public $cacher_object = null;
21 public $cache_id = null;
22 public $compile_id = null;
23 public $caching = null;
24 public $cache_lifetime = null;
25 public $cacher_class = null;
26 public $caching_type = null;
27 public $forceNocache = false;
29 public $template_resource = null;
30 public $resource_type = null;
31 public $resource_name = null;
32 // public $resource_object = null;
33 private $isExisting = null;
34 public $templateUid = '';
36 public $template_filepath = null;
37 public $template_source = null;
38 private $template_timestamp = null;
40 private $compiled_filepath = null;
41 public $compiled_template = null;
42 private $compiled_timestamp = null;
43 public $mustCompile = null;
44 public $suppressHeader = false;
45 public $suppressFileDependency = false;
46 public $has_nocache_code = false;
47 public $write_compiled_code = true;
49 public $rendered_content = null;
51 private $cached_filepath = null;
52 public $cached_timestamp = null;
53 private $isCached = null;
54 // private $cache_resource_object = null;
55 private $cacheFileChecked = false;
57 public $tpl_vars = array();
58 public $parent = null;
59 public $config_vars = array();
61 public $plugin_data = array();
63 public $properties = array ('file_dependency' => array(),
65 'function' => array());
67 public $required_plugins = array('compiled' => array(), 'nocache' => array());
68 public $saved_modifier = null;
69 public $smarty = null;
70 // blocks for template inheritance
71 public $block_data = array();
72 public $wrapper = null;
74 * Create template data object
76 * Some of the global Smarty settings copied to template scope
77 * It load the required template resources and cacher plugins
79 * @param string $template_resource template resource string
80 * @param object $_parent back pointer to parent object with variables or null
81 * @param mixed $_cache_id cache id or null
82 * @param mixed $_compile_id compile id or null
84 public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null)
86 $this->smarty = &$smarty;
88 $this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id;
89 $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id;
90 $this->caching = $_caching === null ? $this->smarty->caching : $_caching;
91 if ($this->caching === true) $this->caching = Smarty::CACHING_LIFETIME_CURRENT;
92 $this->cache_lifetime = $_cache_lifetime === null ?$this->smarty->cache_lifetime : $_cache_lifetime;
93 $this->parent = $_parent;
94 // dummy local smarty variable
95 $this->tpl_vars['smarty'] = new Smarty_Variable;
97 $this->template_resource = $template_resource;
98 // copy block data of template inheritance
99 if ($this->parent instanceof Smarty_Internal_Template) {
100 $this->block_data = $this->parent->block_data;
106 * Returns the template filepath
108 * The template filepath is determined by the actual resource handler
110 * @return string the template filepath
112 public function getTemplateFilepath ()
114 return $this->template_filepath === null ?
115 $this->template_filepath = $this->resource_object->getTemplateFilepath($this) :
116 $this->template_filepath;
120 * Returns the timpestamp of the template source
122 * The template timestamp is determined by the actual resource handler
124 * @return integer the template timestamp
126 public function getTemplateTimestamp ()
128 return $this->template_timestamp === null ?
129 $this->template_timestamp = $this->resource_object->getTemplateTimestamp($this) :
130 $this->template_timestamp;
134 * Returns the template source code
136 * The template source is being read by the actual resource handler
138 * @return string the template source
140 public function getTemplateSource ()
142 if ($this->template_source === null) {
143 if (!$this->resource_object->getTemplateSource($this)) {
144 throw new SmartyException("Unable to read template {$this->resource_type} '{$this->resource_name}'");
147 return $this->template_source;
151 * Returns if the template is existing
153 * The status is determined by the actual resource handler
155 * @return boolean true if the template exists
157 public function isExisting ($error = false)
159 if ($this->isExisting === null) {
160 $this->isExisting = $this->resource_object->isExisting($this);
162 if (!$this->isExisting && $error) {
163 throw new SmartyException("Unable to load template {$this->resource_type} '{$this->resource_name}'");
165 return $this->isExisting;
169 * Returns if the current template must be compiled by the Smarty compiler
171 * It does compare the timestamps of template source and the compiled templates and checks the force compile configuration
173 * @return boolean true if the template must be compiled
175 public function mustCompile ()
177 $this->isExisting(true);
178 if ($this->mustCompile === null) {
179 $this->mustCompile = ($this->resource_object->usesCompiler && ($this->smarty->force_compile || $this->resource_object->isEvaluated || $this->getCompiledTimestamp () === false ||
180 // ($this->smarty->compile_check && $this->getCompiledTimestamp () !== $this->getTemplateTimestamp ())));
181 ($this->smarty->compile_check && $this->getCompiledTimestamp () < $this->getTemplateTimestamp ())));
183 return $this->mustCompile;
187 * Returns the compiled template filepath
189 * @return string the template filepath
191 public function getCompiledFilepath ()
193 return $this->compiled_filepath === null ?
194 ($this->compiled_filepath = !$this->resource_object->isEvaluated ? $this->resource_object->getCompiledFilepath($this) : false) :
195 $this->compiled_filepath;
199 * Returns the timpestamp of the compiled template
201 * @return integer the template timestamp
203 public function getCompiledTimestamp ()
205 return $this->compiled_timestamp === null ?
206 ($this->compiled_timestamp = (!$this->resource_object->isEvaluated && file_exists($this->getCompiledFilepath())) ? filemtime($this->getCompiledFilepath()) : false) :
207 $this->compiled_timestamp;
211 * Returns the compiled template
213 * It checks if the template must be compiled or just read from the template resource
215 * @return string the compiled template
217 public function getCompiledTemplate ()
219 if ($this->compiled_template === null) {
220 // see if template needs compiling.
221 if ($this->mustCompile()) {
222 $this->compileTemplateSource();
224 if ($this->compiled_template === null) {
225 $this->compiled_template = !$this->resource_object->isEvaluated && $this->resource_object->usesCompiler ? file_get_contents($this->getCompiledFilepath()) : false;
229 return $this->compiled_template;
233 * Compiles the template
235 * If the template is not evaluated the compiled template is saved on disk
237 public function compileTemplateSource ()
239 if (!$this->resource_object->isEvaluated) {
240 $this->properties['file_dependency'] = array();
241 $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type);
243 if ($this->smarty->debugging) {
244 Smarty_Internal_Debug::start_compile($this);
247 if (!is_object($this->compiler_object)) {
249 $this->smarty->loadPlugin($this->resource_object->compiler_class);
250 $this->compiler_object = new $this->resource_object->compiler_class($this->resource_object->template_lexer_class, $this->resource_object->template_parser_class, $this->smarty);
253 if ($this->smarty->compile_locking && !$this->resource_object->isEvaluated) {
254 if ($saved_timestamp = $this->getCompiledTimestamp()) {
255 touch($this->getCompiledFilepath());
260 $this->compiler_object->compileTemplate($this);
262 catch (Exception $e) {
263 // restore old timestamp in case of error
264 if ($this->smarty->compile_locking && !$this->resource_object->isEvaluated && $saved_timestamp) {
265 touch($this->getCompiledFilepath(), $saved_timestamp);
269 // compiling succeded
270 if (!$this->resource_object->isEvaluated && $this->write_compiled_code) {
271 // write compiled template
272 Smarty_Internal_Write_File::writeFile($this->getCompiledFilepath(), $this->compiled_template, $this->smarty);
274 if ($this->smarty->debugging) {
275 Smarty_Internal_Debug::end_compile($this);
277 // release objects to free memory
278 Smarty_Internal_TemplateCompilerBase::$_tag_objects = array();
279 unset($this->compiler_object->parser->root_buffer,
280 $this->compiler_object->parser->current_buffer,
281 $this->compiler_object->parser,
282 $this->compiler_object->lex,
283 $this->compiler_object->template,
284 $this->compiler_object
289 * Returns the filepath of the cached template output
291 * The filepath is determined by the actual cache resource
293 * @return string the cache filepath
295 public function getCachedFilepath ()
297 return $this->cached_filepath === null ?
298 $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) :
299 $this->cached_filepath;
303 * Returns the timpestamp of the cached template output
305 * The timestamp is determined by the actual cache resource
307 * @return integer the template timestamp
309 public function getCachedTimestamp ()
311 return $this->cached_timestamp === null ?
312 $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) :
313 $this->cached_timestamp;
317 * Returns the cached template output
319 * @return string |booelan the template content or false if the file does not exist
321 public function getCachedContent ()
323 return $this->rendered_content === null ?
324 $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) :
325 $this->rendered_content;
329 * Writes the cached template output
331 public function writeCachedContent ($content)
333 if ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) {
334 // don't write cache file
337 $this->properties['cache_lifetime'] = $this->cache_lifetime;
338 return $this->cache_resource_object->writeCachedContent($this, $this->createPropertyHeader(true) .$content);
342 * Checks of a valid version redered HTML output is in the cache
344 * If the cache is valid the contents is stored in the template object
346 * @return boolean true if cache is valid
348 public function isCached ($template = null, $cache_id = null, $compile_id = null, $parent = null)
350 if ($template === null) {
352 } elseif ($template === false) {
355 if ($parent === null) {
358 $this->smarty->isCached ($template, $cache_id, $compile_id, $parent);
360 if ($this->isCached === null) {
361 $this->isCached = false;
362 if (($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED) && !$this->resource_object->isEvaluated) {
363 $cachedTimestamp = $this->getCachedTimestamp();
364 if ($cachedTimestamp === false || $this->smarty->force_compile || $this->smarty->force_cache) {
365 return $this->isCached;
367 if ($this->caching === Smarty::CACHING_LIFETIME_SAVED || ($this->caching == Smarty::CACHING_LIFETIME_CURRENT && (time() <= ($cachedTimestamp + $this->cache_lifetime) || $this->cache_lifetime < 0))) {
368 if ($this->smarty->debugging) {
369 Smarty_Internal_Debug::start_cache($this);
371 $this->rendered_content = $this->cache_resource_object->getCachedContents($this, $no_render);
372 if ($this->smarty->debugging) {
373 Smarty_Internal_Debug::end_cache($this);
375 if ($this->cacheFileChecked) {
376 $this->isCached = true;
377 return $this->isCached;
379 $this->cacheFileChecked = true;
380 if ($this->caching === Smarty::CACHING_LIFETIME_SAVED && $this->properties['cache_lifetime'] >= 0 && (time() > ($this->getCachedTimestamp() + $this->properties['cache_lifetime']))) {
381 $this->tpl_vars = array();
382 $this->rendered_content = null;
383 return $this->isCached;
385 if (!empty($this->properties['file_dependency']) && $this->smarty->compile_check) {
386 $resource_type = null;
387 $resource_name = null;
388 foreach ($this->properties['file_dependency'] as $_file_to_check) {
389 If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
390 $mtime = filemtime($_file_to_check[0]);
392 $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
393 $resource_handler = $this->loadTemplateResourceHandler($resource_type);
394 $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
396 // If ($mtime > $this->getCachedTimestamp()) {
397 If ($mtime > $_file_to_check[1]) {
398 $this->tpl_vars = array();
399 $this->rendered_content = null;
400 return $this->isCached;
404 $this->isCached = true;
408 return $this->isCached;
412 * Render the output using the compiled template or the PHP template source
414 * The rendering process is accomplished by just including the PHP files.
415 * The only exceptions are evaluated templates (string template). Their code has
418 public function renderTemplate ()
420 if ($this->resource_object->usesCompiler) {
421 if ($this->mustCompile() && $this->compiled_template === null) {
422 $this->compileTemplateSource();
424 if ($this->smarty->debugging) {
425 Smarty_Internal_Debug::start_render($this);
427 $_smarty_tpl = $this;
429 if ($this->resource_object->isEvaluated) {
430 eval("?>" . $this->compiled_template);
432 include($this->getCompiledFilepath ());
433 // check file dependencies at compiled code
434 if ($this->smarty->compile_check) {
435 if (!empty($this->properties['file_dependency'])) {
436 $this->mustCompile = false;
437 $resource_type = null;
438 $resource_name = null;
439 foreach ($this->properties['file_dependency'] as $_file_to_check) {
440 If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
441 $mtime = filemtime($_file_to_check[0]);
443 $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
444 $resource_handler = $this->loadTemplateResourceHandler($resource_type);
445 $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
447 // If ($mtime != $_file_to_check[1]) {
448 If ($mtime > $_file_to_check[1]) {
449 $this->mustCompile = true;
453 if ($this->mustCompile) {
454 // recompile and render again
456 $this->compileTemplateSource();
458 include($this->getCompiledFilepath ());
464 if (is_callable(array($this->resource_object, 'renderUncompiled'))) {
465 if ($this->smarty->debugging) {
466 Smarty_Internal_Debug::start_render($this);
469 $this->resource_object->renderUncompiled($this);
471 throw new SmartyException("Resource '$this->resource_type' must have 'renderUncompiled' methode");
474 $this->rendered_content = ob_get_clean();
475 if (!$this->resource_object->isEvaluated && empty($this->properties['file_dependency'][$this->templateUid])) {
476 $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type);
478 if ($this->parent instanceof Smarty_Internal_Template) {
479 $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']);
480 foreach($this->required_plugins as $code => $tmp1) {
481 foreach($tmp1 as $name => $tmp) {
482 foreach($tmp as $type => $data) {
483 $this->parent->required_plugins[$code][$name][$type] = $data;
488 if ($this->smarty->debugging) {
489 Smarty_Internal_Debug::end_render($this);
491 // write to cache when nessecary
492 if (!$this->resource_object->isEvaluated && ($this->caching == Smarty::CACHING_LIFETIME_SAVED || $this->caching == Smarty::CACHING_LIFETIME_CURRENT)) {
493 if ($this->smarty->debugging) {
494 Smarty_Internal_Debug::start_cache($this);
496 $this->properties['has_nocache_code'] = false;
497 // get text between non-cached items
498 $cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content);
499 // get non-cached items
500 preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content, $cache_parts);
502 // loop over items, stitch back together
503 foreach($cache_split as $curr_idx => $curr_split) {
504 // escape PHP tags in template content
505 $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php echo \'$1\'; ?>', $curr_split);
506 if (isset($cache_parts[0][$curr_idx])) {
507 $this->properties['has_nocache_code'] = true;
508 // remove nocache tags from cache output
509 $output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);
512 if (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output'])) {
513 $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $this);
515 // rendering (must be done before writing cache file because of {function} nocache handling)
516 $_smarty_tpl = $this;
518 eval("?>" . $output);
519 $this->rendered_content = ob_get_clean();
520 // write cache file content
521 $this->writeCachedContent('<?php if (!$no_render) {?>'. $output. '<?php } ?>');
522 if ($this->smarty->debugging) {
523 Smarty_Internal_Debug::end_cache($this);
526 // var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
527 if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
528 // replace nocache_hash
529 $this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
530 $this->parent->has_nocache_code = $this->has_nocache_code;
536 * Returns the rendered HTML output
538 * If the cache is valid the cached content is used, otherwise
539 * the output is rendered from the compiled template or PHP template source
541 * @return string rendered HTML output
543 public function getRenderedTemplate ()
545 // disable caching for evaluated code
546 if ($this->resource_object->isEvaluated) {
547 $this->caching = false;
549 // checks if template exists
550 $this->isExisting(true);
551 // read from cache or render
552 if ($this->rendered_content === null) {
553 if ($this->isCached) {
554 if ($this->smarty->debugging) {
555 Smarty_Internal_Debug::start_cache($this);
557 $this->rendered_content = $this->cache_resource_object->getCachedContents($this, false);
558 if ($this->smarty->debugging) {
559 Smarty_Internal_Debug::end_cache($this);
562 if ($this->isCached === null) {
563 $this->isCached(false);
565 if (!$this->isCached) {
566 // render template (not loaded and not in cache)
567 $this->renderTemplate();
570 $this->updateParentVariables();
571 $this->isCached = null;
572 return $this->rendered_content;
576 * Parse a template resource in its name and type
577 * Load required resource handler
579 * @param string $template_resource template resource specification
580 * @param string $resource_type return resource type
581 * @param string $resource_name return resource name
582 * @param object $resource_handler return resource handler object
584 public function parseResourceName($template_resource, &$resource_type, &$resource_name, &$resource_handler)
586 if (empty($template_resource))
588 $this->getResourceTypeName($template_resource, $resource_type, $resource_name);
589 $resource_handler = $this->loadTemplateResourceHandler($resource_type);
590 // cache template object under a unique ID
591 // do not cache eval resources
592 if ($resource_type != 'eval') {
593 $this->smarty->template_objects[sha1($this->template_resource . $this->cache_id . $this->compile_id)] = $this;
599 * get system filepath to template
601 public function buildTemplateFilepath ($file = null)
604 $file = $this->resource_name;
606 // relative file name?
607 if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {
608 foreach((array)$this->smarty->template_dir as $_template_dir) {
609 if (strpos('/\\', substr($_template_dir, -1)) === false) {
610 $_template_dir .= DS;
612 $_filepath = $_template_dir . $file;
613 if (file_exists($_filepath)) {
616 if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_template_dir)) {
617 // try PHP include_path
618 if (($_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath)) !== false) {
624 // try absolute filepath
625 if (file_exists($file)) return $file;
627 if (!empty($this->smarty->default_template_handler_func)) {
628 if (!is_callable($this->smarty->default_template_handler_func)) {
629 throw new SmartyException("Default template handler not callable");
631 $_return = call_user_func_array($this->smarty->default_template_handler_func,
632 array($this->resource_type, $this->resource_name, &$this->template_source, &$this->template_timestamp, $this));
633 if (is_string($_return)) {
635 } elseif ($_return === true) {
644 * Update Smarty variables in other scopes
646 public function updateParentVariables ($scope = Smarty::SCOPE_LOCAL)
649 foreach ($this->tpl_vars as $_key => $_variable) {
650 $_variable_scope = $this->tpl_vars[$_key]->scope;
651 if ($scope == Smarty::SCOPE_LOCAL && $_variable_scope == Smarty::SCOPE_LOCAL) {
654 if (isset($this->parent) && ($scope == Smarty::SCOPE_PARENT || $_variable_scope == Smarty::SCOPE_PARENT)) {
655 if (isset($this->parent->tpl_vars[$_key])) {
656 // variable is already defined in parent, copy value
657 $this->parent->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
659 // create variable in parent
660 $this->parent->tpl_vars[$_key] = clone $_variable;
661 $this->parent->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
664 if ($scope == Smarty::SCOPE_ROOT || $_variable_scope == Smarty::SCOPE_ROOT) {
665 if ($this->parent == null) {
671 while ($root_ptr->parent != null) {
672 $root_ptr = $root_ptr->parent;
676 if (isset($root_ptr->tpl_vars[$_key])) {
677 // variable is already defined in root, copy value
678 $root_ptr->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
680 // create variable in root
681 $root_ptr->tpl_vars[$_key] = clone $_variable;
682 $root_ptr->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
685 if ($scope == Smarty::SCOPE_GLOBAL || $_variable_scope == Smarty::SCOPE_GLOBAL) {
686 if (isset(Smarty::$global_tpl_vars[$_key])) {
687 // variable is already defined in root, copy value
688 Smarty::$global_tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
690 // create global variable
691 Smarty::$global_tpl_vars[$_key] = clone $_variable;
693 Smarty::$global_tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
699 * Split a template resource in its name and type
701 * @param string $template_resource template resource specification
702 * @param string $resource_type return resource type
703 * @param string $resource_name return resource name
705 protected function getResourceTypeName ($template_resource, &$resource_type, &$resource_name)
707 if (strpos($template_resource, ':') === false) {
708 // no resource given, use default
709 $resource_type = $this->smarty->default_resource_type;
710 $resource_name = $template_resource;
712 // get type and name from path
713 list($resource_type, $resource_name) = explode(':', $template_resource, 2);
714 if (strlen($resource_type) == 1) {
715 // 1 char is not resource type, but part of filepath
716 $resource_type = 'file';
717 $resource_name = $template_resource;
723 * Load template resource handler by type
725 * @param string $resource_type template resource type
726 * @return object resource handler object
728 protected function loadTemplateResourceHandler ($resource_type)
730 // try registered resource
731 if (isset($this->smarty->registered_resources[$resource_type])) {
732 return new Smarty_Internal_Resource_Registered($this);
734 // try sysplugins dir
735 if (in_array($resource_type, array('file', 'string', 'extends', 'php', 'stream', 'eval'))) {
736 $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($resource_type);
737 return new $_resource_class($this->smarty);
740 $_resource_class = 'Smarty_Resource_' . ucfirst($resource_type);
741 if ($this->smarty->loadPlugin($_resource_class)) {
742 if (class_exists($_resource_class, false)) {
743 return new $_resource_class($this->smarty);
745 return new Smarty_Internal_Resource_Registered($this, $resource_type);
749 $_known_stream = stream_get_wrappers();
750 if (in_array($resource_type, $_known_stream)) {
752 if (is_object($this->smarty->security_policy)) {
753 $this->smarty->security_policy->isTrustedStream($resource_type);
755 return new Smarty_Internal_Resource_Stream($this->smarty);
757 throw new SmartyException('Unkown resource type \'' . $resource_type . '\'');
765 * Create property header
767 public function createPropertyHeader ($cache = false)
769 $plugins_string = '';
770 // include code for plugins
772 if (!empty($this->required_plugins['compiled'])) {
773 $plugins_string = '<?php ';
774 foreach($this->required_plugins['compiled'] as $tmp) {
775 foreach($tmp as $data) {
776 $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n";
779 $plugins_string .= '?>';
781 if (!empty($this->required_plugins['nocache'])) {
782 $this->has_nocache_code = true;
783 $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php ";
784 foreach($this->required_plugins['nocache'] as $tmp) {
785 foreach($tmp as $data) {
786 $plugins_string .= "if (!is_callable(\'{$data['function']}\')) include \'{$data['file']}\';\n";
789 $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
792 // build property code
793 $this->properties['has_nocache_code'] = $this->has_nocache_code;
794 $properties_string = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/" ;
795 if ($this->smarty->direct_access_security) {
796 $properties_string .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n";
799 // remove compiled code of{function} definition
800 unset($this->properties['function']);
801 if (!empty($this->smarty->template_functions)) {
802 // copy code of {function} tags called in nocache mode
803 foreach ($this->smarty->template_functions as $name => $function_data) {
804 if (isset($function_data['called_nocache'])) {
805 unset($function_data['called_nocache'], $this->smarty->template_functions[$name]['called_nocache']);
806 $this->properties['function'][$name] = $function_data;
811 $properties_string .= "\$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n";
812 return $properties_string . $plugins_string;
816 * Decode saved properties from compiled template and cache files
818 public function decodeProperties ($properties)
820 $this->has_nocache_code = $properties['has_nocache_code'];
821 $this->properties['nocache_hash'] = $properties['nocache_hash'];
822 if (isset($properties['cache_lifetime'])) {
823 $this->properties['cache_lifetime'] = $properties['cache_lifetime'];
825 if (isset($properties['file_dependency'])) {
826 $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
828 if (!empty($properties['function'])) {
829 $this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
830 $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
835 * creates a local Smarty variable for array assignments
837 public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL)
839 if (!isset($this->tpl_vars[$tpl_var])) {
840 $tpl_var_inst = $this->getVariable($tpl_var, null, true, false);
841 if ($tpl_var_inst instanceof Undefined_Smarty_Variable) {
842 $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope);
844 $this->tpl_vars[$tpl_var] = clone $tpl_var_inst;
845 if ($scope != Smarty::SCOPE_LOCAL) {
846 $this->tpl_vars[$tpl_var]->scope = $scope;
850 if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) {
851 settype($this->tpl_vars[$tpl_var]->value, 'array');
856 * [util function] counts an array, arrayaccess/traversable or PDOStatement object
857 * @param mixed $value
858 * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 for empty elements
860 public function _count($value)
862 if (is_array($value) === true || $value instanceof Countable) {
863 return count($value);
864 } elseif ($value instanceof Iterator) {
866 if ($value->valid()) {
867 return iterator_count($value);
869 } elseif ($value instanceof PDOStatement) {
870 return $value->rowCount();
871 } elseif ($value instanceof Traversable) {
872 return iterator_count($value);
873 } elseif ($value instanceof ArrayAccess) {
874 if ($value->offsetExists(0)) {
877 } elseif (is_object($value)) {
878 return count($value);
886 public function fetch ($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false)
888 if ($template == null) {
889 return $this->smarty->fetch($this);
891 if (!isset($parent)) {
894 return $this->smarty->fetch($template, $cache_id, $compile_id, $parent, $display);
900 * wrapper for display
902 public function display ($template = null, $cache_id = null, $compile_id = null, $parent = null)
904 if ($template == null) {
905 return $this->smarty->display($this);
907 if (!isset($parent)) {
910 return $this->smarty->display($template, $cache_id, $compile_id, $parent);
916 * set Smarty property in template context
917 * @param string $property_name property name
918 * @param mixed $value value
920 public function __set($property_name, $value)
922 if ($property_name == 'resource_object' || $property_name == 'cache_resource_object') {
923 $this->$property_name = $value;
924 } elseif (property_exists($this->smarty, $property_name)) {
925 $this->smarty->$property_name = $value;
927 throw new SmartyException("invalid template property '$property_name'.");
932 * get Smarty property in template context
933 * @param string $property_name property name
935 public function __get($property_name)
937 if ($property_name == 'resource_object') {
938 // load template resource
939 $this->resource_object = null;
940 if (!$this->parseResourceName ($this->template_resource, $this->resource_type, $this->resource_name, $this->resource_object)) {
941 throw new SmartyException ("Unable to parse resource name \"{$template_resource}\"");
943 return $this->resource_object;
945 if ($property_name == 'cache_resource_object') {
946 // load cache resource
947 $this->cache_resource_object = $this->loadCacheResource();
948 return $this->cache_resource_object;
950 if (property_exists($this->smarty, $property_name)) {
951 return $this->smarty->$property_name;
953 throw new SmartyException("template property '$property_name' does not exist.");
959 * Takes unknown class methods and lazy loads sysplugin files for them
960 * class name format: Smarty_Method_MethodName
961 * plugin filename format: method.methodname.php
963 * @param string $name unknown methode name
964 * @param array $args aurgument array
966 public function __call($name, $args)
969 if (!isset($camel_func))
970 $camel_func = create_function('$c', 'return "_" . strtolower($c[1]);');
971 // see if this is a set/get for a property
972 $first3 = strtolower(substr($name, 0, 3));
973 if (in_array($first3, array('set', 'get')) && substr($name, 3, 1) !== '_') {
974 // try to keep case correct for future PHP 6.0 case-sensitive class methods
975 // lcfirst() not available < PHP 5.3.0, so improvise
976 $property_name = strtolower(substr($name, 3, 1)) . substr($name, 4);
977 // convert camel case to underscored name
978 $property_name = preg_replace_callback('/([A-Z])/', $camel_func, $property_name);
979 if (property_exists($this, $property_name)) {
980 if ($first3 == 'get')
981 return $this->$property_name;
983 return $this->$property_name = $args[0];
986 // Smarty Backward Compatible wrapper
987 if (strpos($name,'_') !== false) {
988 if (!isset($this->wrapper)) {
989 $this->wrapper = new Smarty_Internal_Wrapper($this);
991 return $this->wrapper->convert($name, $args);
993 // pass call to Smarty object
994 return call_user_func_array(array($this->smarty,$name),$args);