Initial repo created
[timetracker.git] / WEB-INF / lib / smarty / sysplugins / smarty_internal_template.php
1 <?php
2
3 /**
4  * Smarty Internal Plugin Template
5  * 
6  * This file contains the Smarty template engine
7  * 
8  * @package Smarty
9  * @subpackage Templates
10  * @author Uwe Tews 
11  */
12
13 /**
14  * Main class with template data structures and methods
15  */
16 class Smarty_Internal_Template extends Smarty_Internal_Data {
17     // object cache
18     public $compiler_object = null;
19     public $cacher_object = null; 
20     // Smarty parameter
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; 
28     // Template resource
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 = ''; 
35     // Template source
36     public $template_filepath = null;
37     public $template_source = null;
38     private $template_timestamp = null; 
39     // Compiled template
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; 
48     // Rendered content
49     public $rendered_content = null; 
50     // Cache file
51     private $cached_filepath = null;
52     public $cached_timestamp = null;
53     private $isCached = null;
54 //    private $cache_resource_object = null;
55     private $cacheFileChecked = false; 
56     // template variables
57     public $tpl_vars = array();
58     public $parent = null;
59     public $config_vars = array(); 
60     // storage for plugin
61     public $plugin_data = array(); 
62     // special properties
63     public $properties = array ('file_dependency' => array(),
64         'nocache_hash' => '',
65         'function' => array()); 
66     // required plugins
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;
73     /**
74      * Create template data object
75      * 
76      * Some of the global Smarty settings copied to template scope
77      * It load the required template resources and cacher plugins
78      * 
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
83      */
84     public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null)
85     {
86         $this->smarty = &$smarty; 
87         // Smarty parameter
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; 
96         // Template resource
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;
101         }
102  
103     } 
104
105     /**
106      * Returns the template filepath
107      * 
108      * The template filepath is determined by the actual resource handler
109      * 
110      * @return string the template filepath
111      */
112     public function getTemplateFilepath ()
113     {
114         return $this->template_filepath === null ?
115         $this->template_filepath = $this->resource_object->getTemplateFilepath($this) :
116         $this->template_filepath;
117     } 
118
119     /**
120      * Returns the timpestamp of the template source
121      * 
122      * The template timestamp is determined by the actual resource handler
123      * 
124      * @return integer the template timestamp
125      */
126     public function getTemplateTimestamp ()
127     {
128         return $this->template_timestamp === null ?
129         $this->template_timestamp = $this->resource_object->getTemplateTimestamp($this) :
130         $this->template_timestamp;
131     } 
132
133     /**
134      * Returns the template source code
135      * 
136      * The template source is being read by the actual resource handler
137      * 
138      * @return string the template source
139      */
140     public function getTemplateSource ()
141     {
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}'");
145             } 
146         } 
147         return $this->template_source;
148     } 
149
150     /**
151      * Returns if the  template is existing
152      * 
153      * The status is determined by the actual resource handler
154      * 
155      * @return boolean true if the template exists
156      */
157     public function isExisting ($error = false)
158     {
159         if ($this->isExisting === null) {
160             $this->isExisting = $this->resource_object->isExisting($this);
161         } 
162         if (!$this->isExisting && $error) {
163             throw new SmartyException("Unable to load template {$this->resource_type} '{$this->resource_name}'");
164         } 
165         return $this->isExisting;
166     } 
167
168     /**
169      * Returns if the current template must be compiled by the Smarty compiler
170      * 
171      * It does compare the timestamps of template source and the compiled templates and checks the force compile configuration
172      * 
173      * @return boolean true if the template must be compiled
174      */
175     public function mustCompile ()
176     {
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 ())));
182         } 
183         return $this->mustCompile;
184     } 
185
186     /**
187      * Returns the compiled template filepath
188      * 
189      * @return string the template filepath
190      */
191     public function getCompiledFilepath ()
192     {
193         return $this->compiled_filepath === null ?
194         ($this->compiled_filepath = !$this->resource_object->isEvaluated ? $this->resource_object->getCompiledFilepath($this) : false) :
195         $this->compiled_filepath;
196     } 
197
198     /**
199      * Returns the timpestamp of the compiled template
200      * 
201      * @return integer the template timestamp
202      */
203     public function getCompiledTimestamp ()
204     {
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;
208     } 
209
210     /**
211      * Returns the compiled template 
212      * 
213      * It checks if the template must be compiled or just read from the template resource
214      * 
215      * @return string the compiled template
216      */
217     public function getCompiledTemplate ()
218     {
219         if ($this->compiled_template === null) {
220             // see if template needs compiling.
221             if ($this->mustCompile()) {
222                 $this->compileTemplateSource();
223             } else {
224                 if ($this->compiled_template === null) {
225                     $this->compiled_template = !$this->resource_object->isEvaluated && $this->resource_object->usesCompiler ? file_get_contents($this->getCompiledFilepath()) : false;
226                 } 
227             } 
228         } 
229         return $this->compiled_template;
230     } 
231
232     /**
233      * Compiles the template
234      * 
235      * If the template is not evaluated the compiled template is saved on disk
236      */
237     public function compileTemplateSource ()
238     {
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);
242         } 
243         if ($this->smarty->debugging) {
244             Smarty_Internal_Debug::start_compile($this);
245         } 
246         // compile template
247         if (!is_object($this->compiler_object)) {
248             // load compiler
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);
251         } 
252         // compile locking
253         if ($this->smarty->compile_locking && !$this->resource_object->isEvaluated) {
254             if ($saved_timestamp = $this->getCompiledTimestamp()) {
255                 touch($this->getCompiledFilepath());
256             } 
257         } 
258         // call compiler
259         try {
260             $this->compiler_object->compileTemplate($this);
261         } 
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);
266             } 
267             throw $e;
268         } 
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);
273         } 
274         if ($this->smarty->debugging) {
275             Smarty_Internal_Debug::end_compile($this);
276         }
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
285                 ); 
286     } 
287
288     /**
289      * Returns the filepath of the cached template output
290      * 
291      * The filepath is determined by the actual cache resource
292      * 
293      * @return string the cache filepath
294      */
295     public function getCachedFilepath ()
296     {
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;
300     } 
301
302     /**
303      * Returns the timpestamp of the cached template output
304      * 
305      * The timestamp is determined by the actual cache resource
306      * 
307      * @return integer the template timestamp
308      */
309     public function getCachedTimestamp ()
310     {
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;
314     } 
315
316     /**
317      * Returns the cached template output
318      * 
319      * @return string |booelan the template content or false if the file does not exist
320      */
321     public function getCachedContent ()
322     {
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;
326     } 
327
328     /**
329      * Writes the cached template output
330      */
331     public function writeCachedContent ($content)
332     {
333         if ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) {
334             // don't write cache file
335             return false;
336         } 
337         $this->properties['cache_lifetime'] = $this->cache_lifetime;
338         return $this->cache_resource_object->writeCachedContent($this, $this->createPropertyHeader(true) .$content);
339     } 
340
341     /**
342      * Checks of a valid version redered HTML output is in the cache
343      * 
344      * If the cache is valid the contents is stored in the template object
345      * 
346      * @return boolean true if cache is valid
347      */
348     public function isCached ($template = null, $cache_id = null, $compile_id = null, $parent = null)
349     {
350         if ($template === null) {               
351                         $no_render = true;
352                 } elseif ($template === false) {
353                         $no_render = false;
354                 } else {
355                         if ($parent === null) {
356                                 $parent = $this;
357                         }
358                         $this->smarty->isCached ($template, $cache_id, $compile_id, $parent);
359                 }
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;
366                 } 
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);
370                     } 
371                     $this->rendered_content = $this->cache_resource_object->getCachedContents($this, $no_render);
372                     if ($this->smarty->debugging) {
373                         Smarty_Internal_Debug::end_cache($this);
374                     } 
375                     if ($this->cacheFileChecked) {
376                         $this->isCached = true;
377                         return $this->isCached;
378                     } 
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;
384                     } 
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]);
391                             } else {
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);
395                             } 
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;
401                             } 
402                         } 
403                     } 
404                     $this->isCached = true;
405                 } 
406             } 
407         } 
408         return $this->isCached;
409     } 
410
411     /**
412      * Render the output using the compiled template or the PHP template source
413      * 
414      * The rendering process is accomplished by just including the PHP files.
415      * The only exceptions are evaluated templates (string template). Their code has 
416      * to be evaluated
417      */
418     public function renderTemplate ()
419     {
420         if ($this->resource_object->usesCompiler) {
421             if ($this->mustCompile() && $this->compiled_template === null) {
422                 $this->compileTemplateSource();
423             } 
424             if ($this->smarty->debugging) {
425                 Smarty_Internal_Debug::start_render($this);
426             } 
427             $_smarty_tpl = $this;
428             ob_start();
429             if ($this->resource_object->isEvaluated) {
430                 eval("?>" . $this->compiled_template);
431             } else {
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]);
442                             } else {
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);
446                             } 
447                             // If ($mtime != $_file_to_check[1]) {
448                             If ($mtime > $_file_to_check[1]) {
449                                 $this->mustCompile = true;
450                                 break;
451                             } 
452                         } 
453                         if ($this->mustCompile) {
454                             // recompile and render again
455                             ob_get_clean();
456                             $this->compileTemplateSource();
457                             ob_start();
458                             include($this->getCompiledFilepath ());
459                         } 
460                     } 
461                 } 
462             } 
463         } else {
464             if (is_callable(array($this->resource_object, 'renderUncompiled'))) {
465                 if ($this->smarty->debugging) {
466                     Smarty_Internal_Debug::start_render($this);
467                 } 
468                 ob_start();
469                 $this->resource_object->renderUncompiled($this);
470             } else {
471                 throw new SmartyException("Resource '$this->resource_type' must have 'renderUncompiled' methode");
472             } 
473         } 
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);
477         } 
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;
484                     } 
485                 } 
486             } 
487         } 
488         if ($this->smarty->debugging) {
489             Smarty_Internal_Debug::end_render($this);
490         } 
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);
495             } 
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);
501             $output = ''; 
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]);
510                 } 
511             } 
512             if (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output'])) {
513                 $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $this);
514                 }
515             // rendering (must be done before writing cache file because of {function} nocache handling)
516             $_smarty_tpl = $this;
517             ob_start();
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);
524             } 
525         } else {
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;
531             } 
532         } 
533     } 
534
535     /**
536      * Returns the rendered HTML output 
537      * 
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
540      * 
541      * @return string rendered HTML output
542      */
543     public function getRenderedTemplate ()
544     { 
545         // disable caching for evaluated code
546         if ($this->resource_object->isEvaluated) {
547             $this->caching = false;
548         } 
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);
556             } 
557             $this->rendered_content = $this->cache_resource_object->getCachedContents($this, false);
558             if ($this->smarty->debugging) {
559                 Smarty_Internal_Debug::end_cache($this);
560             }
561           } 
562           if ($this->isCached === null) { 
563             $this->isCached(false); 
564           }
565           if (!$this->isCached) {          
566             // render template (not loaded and not in cache)
567             $this->renderTemplate();
568           }
569         } 
570         $this->updateParentVariables();
571         $this->isCached = null;
572         return $this->rendered_content;
573     } 
574
575     /**
576      * Parse a template resource in its name and type
577      * Load required resource handler
578      * 
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
583      */
584     public function parseResourceName($template_resource, &$resource_type, &$resource_name, &$resource_handler)
585     {
586         if (empty($template_resource))
587             return false;
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;
594         } 
595         return true;
596     } 
597
598     /**
599      * get system filepath to template
600      */
601     public function buildTemplateFilepath ($file = null)
602     {
603         if ($file == null) {
604             $file = $this->resource_name;
605         }
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;
611                 } 
612                 $_filepath = $_template_dir . $file;
613                 if (file_exists($_filepath)) {
614                         return $_filepath;
615                 }
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) {
619                                         return $_filepath;
620                                 }
621                         }
622                 }
623         }
624         // try absolute filepath
625         if (file_exists($file)) return $file;
626         // no tpl file found
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");
630             } else {
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)) {
634                     return $_return;
635                 } elseif ($_return === true) {
636                     return $file;
637                 } 
638             } 
639         } 
640         return false;
641     } 
642
643     /**
644      * Update Smarty variables in other scopes
645      */
646     public function updateParentVariables ($scope = Smarty::SCOPE_LOCAL)
647     {
648         $has_root = false;
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) {
652                 continue;
653             } 
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;
658                 } else {
659                     // create variable in parent
660                     $this->parent->tpl_vars[$_key] = clone $_variable;
661                     $this->parent->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
662                 } 
663             } 
664             if ($scope == Smarty::SCOPE_ROOT || $_variable_scope == Smarty::SCOPE_ROOT) {
665                 if ($this->parent == null) {
666                     continue;
667                 } 
668                 if (!$has_root) {
669                     // find  root
670                     $root_ptr = $this;
671                     while ($root_ptr->parent != null) {
672                         $root_ptr = $root_ptr->parent;
673                         $has_root = true;
674                     } 
675                 } 
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;
679                 } else {
680                     // create variable in root
681                     $root_ptr->tpl_vars[$_key] = clone $_variable;
682                     $root_ptr->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
683                 } 
684             } 
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;
689                 } else {
690                     // create global variable
691                    Smarty::$global_tpl_vars[$_key] = clone $_variable;
692                 } 
693                Smarty::$global_tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
694             } 
695         } 
696     } 
697
698     /**
699      * Split a template resource in its name and type
700      * 
701      * @param string $template_resource template resource specification
702      * @param string $resource_type return resource type
703      * @param string $resource_name return resource name
704      */
705     protected function getResourceTypeName ($template_resource, &$resource_type, &$resource_name)
706     {
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;
711         } else {
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;
718             }
719         } 
720     } 
721
722     /**
723      * Load template resource handler by type
724      * 
725      * @param string $resource_type template resource type
726      * @return object resource handler object
727      */
728     protected function loadTemplateResourceHandler ($resource_type)
729     { 
730         // try registered resource
731         if (isset($this->smarty->registered_resources[$resource_type])) {
732             return new Smarty_Internal_Resource_Registered($this);
733         } else {
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);
738             } else {
739                 // try plugins dir
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);
744                     } else {
745                         return new Smarty_Internal_Resource_Registered($this, $resource_type);
746                     } 
747                 } else {
748                     // try streams
749                     $_known_stream = stream_get_wrappers();
750                     if (in_array($resource_type, $_known_stream)) {
751                         // is known stream
752                         if (is_object($this->smarty->security_policy)) {
753                             $this->smarty->security_policy->isTrustedStream($resource_type);
754                         } 
755                         return new Smarty_Internal_Resource_Stream($this->smarty);
756                     } else {
757                         throw new SmartyException('Unkown resource type \'' . $resource_type . '\'');
758                     } 
759                 } 
760             } 
761         } 
762     } 
763
764     /**
765      * Create property header
766      */
767     public function createPropertyHeader ($cache = false)
768     {
769         $plugins_string = ''; 
770         // include code for plugins
771         if (!$cache) {
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";
777                     } 
778                 } 
779                 $plugins_string .= '?>';
780             } 
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";
787                     } 
788                 } 
789                 $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
790             } 
791         } 
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";
797         } 
798         if ($cache) {
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;
807                     } 
808                 } 
809             } 
810         } 
811         $properties_string .= "\$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n";
812         return $properties_string . $plugins_string;
813     } 
814
815     /**
816      * Decode saved properties from compiled template and cache files
817      */
818     public function decodeProperties ($properties)
819     {
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'];
824         } 
825         if (isset($properties['file_dependency'])) {
826             $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
827         } 
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']);
831         } 
832     } 
833
834     /**
835      * creates a local Smarty variable for array assignments
836      */
837     public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL)
838     {
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);
843             } else {
844                 $this->tpl_vars[$tpl_var] = clone $tpl_var_inst;
845                 if ($scope != Smarty::SCOPE_LOCAL) {
846                     $this->tpl_vars[$tpl_var]->scope = $scope;
847                 } 
848             } 
849         } 
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');
852         } 
853     } 
854
855     /**
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
859      */
860     public function _count($value)
861     {
862         if (is_array($value) === true || $value instanceof Countable) {
863             return count($value);
864         } elseif ($value instanceof Iterator) {
865             $value->rewind();
866             if ($value->valid()) {
867                 return iterator_count($value);
868             }
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)) {
875                 return 1;
876             }
877        } elseif (is_object($value)) {
878             return count($value);
879        }
880        return 0;
881     }
882
883     /**
884      * wrapper for fetch
885      */
886     public function fetch ($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false)
887     {
888                 if ($template == null) {
889                 return $this->smarty->fetch($this);
890         } else {
891                 if (!isset($parent)) {
892                         $parent = $this;
893                 }
894                 return $this->smarty->fetch($template, $cache_id, $compile_id, $parent, $display);
895         }
896         
897     } 
898  
899      /**
900      * wrapper for display
901      */
902     public function display ($template = null, $cache_id = null, $compile_id = null, $parent = null)
903     {
904                 if ($template == null) {
905                 return $this->smarty->display($this);
906         } else {
907                 if (!isset($parent)) {
908                         $parent = $this;
909                 }
910                 return $this->smarty->display($template, $cache_id, $compile_id, $parent);
911         }
912        
913     } 
914
915     /**
916      * set Smarty property in template context      
917      * @param string $property_name property name
918      * @param mixed $value value
919      */
920     public function __set($property_name, $value)
921     {
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;
926         } else {
927                 throw new SmartyException("invalid template property '$property_name'.");
928         }
929     }
930
931     /**
932      * get Smarty property in template context      
933      * @param string $property_name property name
934      */
935     public function __get($property_name)
936     {
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}\"");
942                 }
943                 return $this->resource_object;
944         }
945         if ($property_name == 'cache_resource_object') { 
946                 // load cache resource
947             $this->cache_resource_object = $this->loadCacheResource();
948             return $this->cache_resource_object;
949         }
950         if (property_exists($this->smarty, $property_name)) {
951                 return $this->smarty->$property_name;
952         } else {
953                 throw new SmartyException("template property '$property_name' does not exist.");
954         }
955     }
956
957
958     /**
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
962      * 
963      * @param string $name unknown methode name
964      * @param array $args aurgument array
965      */
966     public function __call($name, $args)
967     {
968         static $camel_func;
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;
982                 else
983                         return $this->$property_name = $args[0];
984                 }
985         }
986         // Smarty Backward Compatible wrapper
987                 if (strpos($name,'_') !== false) {
988                 if (!isset($this->wrapper)) {
989                  $this->wrapper = new Smarty_Internal_Wrapper($this);
990                 } 
991                 return $this->wrapper->convert($name, $args);
992         }
993         // pass call to Smarty object   
994         return call_user_func_array(array($this->smarty,$name),$args);
995     } 
996
997 }
998 ?>