]> git.mxchange.org Git - friendica.git/blob - library/Smarty/libs/sysplugins/smarty_internal_template.php
Merge remote branch 'upstream/master'
[friendica.git] / library / Smarty / libs / sysplugins / smarty_internal_template.php
1 <?php
2 /**
3  * Smarty Internal Plugin Template
4  *
5  * This file contains the Smarty template engine
6  *
7  * @package Smarty
8  * @subpackage Template
9  * @author Uwe Tews
10  */
11
12 /**
13  * Main class with template data structures and methods
14  *
15  * @package Smarty
16  * @subpackage Template
17  *
18  * @property Smarty_Template_Source   $source
19  * @property Smarty_Template_Compiled $compiled
20  * @property Smarty_Template_Cached   $cached
21  */
22 class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
23
24     /**
25      * cache_id
26      * @var string
27      */
28     public $cache_id = null;
29     /**
30      * $compile_id
31      * @var string
32      */
33     public $compile_id = null;
34     /**
35      * caching enabled
36      * @var boolean
37      */
38     public $caching = null;
39     /**
40      * cache lifetime in seconds
41      * @var integer
42      */
43     public $cache_lifetime = null;
44     /**
45      * Template resource
46      * @var string
47      */
48     public $template_resource = null;
49     /**
50      * flag if compiled template is invalid and must be (re)compiled
51      * @var bool
52      */
53     public $mustCompile = null;
54     /**
55      * flag if template does contain nocache code sections
56      * @var bool
57      */
58     public $has_nocache_code = false;
59     /**
60      * special compiled and cached template properties
61      * @var array
62      */
63     public $properties = array('file_dependency' => array(),
64         'nocache_hash' => '',
65         'function' => array());
66     /**
67      * required plugins
68      * @var array
69      */
70     public $required_plugins = array('compiled' => array(), 'nocache' => array());
71     /**
72      * Global smarty instance
73      * @var Smarty
74      */
75     public $smarty = null;
76     /**
77      * blocks for template inheritance
78      * @var array
79      */
80     public $block_data = array();
81     /**
82      * variable filters
83      * @var array
84      */
85     public $variable_filters = array();
86     /**
87      * optional log of tag/attributes
88      * @var array
89      */
90     public $used_tags = array();
91     /**
92      * internal flag to allow relative path in child template blocks
93      * @var bool
94      */
95     public $allow_relative_path = false;
96     /**
97      * internal capture runtime stack
98      * @var array
99      */
100     public $_capture_stack = array(0 => array());
101
102     /**
103      * Create template data object
104      *
105      * Some of the global Smarty settings copied to template scope
106      * It load the required template resources and cacher plugins
107      *
108      * @param string                   $template_resource template resource string
109      * @param Smarty                   $smarty            Smarty instance
110      * @param Smarty_Internal_Template $_parent           back pointer to parent object with variables or null
111      * @param mixed                    $_cache_id cache   id or null
112      * @param mixed                    $_compile_id       compile id or null
113      * @param bool                     $_caching          use caching?
114      * @param int                      $_cache_lifetime   cache life-time in seconds
115      */
116     public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null)
117     {
118         $this->smarty = &$smarty;
119         // Smarty parameter
120         $this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id;
121         $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id;
122         $this->caching = $_caching === null ? $this->smarty->caching : $_caching;
123         if ($this->caching === true)
124             $this->caching = Smarty::CACHING_LIFETIME_CURRENT;
125         $this->cache_lifetime = $_cache_lifetime === null ? $this->smarty->cache_lifetime : $_cache_lifetime;
126         $this->parent = $_parent;
127         // Template resource
128         $this->template_resource = $template_resource;
129         // copy block data of template inheritance
130         if ($this->parent instanceof Smarty_Internal_Template) {
131             $this->block_data = $this->parent->block_data;
132         }
133     }
134
135     /**
136      * Returns if the current template must be compiled by the Smarty compiler
137      *
138      * It does compare the timestamps of template source and the compiled templates and checks the force compile configuration
139      *
140      * @return boolean true if the template must be compiled
141      */
142     public function mustCompile()
143     {
144         if (!$this->source->exists) {
145             if ($this->parent instanceof Smarty_Internal_Template) {
146                 $parent_resource = " in '$this->parent->template_resource}'";
147             } else {
148                 $parent_resource = '';
149             }
150             throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'{$parent_resource}");
151         }
152         if ($this->mustCompile === null) {
153             $this->mustCompile = (!$this->source->uncompiled && ($this->smarty->force_compile || $this->source->recompiled || $this->compiled->timestamp === false ||
154                     ($this->smarty->compile_check && $this->compiled->timestamp < $this->source->timestamp)));
155         }
156         return $this->mustCompile;
157     }
158
159     /**
160      * Compiles the template
161      *
162      * If the template is not evaluated the compiled template is saved on disk
163      */
164     public function compileTemplateSource()
165     {
166         if (!$this->source->recompiled) {
167             $this->properties['file_dependency'] = array();
168             if ($this->source->components) {
169                 // uses real resource for file dependency
170                 $source = end($this->source->components);
171                 $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $source->type);
172             } else {
173                 $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type);
174             }
175         }
176         if ($this->smarty->debugging) {
177             Smarty_Internal_Debug::start_compile($this);
178         }
179         // compile locking
180         if ($this->smarty->compile_locking && !$this->source->recompiled) {
181             if ($saved_timestamp = $this->compiled->timestamp) {
182                 touch($this->compiled->filepath);
183             }
184         }
185         // call compiler
186         try {
187             $code = $this->compiler->compileTemplate($this);
188         } catch (Exception $e) {
189             // restore old timestamp in case of error
190             if ($this->smarty->compile_locking && !$this->source->recompiled && $saved_timestamp) {
191                 touch($this->compiled->filepath, $saved_timestamp);
192             }
193             throw $e;
194         }
195         // compiling succeded
196         if (!$this->source->recompiled && $this->compiler->write_compiled_code) {
197             // write compiled template
198             $_filepath = $this->compiled->filepath;
199             if ($_filepath === false)
200                 throw new SmartyException('getCompiledFilepath() did not return a destination to save the compiled template to');
201             Smarty_Internal_Write_File::writeFile($_filepath, $code, $this->smarty);
202             $this->compiled->exists = true;
203             $this->compiled->isCompiled = true;
204         }
205         if ($this->smarty->debugging) {
206             Smarty_Internal_Debug::end_compile($this);
207         }
208         // release compiler object to free memory
209         unset($this->compiler);
210     }
211
212     /**
213      * Writes the cached template output
214      *
215      * @return bool
216      */
217     public function writeCachedContent($content)
218     {
219         if ($this->source->recompiled || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) {
220             // don't write cache file
221             return false;
222         }
223         $this->properties['cache_lifetime'] = $this->cache_lifetime;
224         $this->properties['unifunc'] = 'content_' . str_replace('.', '_', uniqid('', true));
225         $content = $this->createTemplateCodeFrame($content, true);
226         $_smarty_tpl = $this;
227         eval("?>" . $content);
228         $this->cached->valid = true;
229         $this->cached->processed = true;
230         return $this->cached->write($this, $content);
231     }
232
233     /**
234      * Template code runtime function to get subtemplate content
235      *
236      * @param string  $template       the resource handle of the template file
237      * @param mixed   $cache_id       cache id to be used with this template
238      * @param mixed   $compile_id     compile id to be used with this template
239      * @param integer $caching        cache mode
240      * @param integer $cache_lifetime life time of cache data
241      * @param array   $vars optional  variables to assign
242      * @param int     $parent_scope   scope in which {include} should execute
243      * @returns string template content
244      */
245     public function getSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope)
246     {
247         // already in template cache?
248         if ($this->smarty->allow_ambiguous_resources) {
249             $_templateId = Smarty_Resource::getUniqueTemplateName($this->smarty, $template) . $cache_id . $compile_id;
250         } else {
251             $_templateId = $this->smarty->joined_template_dir . '#' . $template . $cache_id . $compile_id;
252         }
253
254         if (isset($_templateId[150])) {
255             $_templateId = sha1($_templateId);
256         }
257         if (isset($this->smarty->template_objects[$_templateId])) {
258             // clone cached template object because of possible recursive call
259             $tpl = clone $this->smarty->template_objects[$_templateId];
260             $tpl->parent = $this;
261             $tpl->caching = $caching;
262             $tpl->cache_lifetime = $cache_lifetime;
263         } else {
264             $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime);
265         }
266         // get variables from calling scope
267         if ($parent_scope == Smarty::SCOPE_LOCAL) {
268             $tpl->tpl_vars = $this->tpl_vars;
269             $tpl->tpl_vars['smarty'] = clone $this->tpl_vars['smarty'];
270         } elseif ($parent_scope == Smarty::SCOPE_PARENT) {
271             $tpl->tpl_vars = &$this->tpl_vars;
272         } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) {
273             $tpl->tpl_vars = &Smarty::$global_tpl_vars;
274         } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) {
275             $tpl->tpl_vars = &$this->tpl_vars;
276         } else {
277             $tpl->tpl_vars = &$scope_ptr->tpl_vars;
278         }
279         $tpl->config_vars = $this->config_vars;
280         if (!empty($data)) {
281             // set up variable values
282             foreach ($data as $_key => $_val) {
283                 $tpl->tpl_vars[$_key] = new Smarty_variable($_val);
284             }
285         }
286         return $tpl->fetch(null, null, null, null, false, false, true);
287     }
288
289     /**
290      * Template code runtime function to set up an inline subtemplate
291      *
292      * @param string  $template       the resource handle of the template file
293      * @param mixed   $cache_id       cache id to be used with this template
294      * @param mixed   $compile_id     compile id to be used with this template
295      * @param integer $caching        cache mode
296      * @param integer $cache_lifetime life time of cache data
297      * @param array   $vars optional  variables to assign
298      * @param int     $parent_scope   scope in which {include} should execute
299      * @param string  $hash           nocache hash code
300      * @returns string template content
301      */
302     public function setupInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash)
303     {
304         $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime);
305         $tpl->properties['nocache_hash']  = $hash;
306         // get variables from calling scope
307         if ($parent_scope == Smarty::SCOPE_LOCAL ) {
308             $tpl->tpl_vars = $this->tpl_vars;
309             $tpl->tpl_vars['smarty'] = clone $this->tpl_vars['smarty'];
310         } elseif ($parent_scope == Smarty::SCOPE_PARENT) {
311             $tpl->tpl_vars = &$this->tpl_vars;
312         } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) {
313             $tpl->tpl_vars = &Smarty::$global_tpl_vars;
314         } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) {
315             $tpl->tpl_vars = &$this->tpl_vars;
316         } else {
317             $tpl->tpl_vars = &$scope_ptr->tpl_vars;
318         }
319         $tpl->config_vars = $this->config_vars;
320         if (!empty($data)) {
321             // set up variable values
322             foreach ($data as $_key => $_val) {
323                 $tpl->tpl_vars[$_key] = new Smarty_variable($_val);
324             }
325         }
326         return $tpl;
327     }
328
329
330     /**
331      * Create code frame for compiled and cached templates
332      *
333      * @param string $content   optional template content
334      * @param bool   $cache     flag for cache file
335      * @return string
336      */
337     public function createTemplateCodeFrame($content = '', $cache = false)
338     {
339         $plugins_string = '';
340         // include code for plugins
341         if (!$cache) {
342             if (!empty($this->required_plugins['compiled'])) {
343                 $plugins_string = '<?php ';
344                 foreach ($this->required_plugins['compiled'] as $tmp) {
345                     foreach ($tmp as $data) {
346                         $file = addslashes($data['file']);
347                         $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$file}';\n";
348                     }
349                 }
350                 $plugins_string .= '?>';
351             }
352             if (!empty($this->required_plugins['nocache'])) {
353                 $this->has_nocache_code = true;
354                 $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php \$_smarty = \$_smarty_tpl->smarty; ";
355                 foreach ($this->required_plugins['nocache'] as $tmp) {
356                     foreach ($tmp as $data) {
357                         $file = addslashes($data['file']);
358                         $plugins_string .= addslashes("if (!is_callable('{$data['function']}')) include '{$file}';\n");
359                     }
360                 }
361                 $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
362             }
363         }
364         // build property code
365         $this->properties['has_nocache_code'] = $this->has_nocache_code;
366         $output = '';
367         if (!$this->source->recompiled) {
368             $output = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/";
369             if ($this->smarty->direct_access_security) {
370                 $output .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n";
371             }
372         }
373         if ($cache) {
374             // remove compiled code of{function} definition
375             unset($this->properties['function']);
376             if (!empty($this->smarty->template_functions)) {
377                 // copy code of {function} tags called in nocache mode
378                 foreach ($this->smarty->template_functions as $name => $function_data) {
379                     if (isset($function_data['called_nocache'])) {
380                         foreach ($function_data['called_functions'] as $func_name) {
381                             $this->smarty->template_functions[$func_name]['called_nocache'] = true;
382                         }
383                     }
384                 }
385                  foreach ($this->smarty->template_functions as $name => $function_data) {
386                     if (isset($function_data['called_nocache'])) {
387                         unset($function_data['called_nocache'], $function_data['called_functions'], $this->smarty->template_functions[$name]['called_nocache']);
388                         $this->properties['function'][$name] = $function_data;
389                     }
390                 }
391             }
392         }
393         $this->properties['version'] = Smarty::SMARTY_VERSION;
394         if (!isset($this->properties['unifunc'])) {
395             $this->properties['unifunc'] = 'content_' . str_replace('.', '_', uniqid('', true));
396         }
397         if (!$this->source->recompiled) {
398             $output .= "\$_valid = \$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . ',' . ($cache ? 'true' : 'false') . "); /*/%%SmartyHeaderCode%%*/?>\n";
399             $output .= '<?php if ($_valid && !is_callable(\'' . $this->properties['unifunc'] . '\')) {function ' . $this->properties['unifunc'] . '($_smarty_tpl) {?>';
400         }
401         $output .= $plugins_string;
402         $output .= $content;
403         if (!$this->source->recompiled) {
404             $output .= '<?php }} ?>';
405         }
406         return $output;
407     }
408
409     /**
410      * This function is executed automatically when a compiled or cached template file is included
411      *
412      * - Decode saved properties from compiled template and cache files
413      * - Check if compiled or cache file is valid
414      *
415      * @param array $properties     special template properties
416      * @param bool  $cache          flag if called from cache file
417      * @return bool                 flag if compiled or cache file is valid
418      */
419     public function decodeProperties($properties, $cache = false)
420     {
421         $this->has_nocache_code = $properties['has_nocache_code'];
422         $this->properties['nocache_hash'] = $properties['nocache_hash'];
423         if (isset($properties['cache_lifetime'])) {
424             $this->properties['cache_lifetime'] = $properties['cache_lifetime'];
425         }
426         if (isset($properties['file_dependency'])) {
427             $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
428         }
429         if (!empty($properties['function'])) {
430             $this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
431             $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
432         }
433         $this->properties['version'] = (isset($properties['version'])) ? $properties['version'] : '';
434         $this->properties['unifunc'] = $properties['unifunc'];
435         // check file dependencies at compiled code
436         $is_valid = true;
437         if ($this->properties['version'] != Smarty::SMARTY_VERSION) {
438             $is_valid = false;
439         } else if (((!$cache && $this->smarty->compile_check && empty($this->compiled->_properties) && !$this->compiled->isCompiled) || $cache && ($this->smarty->compile_check === true || $this->smarty->compile_check === Smarty::COMPILECHECK_ON)) && !empty($this->properties['file_dependency'])) {
440             foreach ($this->properties['file_dependency'] as $_file_to_check) {
441                 if ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'php') {
442                     if ($this->source->filepath == $_file_to_check[0] && isset($this->source->timestamp)) {
443                         // do not recheck current template
444                         $mtime = $this->source->timestamp;
445                     } else {
446                         // file and php types can be checked without loading the respective resource handlers
447                         $mtime = @filemtime($_file_to_check[0]);
448                     }
449                 } elseif ($_file_to_check[2] == 'string') {
450                     continue;
451                 } else {
452                     $source = Smarty_Resource::source(null, $this->smarty, $_file_to_check[0]);
453                     $mtime = $source->timestamp;
454                 }
455                 if (!$mtime || $mtime > $_file_to_check[1]) {
456                     $is_valid = false;
457                     break;
458                 }
459             }
460         }
461         if ($cache) {
462             $this->cached->valid = $is_valid;
463         } else {
464             $this->mustCompile = !$is_valid;
465         }
466         // store data in reusable Smarty_Template_Compiled
467         if (!$cache) {
468             $this->compiled->_properties = $properties;
469         }
470         return $is_valid;
471     }
472
473     /**
474      * Template code runtime function to create a local Smarty variable for array assignments
475      *
476      * @param string $tpl_var   tempate variable name
477      * @param bool   $nocache   cache mode of variable
478      * @param int    $scope     scope of variable
479      */
480     public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL)
481     {
482         if (!isset($this->tpl_vars[$tpl_var])) {
483             $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope);
484         } else {
485             $this->tpl_vars[$tpl_var] = clone $this->tpl_vars[$tpl_var];
486             if ($scope != Smarty::SCOPE_LOCAL) {
487                 $this->tpl_vars[$tpl_var]->scope = $scope;
488             }
489             if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) {
490                 settype($this->tpl_vars[$tpl_var]->value, 'array');
491             }
492         }
493     }
494
495     /**
496      * Template code runtime function to get pointer to template variable array of requested scope
497      *
498      * @param int $scope    requested variable scope
499      * @return array        array of template variables
500      */
501     public function &getScope($scope)
502     {
503         if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) {
504             return $this->parent->tpl_vars;
505         } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) {
506             $ptr = $this->parent;
507             while (!empty($ptr->parent)) {
508                 $ptr = $ptr->parent;
509             }
510             return $ptr->tpl_vars;
511         } elseif ($scope == Smarty::SCOPE_GLOBAL) {
512             return Smarty::$global_tpl_vars;
513         }
514         $null = null;
515         return $null;
516     }
517
518     /**
519      * Get parent or root of template parent chain
520      *
521      * @param int $scope    pqrent or root scope
522      * @return mixed object
523      */
524     public function getScopePointer($scope)
525     {
526         if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) {
527             return $this->parent;
528         } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) {
529             $ptr = $this->parent;
530             while (!empty($ptr->parent)) {
531                 $ptr = $ptr->parent;
532             }
533             return $ptr;
534         }
535         return null;
536     }
537
538     /**
539      * [util function] counts an array, arrayaccess/traversable or PDOStatement object
540      *
541      * @param mixed $value
542      * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 for empty elements
543      */
544     public function _count($value)
545     {
546         if (is_array($value) === true || $value instanceof Countable) {
547             return count($value);
548         } elseif ($value instanceof IteratorAggregate) {
549             // Note: getIterator() returns a Traversable, not an Iterator
550             // thus rewind() and valid() methods may not be present
551             return iterator_count($value->getIterator());
552         } elseif ($value instanceof Iterator) {
553             return iterator_count($value);
554         } elseif ($value instanceof PDOStatement) {
555             return $value->rowCount();
556         } elseif ($value instanceof Traversable) {
557             return iterator_count($value);
558         } elseif ($value instanceof ArrayAccess) {
559             if ($value->offsetExists(0)) {
560                 return 1;
561             }
562         } elseif (is_object($value)) {
563             return count($value);
564         }
565         return 0;
566     }
567
568     /**
569      * runtime error not matching capture tags
570      *
571      */
572     public function capture_error()
573     {
574         throw new SmartyException("Not matching {capture} open/close in \"{$this->template_resource}\"");
575     }
576
577     /**
578     * Empty cache for this template
579     *
580     * @param integer $exp_time      expiration time
581     * @return integer number of cache files deleted
582     */
583     public function clearCache($exp_time=null)
584     {
585         Smarty_CacheResource::invalidLoadedCache($this->smarty);
586         return $this->cached->handler->clear($this->smarty, $this->template_name, $this->cache_id, $this->compile_id, $exp_time);
587     }
588
589      /**
590      * set Smarty property in template context
591      *
592      * @param string $property_name property name
593      * @param mixed  $value         value
594      */
595     public function __set($property_name, $value)
596     {
597         switch ($property_name) {
598             case 'source':
599             case 'compiled':
600             case 'cached':
601             case 'compiler':
602                 $this->$property_name = $value;
603                 return;
604
605             // FIXME: routing of template -> smarty attributes
606             default:
607                 if (property_exists($this->smarty, $property_name)) {
608                     $this->smarty->$property_name = $value;
609                     return;
610                 }
611         }
612
613         throw new SmartyException("invalid template property '$property_name'.");
614     }
615
616     /**
617      * get Smarty property in template context
618      *
619      * @param string $property_name property name
620      */
621     public function __get($property_name)
622     {
623         switch ($property_name) {
624             case 'source':
625                 if (strlen($this->template_resource) == 0) {
626                     throw new SmartyException('Missing template name');
627                 }
628                 $this->source = Smarty_Resource::source($this);
629                 // cache template object under a unique ID
630                 // do not cache eval resources
631                 if ($this->source->type != 'eval') {
632                     if ($this->smarty->allow_ambiguous_resources) {
633                         $_templateId = $this->source->unique_resource . $this->cache_id . $this->compile_id;
634                     } else {
635                         $_templateId = $this->smarty->joined_template_dir . '#' . $this->template_resource . $this->cache_id . $this->compile_id;
636                     }
637
638                     if (isset($_templateId[150])) {
639                         $_templateId = sha1($_templateId);
640                     }
641                     $this->smarty->template_objects[$_templateId] = $this;
642                 }
643                 return $this->source;
644
645             case 'compiled':
646                 $this->compiled = $this->source->getCompiled($this);
647                 return $this->compiled;
648
649             case 'cached':
650                 if (!class_exists('Smarty_Template_Cached')) {
651                     include SMARTY_SYSPLUGINS_DIR . 'smarty_cacheresource.php';
652                 }
653                 $this->cached = new Smarty_Template_Cached($this);
654                 return $this->cached;
655
656             case 'compiler':
657                 $this->smarty->loadPlugin($this->source->compiler_class);
658                 $this->compiler = new $this->source->compiler_class($this->source->template_lexer_class, $this->source->template_parser_class, $this->smarty);
659                 return $this->compiler;
660
661             // FIXME: routing of template -> smarty attributes
662             default:
663                 if (property_exists($this->smarty, $property_name)) {
664                     return $this->smarty->$property_name;
665                 }
666         }
667
668         throw new SmartyException("template property '$property_name' does not exist.");
669     }
670
671     /**
672      * Template data object destrutor
673      *
674      */
675     public function __destruct()
676     {
677         if ($this->smarty->cache_locking && isset($this->cached) && $this->cached->is_locked) {
678             $this->cached->handler->releaseLock($this->smarty, $this->cached);
679         }
680     }
681
682 }
683
684 ?>