]> git.mxchange.org Git - friendica.git/blob - library/Smarty/libs/sysplugins/smarty_internal_templatebase.php
Merge branch 'develop' of https://github.com/friendica/friendica into develop
[friendica.git] / library / Smarty / libs / sysplugins / smarty_internal_templatebase.php
1 <?php\r
2 /**\r
3  * Smarty Internal Plugin Smarty Template  Base\r
4  * This file contains the basic shared methods for template handling\r
5  *\r
6  * @package    Smarty\r
7  * @subpackage Template\r
8  * @author     Uwe Tews\r
9  */\r
10 \r
11 /**\r
12  * Class with shared template methods\r
13  *\r
14  * @package    Smarty\r
15  * @subpackage Template\r
16  */\r
17 abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data\r
18 {\r
19     /**\r
20      * fetches a rendered Smarty template\r
21      *\r
22      * @param  string $template         the resource handle of the template file or template object\r
23      * @param  mixed  $cache_id         cache id to be used with this template\r
24      * @param  mixed  $compile_id       compile id to be used with this template\r
25      * @param  object $parent           next higher level of Smarty variables\r
26      * @param  bool   $display          true: display, false: fetch\r
27      * @param  bool   $merge_tpl_vars   if true parent template variables merged in to local scope\r
28      * @param  bool   $no_output_filter if true do not run output filter\r
29      *\r
30      * @throws Exception\r
31      * @throws SmartyException\r
32      * @return string rendered template output\r
33      */\r
34     public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false, $merge_tpl_vars = true, $no_output_filter = false)\r
35     {\r
36         if ($template === null && $this instanceof $this->template_class) {\r
37             $template = $this;\r
38         }\r
39         if ($cache_id !== null && is_object($cache_id)) {\r
40             $parent = $cache_id;\r
41             $cache_id = null;\r
42         }\r
43         if ($parent === null && ($this instanceof Smarty || is_string($template))) {\r
44             $parent = $this;\r
45         }\r
46         // create template object if necessary\r
47         $_template = ($template instanceof $this->template_class)\r
48             ? $template\r
49             : $this->smarty->createTemplate($template, $cache_id, $compile_id, $parent, false);\r
50         // if called by Smarty object make sure we use current caching status\r
51         if ($this instanceof Smarty) {\r
52             $_template->caching = $this->caching;\r
53         }\r
54         // merge all variable scopes into template\r
55         if ($merge_tpl_vars) {\r
56             // save local variables\r
57             $save_tpl_vars = $_template->tpl_vars;\r
58             $save_config_vars = $_template->config_vars;\r
59             $ptr_array = array($_template);\r
60             $ptr = $_template;\r
61             while (isset($ptr->parent)) {\r
62                 $ptr_array[] = $ptr = $ptr->parent;\r
63             }\r
64             $ptr_array = array_reverse($ptr_array);\r
65             $parent_ptr = reset($ptr_array);\r
66             $tpl_vars = $parent_ptr->tpl_vars;\r
67             $config_vars = $parent_ptr->config_vars;\r
68             while ($parent_ptr = next($ptr_array)) {\r
69                 if (!empty($parent_ptr->tpl_vars)) {\r
70                     $tpl_vars = array_merge($tpl_vars, $parent_ptr->tpl_vars);\r
71                 }\r
72                 if (!empty($parent_ptr->config_vars)) {\r
73                     $config_vars = array_merge($config_vars, $parent_ptr->config_vars);\r
74                 }\r
75             }\r
76             if (!empty(Smarty::$global_tpl_vars)) {\r
77                 $tpl_vars = array_merge(Smarty::$global_tpl_vars, $tpl_vars);\r
78             }\r
79             $_template->tpl_vars = $tpl_vars;\r
80             $_template->config_vars = $config_vars;\r
81         }\r
82         // dummy local smarty variable\r
83         if (!isset($_template->tpl_vars['smarty'])) {\r
84             $_template->tpl_vars['smarty'] = new Smarty_Variable;\r
85         }\r
86         if (isset($this->smarty->error_reporting)) {\r
87             $_smarty_old_error_level = error_reporting($this->smarty->error_reporting);\r
88         }\r
89         // check URL debugging control\r
90         if (!$this->smarty->debugging && $this->smarty->debugging_ctrl == 'URL') {\r
91             if (isset($_SERVER['QUERY_STRING'])) {\r
92                 $_query_string = $_SERVER['QUERY_STRING'];\r
93             } else {\r
94                 $_query_string = '';\r
95             }\r
96             if (false !== strpos($_query_string, $this->smarty->smarty_debug_id)) {\r
97                 if (false !== strpos($_query_string, $this->smarty->smarty_debug_id . '=on')) {\r
98                     // enable debugging for this browser session\r
99                     setcookie('SMARTY_DEBUG', true);\r
100                     $this->smarty->debugging = true;\r
101                 } elseif (false !== strpos($_query_string, $this->smarty->smarty_debug_id . '=off')) {\r
102                     // disable debugging for this browser session\r
103                     setcookie('SMARTY_DEBUG', false);\r
104                     $this->smarty->debugging = false;\r
105                 } else {\r
106                     // enable debugging for this page\r
107                     $this->smarty->debugging = true;\r
108                 }\r
109             } else {\r
110                 if (isset($_COOKIE['SMARTY_DEBUG'])) {\r
111                     $this->smarty->debugging = true;\r
112                 }\r
113             }\r
114         }\r
115         // must reset merge template date\r
116         $_template->smarty->merged_templates_func = array();\r
117         // get rendered template\r
118         // disable caching for evaluated code\r
119         if ($_template->source->recompiled) {\r
120             $_template->caching = false;\r
121         }\r
122         // checks if template exists\r
123         if (!$_template->source->exists) {\r
124             if ($_template->parent instanceof Smarty_Internal_Template) {\r
125                 $parent_resource = " in '{$_template->parent->template_resource}'";\r
126             } else {\r
127                 $parent_resource = '';\r
128             }\r
129             throw new SmartyException("Unable to load template {$_template->source->type} '{$_template->source->name}'{$parent_resource}");\r
130         }\r
131         // read from cache or render\r
132         if (!($_template->caching == Smarty::CACHING_LIFETIME_CURRENT || $_template->caching == Smarty::CACHING_LIFETIME_SAVED) || !$_template->cached->valid) {\r
133             // render template (not loaded and not in cache)\r
134             if (!$_template->source->uncompiled) {\r
135                 /** @var Smarty_Internal_Template $_smarty_tpl\r
136                  * used in evaluated code\r
137                  */\r
138                 $_smarty_tpl = $_template;\r
139                 if ($_template->source->recompiled) {\r
140                     $code = $_template->compiler->compileTemplate($_template);\r
141                     if ($this->smarty->debugging) {\r
142                         Smarty_Internal_Debug::start_render($_template);\r
143                     }\r
144                     try {\r
145                         ob_start();\r
146                         eval("?>" . $code);\r
147                         unset($code);\r
148                     }\r
149                     catch (Exception $e) {\r
150                         ob_get_clean();\r
151                         throw $e;\r
152                     }\r
153                 } else {\r
154                     if (!$_template->compiled->exists || ($_template->smarty->force_compile && !$_template->compiled->isCompiled)) {\r
155                         $_template->compileTemplateSource();\r
156                         $code = file_get_contents($_template->compiled->filepath);\r
157                         eval("?>" . $code);\r
158                         unset($code);\r
159                         $_template->compiled->loaded = true;\r
160                         $_template->compiled->isCompiled = true;\r
161                     }\r
162                     if ($this->smarty->debugging) {\r
163                         Smarty_Internal_Debug::start_render($_template);\r
164                     }\r
165                     if (!$_template->compiled->loaded) {\r
166                         include($_template->compiled->filepath);\r
167                         if ($_template->mustCompile) {\r
168                             // recompile and load again\r
169                             $_template->compileTemplateSource();\r
170                             $code = file_get_contents($_template->compiled->filepath);\r
171                             eval("?>" . $code);\r
172                             unset($code);\r
173                             $_template->compiled->isCompiled = true;\r
174                         }\r
175                         $_template->compiled->loaded = true;\r
176                     } else {\r
177                         $_template->decodeProperties($_template->compiled->_properties, false);\r
178                     }\r
179                     try {\r
180                         ob_start();\r
181                         if (empty($_template->properties['unifunc']) || !is_callable($_template->properties['unifunc'])) {\r
182                             throw new SmartyException("Invalid compiled template for '{$_template->template_resource}'");\r
183                         }\r
184                         array_unshift($_template->_capture_stack, array());\r
185                         //\r
186                         // render compiled template\r
187                         //\r
188                         $_template->properties['unifunc']($_template);\r
189                         // any unclosed {capture} tags ?\r
190                         if (isset($_template->_capture_stack[0][0])) {\r
191                             $_template->capture_error();\r
192                         }\r
193                         array_shift($_template->_capture_stack);\r
194                     }\r
195                     catch (Exception $e) {\r
196                         ob_get_clean();\r
197                         throw $e;\r
198                     }\r
199                 }\r
200             } else {\r
201                 if ($_template->source->uncompiled) {\r
202                     if ($this->smarty->debugging) {\r
203                         Smarty_Internal_Debug::start_render($_template);\r
204                     }\r
205                     try {\r
206                         ob_start();\r
207                         $_template->source->renderUncompiled($_template);\r
208                     }\r
209                     catch (Exception $e) {\r
210                         ob_get_clean();\r
211                         throw $e;\r
212                     }\r
213                 } else {\r
214                     throw new SmartyException("Resource '$_template->source->type' must have 'renderUncompiled' method");\r
215                 }\r
216             }\r
217             $_output = ob_get_clean();\r
218             if (!$_template->source->recompiled && empty($_template->properties['file_dependency'][$_template->source->uid])) {\r
219                 $_template->properties['file_dependency'][$_template->source->uid] = array($_template->source->filepath, $_template->source->timestamp, $_template->source->type);\r
220             }\r
221             if ($_template->parent instanceof Smarty_Internal_Template) {\r
222                 $_template->parent->properties['file_dependency'] = array_merge($_template->parent->properties['file_dependency'], $_template->properties['file_dependency']);\r
223                 foreach ($_template->required_plugins as $code => $tmp1) {\r
224                     foreach ($tmp1 as $name => $tmp) {\r
225                         foreach ($tmp as $type => $data) {\r
226                             $_template->parent->required_plugins[$code][$name][$type] = $data;\r
227                         }\r
228                     }\r
229                 }\r
230             }\r
231             if ($this->smarty->debugging) {\r
232                 Smarty_Internal_Debug::end_render($_template);\r
233             }\r
234             // write to cache when nessecary\r
235             if (!$_template->source->recompiled && ($_template->caching == Smarty::CACHING_LIFETIME_SAVED || $_template->caching == Smarty::CACHING_LIFETIME_CURRENT)) {\r
236                 if ($this->smarty->debugging) {\r
237                     Smarty_Internal_Debug::start_cache($_template);\r
238                 }\r
239                 $_template->properties['has_nocache_code'] = false;\r
240                 // get text between non-cached items\r
241                 $cache_split = preg_split("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $_output);\r
242                 // get non-cached items\r
243                 preg_match_all("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $_output, $cache_parts);\r
244                 $output = '';\r
245                 // loop over items, stitch back together\r
246                 foreach ($cache_split as $curr_idx => $curr_split) {\r
247                     // escape PHP tags in template content\r
248                     $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', "<?php echo '\$1'; ?>\n", $curr_split);\r
249                     if (isset($cache_parts[0][$curr_idx])) {\r
250                         $_template->properties['has_nocache_code'] = true;\r
251                         // remove nocache tags from cache output\r
252                         $output .= preg_replace("!/\*/?%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);\r
253                     }\r
254                 }\r
255                 if (!$no_output_filter && !$_template->has_nocache_code && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))) {\r
256                     $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $_template);\r
257                 }\r
258                 // rendering (must be done before writing cache file because of {function} nocache handling)\r
259                 /** @var Smarty_Internal_Template $_smarty_tpl\r
260                  * used in evaluated code\r
261                  */\r
262                 $_smarty_tpl = $_template;\r
263                 try {\r
264                     ob_start();\r
265                     eval("?>" . $output);\r
266                     $_output = ob_get_clean();\r
267                 }\r
268                 catch (Exception $e) {\r
269                     ob_get_clean();\r
270                     throw $e;\r
271                 }\r
272                 // write cache file content\r
273                 $_template->writeCachedContent($output);\r
274                 if ($this->smarty->debugging) {\r
275                     Smarty_Internal_Debug::end_cache($_template);\r
276                 }\r
277             } else {\r
278                 // var_dump('renderTemplate', $_template->has_nocache_code, $_template->template_resource, $_template->properties['nocache_hash'], $_template->parent->properties['nocache_hash'], $_output);\r
279                 if (!empty($_template->properties['nocache_hash']) && !empty($_template->parent->properties['nocache_hash'])) {\r
280                     // replace nocache_hash\r
281                     $_output = str_replace("{$_template->properties['nocache_hash']}", $_template->parent->properties['nocache_hash'], $_output);\r
282                     $_template->parent->has_nocache_code = $_template->parent->has_nocache_code || $_template->has_nocache_code;\r
283                 }\r
284             }\r
285         } else {\r
286             if ($this->smarty->debugging) {\r
287                 Smarty_Internal_Debug::start_cache($_template);\r
288             }\r
289             try {\r
290                 ob_start();\r
291                 array_unshift($_template->_capture_stack, array());\r
292                 //\r
293                 // render cached template\r
294                 //\r
295                 $_template->properties['unifunc']($_template);\r
296                 // any unclosed {capture} tags ?\r
297                 if (isset($_template->_capture_stack[0][0])) {\r
298                     $_template->capture_error();\r
299                 }\r
300                 array_shift($_template->_capture_stack);\r
301                 $_output = ob_get_clean();\r
302             }\r
303             catch (Exception $e) {\r
304                 ob_get_clean();\r
305                 throw $e;\r
306             }\r
307             if ($this->smarty->debugging) {\r
308                 Smarty_Internal_Debug::end_cache($_template);\r
309             }\r
310         }\r
311         if ((!$this->caching || $_template->has_nocache_code || $_template->source->recompiled) && !$no_output_filter && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))) {\r
312             $_output = Smarty_Internal_Filter_Handler::runFilter('output', $_output, $_template);\r
313         }\r
314         if (isset($this->error_reporting)) {\r
315             error_reporting($_smarty_old_error_level);\r
316         }\r
317         // display or fetch\r
318         if ($display) {\r
319             if ($this->caching && $this->cache_modified_check) {\r
320                 $_isCached = $_template->isCached() && !$_template->has_nocache_code;\r
321                 $_last_modified_date = @substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3);\r
322                 if ($_isCached && $_template->cached->timestamp <= strtotime($_last_modified_date)) {\r
323                     switch (PHP_SAPI) {\r
324                         case 'cgi': // php-cgi < 5.3\r
325                         case 'cgi-fcgi': // php-cgi >= 5.3\r
326                         case 'fpm-fcgi': // php-fpm >= 5.3.3\r
327                             header('Status: 304 Not Modified');\r
328                             break;\r
329 \r
330                         case 'cli':\r
331                             if ( /* ^phpunit */\r
332                             !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */\r
333                             ) {\r
334                                 $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = '304 Not Modified';\r
335                             }\r
336                             break;\r
337 \r
338                         default:\r
339                             header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');\r
340                             break;\r
341                     }\r
342                 } else {\r
343                     switch (PHP_SAPI) {\r
344                         case 'cli':\r
345                             if ( /* ^phpunit */\r
346                             !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */\r
347                             ) {\r
348                                 $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $_template->cached->timestamp) . ' GMT';\r
349                             }\r
350                             break;\r
351 \r
352                         default:\r
353                             header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $_template->cached->timestamp) . ' GMT');\r
354                             break;\r
355                     }\r
356                     echo $_output;\r
357                 }\r
358             } else {\r
359                 echo $_output;\r
360             }\r
361             // debug output\r
362             if ($this->smarty->debugging) {\r
363                 Smarty_Internal_Debug::display_debug($_template);\r
364             }\r
365             if ($merge_tpl_vars) {\r
366                 // restore local variables\r
367                 $_template->tpl_vars = $save_tpl_vars;\r
368                 $_template->config_vars = $save_config_vars;\r
369             }\r
370 \r
371             return;\r
372         } else {\r
373             if ($merge_tpl_vars) {\r
374                 // restore local variables\r
375                 $_template->tpl_vars = $save_tpl_vars;\r
376                 $_template->config_vars = $save_config_vars;\r
377             }\r
378             // return fetched content\r
379             return $_output;\r
380         }\r
381     }\r
382 \r
383     /**\r
384      * displays a Smarty template\r
385      *\r
386      * @param string $template   the resource handle of the template file or template object\r
387      * @param mixed  $cache_id   cache id to be used with this template\r
388      * @param mixed  $compile_id compile id to be used with this template\r
389      * @param object $parent     next higher level of Smarty variables\r
390      */\r
391     public function display($template = null, $cache_id = null, $compile_id = null, $parent = null)\r
392     {\r
393         // display template\r
394         $this->fetch($template, $cache_id, $compile_id, $parent, true);\r
395     }\r
396 \r
397     /**\r
398      * test if cache is valid\r
399      *\r
400      * @param  string|object $template   the resource handle of the template file or template object\r
401      * @param  mixed         $cache_id   cache id to be used with this template\r
402      * @param  mixed         $compile_id compile id to be used with this template\r
403      * @param  object        $parent     next higher level of Smarty variables\r
404      *\r
405      * @return boolean       cache status\r
406      */\r
407     public function isCached($template = null, $cache_id = null, $compile_id = null, $parent = null)\r
408     {\r
409         if ($template === null && $this instanceof $this->template_class) {\r
410             return $this->cached->valid;\r
411         }\r
412         if (!($template instanceof $this->template_class)) {\r
413             if ($parent === null) {\r
414                 $parent = $this;\r
415             }\r
416             $template = $this->smarty->createTemplate($template, $cache_id, $compile_id, $parent, false);\r
417         }\r
418         // return cache status of template\r
419         return $template->cached->valid;\r
420     }\r
421 \r
422     /**\r
423      * creates a data object\r
424      *\r
425      * @param object $parent next higher level of Smarty variables\r
426      *\r
427      * @returns Smarty_Data data object\r
428      */\r
429     public function createData($parent = null)\r
430     {\r
431         return new Smarty_Data($parent, $this);\r
432     }\r
433 \r
434     /**\r
435      * Registers plugin to be used in templates\r
436      *\r
437      * @param  string   $type       plugin type\r
438      * @param  string   $tag        name of template tag\r
439      * @param  callback $callback   PHP callback to register\r
440      * @param  boolean  $cacheable  if true (default) this fuction is cachable\r
441      * @param  array    $cache_attr caching attributes if any\r
442      *\r
443      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
444      * @throws SmartyException              when the plugin tag is invalid\r
445      */\r
446     public function registerPlugin($type, $tag, $callback, $cacheable = true, $cache_attr = null)\r
447     {\r
448         if (isset($this->smarty->registered_plugins[$type][$tag])) {\r
449             throw new SmartyException("Plugin tag \"{$tag}\" already registered");\r
450         } elseif (!is_callable($callback)) {\r
451             throw new SmartyException("Plugin \"{$tag}\" not callable");\r
452         } else {\r
453             $this->smarty->registered_plugins[$type][$tag] = array($callback, (bool) $cacheable, (array) $cache_attr);\r
454         }\r
455 \r
456         return $this;\r
457     }\r
458 \r
459     /**\r
460      * Unregister Plugin\r
461      *\r
462      * @param  string $type of plugin\r
463      * @param  string $tag  name of plugin\r
464      *\r
465      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
466      */\r
467     public function unregisterPlugin($type, $tag)\r
468     {\r
469         if (isset($this->smarty->registered_plugins[$type][$tag])) {\r
470             unset($this->smarty->registered_plugins[$type][$tag]);\r
471         }\r
472 \r
473         return $this;\r
474     }\r
475 \r
476     /**\r
477      * Registers a resource to fetch a template\r
478      *\r
479      * @param  string                $type     name of resource type\r
480      * @param  Smarty_Resource|array $callback or instance of Smarty_Resource, or array of callbacks to handle resource (deprecated)\r
481      *\r
482      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
483      */\r
484     public function registerResource($type, $callback)\r
485     {\r
486         $this->smarty->registered_resources[$type] = $callback instanceof Smarty_Resource ? $callback : array($callback, false);\r
487 \r
488         return $this;\r
489     }\r
490 \r
491     /**\r
492      * Unregisters a resource\r
493      *\r
494      * @param  string $type name of resource type\r
495      *\r
496      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
497      */\r
498     public function unregisterResource($type)\r
499     {\r
500         if (isset($this->smarty->registered_resources[$type])) {\r
501             unset($this->smarty->registered_resources[$type]);\r
502         }\r
503 \r
504         return $this;\r
505     }\r
506 \r
507     /**\r
508      * Registers a cache resource to cache a template's output\r
509      *\r
510      * @param  string               $type     name of cache resource type\r
511      * @param  Smarty_CacheResource $callback instance of Smarty_CacheResource to handle output caching\r
512      *\r
513      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
514      */\r
515     public function registerCacheResource($type, Smarty_CacheResource $callback)\r
516     {\r
517         $this->smarty->registered_cache_resources[$type] = $callback;\r
518 \r
519         return $this;\r
520     }\r
521 \r
522     /**\r
523      * Unregisters a cache resource\r
524      *\r
525      * @param  string $type name of cache resource type\r
526      *\r
527      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
528      */\r
529     public function unregisterCacheResource($type)\r
530     {\r
531         if (isset($this->smarty->registered_cache_resources[$type])) {\r
532             unset($this->smarty->registered_cache_resources[$type]);\r
533         }\r
534 \r
535         return $this;\r
536     }\r
537 \r
538     /**\r
539      * Registers object to be used in templates\r
540      *\r
541      * @param          $object_name\r
542      * @param  object  $object_impl   the referenced PHP object to register\r
543      * @param  array   $allowed       list of allowed methods (empty = all)\r
544      * @param  boolean $smarty_args   smarty argument format, else traditional\r
545      * @param  array   $block_methods list of block-methods\r
546      *\r
547      * @throws SmartyException\r
548      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
549      */\r
550     public function registerObject($object_name, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())\r
551     {\r
552         // test if allowed methods callable\r
553         if (!empty($allowed)) {\r
554             foreach ((array) $allowed as $method) {\r
555                 if (!is_callable(array($object_impl, $method)) && !property_exists($object_impl, $method)) {\r
556                     throw new SmartyException("Undefined method or property '$method' in registered object");\r
557                 }\r
558             }\r
559         }\r
560         // test if block methods callable\r
561         if (!empty($block_methods)) {\r
562             foreach ((array) $block_methods as $method) {\r
563                 if (!is_callable(array($object_impl, $method))) {\r
564                     throw new SmartyException("Undefined method '$method' in registered object");\r
565                 }\r
566             }\r
567         }\r
568         // register the object\r
569         $this->smarty->registered_objects[$object_name] =\r
570             array($object_impl, (array) $allowed, (boolean) $smarty_args, (array) $block_methods);\r
571 \r
572         return $this;\r
573     }\r
574 \r
575     /**\r
576      * return a reference to a registered object\r
577      *\r
578      * @param  string $name object name\r
579      *\r
580      * @return object\r
581      * @throws SmartyException if no such object is found\r
582      */\r
583     public function getRegisteredObject($name)\r
584     {\r
585         if (!isset($this->smarty->registered_objects[$name])) {\r
586             throw new SmartyException("'$name' is not a registered object");\r
587         }\r
588         if (!is_object($this->smarty->registered_objects[$name][0])) {\r
589             throw new SmartyException("registered '$name' is not an object");\r
590         }\r
591 \r
592         return $this->smarty->registered_objects[$name][0];\r
593     }\r
594 \r
595     /**\r
596      * unregister an object\r
597      *\r
598      * @param  string $name object name\r
599      *\r
600      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
601      */\r
602     public function unregisterObject($name)\r
603     {\r
604         if (isset($this->smarty->registered_objects[$name])) {\r
605             unset($this->smarty->registered_objects[$name]);\r
606         }\r
607 \r
608         return $this;\r
609     }\r
610 \r
611     /**\r
612      * Registers static classes to be used in templates\r
613      *\r
614      * @param         $class_name\r
615      * @param  string $class_impl the referenced PHP class to register\r
616      *\r
617      * @throws SmartyException\r
618      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
619      */\r
620     public function registerClass($class_name, $class_impl)\r
621     {\r
622         // test if exists\r
623         if (!class_exists($class_impl)) {\r
624             throw new SmartyException("Undefined class '$class_impl' in register template class");\r
625         }\r
626         // register the class\r
627         $this->smarty->registered_classes[$class_name] = $class_impl;\r
628 \r
629         return $this;\r
630     }\r
631 \r
632     /**\r
633      * Registers a default plugin handler\r
634      *\r
635      * @param  callable $callback class/method name\r
636      *\r
637      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
638      * @throws SmartyException              if $callback is not callable\r
639      */\r
640     public function registerDefaultPluginHandler($callback)\r
641     {\r
642         if (is_callable($callback)) {\r
643             $this->smarty->default_plugin_handler_func = $callback;\r
644         } else {\r
645             throw new SmartyException("Default plugin handler '$callback' not callable");\r
646         }\r
647 \r
648         return $this;\r
649     }\r
650 \r
651     /**\r
652      * Registers a default template handler\r
653      *\r
654      * @param  callable $callback class/method name\r
655      *\r
656      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
657      * @throws SmartyException              if $callback is not callable\r
658      */\r
659     public function registerDefaultTemplateHandler($callback)\r
660     {\r
661         if (is_callable($callback)) {\r
662             $this->smarty->default_template_handler_func = $callback;\r
663         } else {\r
664             throw new SmartyException("Default template handler '$callback' not callable");\r
665         }\r
666 \r
667         return $this;\r
668     }\r
669 \r
670     /**\r
671      * Registers a default template handler\r
672      *\r
673      * @param  callable $callback class/method name\r
674      *\r
675      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
676      * @throws SmartyException              if $callback is not callable\r
677      */\r
678     public function registerDefaultConfigHandler($callback)\r
679     {\r
680         if (is_callable($callback)) {\r
681             $this->smarty->default_config_handler_func = $callback;\r
682         } else {\r
683             throw new SmartyException("Default config handler '$callback' not callable");\r
684         }\r
685 \r
686         return $this;\r
687     }\r
688 \r
689     /**\r
690      * Registers a filter function\r
691      *\r
692      * @param  string   $type filter type\r
693      * @param  callback $callback\r
694      *\r
695      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
696      */\r
697     public function registerFilter($type, $callback)\r
698     {\r
699         $this->smarty->registered_filters[$type][$this->_get_filter_name($callback)] = $callback;\r
700 \r
701         return $this;\r
702     }\r
703 \r
704     /**\r
705      * Unregisters a filter function\r
706      *\r
707      * @param  string   $type filter type\r
708      * @param  callback $callback\r
709      *\r
710      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
711      */\r
712     public function unregisterFilter($type, $callback)\r
713     {\r
714         $name = $this->_get_filter_name($callback);\r
715         if (isset($this->smarty->registered_filters[$type][$name])) {\r
716             unset($this->smarty->registered_filters[$type][$name]);\r
717         }\r
718 \r
719         return $this;\r
720     }\r
721 \r
722     /**\r
723      * Return internal filter name\r
724      *\r
725      * @param  callback $function_name\r
726      *\r
727      * @return string   internal filter name\r
728      */\r
729     public function _get_filter_name($function_name)\r
730     {\r
731         if (is_array($function_name)) {\r
732             $_class_name = (is_object($function_name[0]) ?\r
733                 get_class($function_name[0]) : $function_name[0]);\r
734 \r
735             return $_class_name . '_' . $function_name[1];\r
736         } else {\r
737             return $function_name;\r
738         }\r
739     }\r
740 \r
741     /**\r
742      * load a filter of specified type and name\r
743      *\r
744      * @param  string $type filter type\r
745      * @param  string $name filter name\r
746      *\r
747      * @throws SmartyException if filter could not be loaded\r
748      */\r
749     public function loadFilter($type, $name)\r
750     {\r
751         $_plugin = "smarty_{$type}filter_{$name}";\r
752         $_filter_name = $_plugin;\r
753         if ($this->smarty->loadPlugin($_plugin)) {\r
754             if (class_exists($_plugin, false)) {\r
755                 $_plugin = array($_plugin, 'execute');\r
756             }\r
757             if (is_callable($_plugin)) {\r
758                 $this->smarty->registered_filters[$type][$_filter_name] = $_plugin;\r
759 \r
760                 return true;\r
761             }\r
762         }\r
763         throw new SmartyException("{$type}filter \"{$name}\" not callable");\r
764     }\r
765 \r
766     /**\r
767      * unload a filter of specified type and name\r
768      *\r
769      * @param  string $type filter type\r
770      * @param  string $name filter name\r
771      *\r
772      * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining\r
773      */\r
774     public function unloadFilter($type, $name)\r
775     {\r
776         $_filter_name = "smarty_{$type}filter_{$name}";\r
777         if (isset($this->smarty->registered_filters[$type][$_filter_name])) {\r
778             unset ($this->smarty->registered_filters[$type][$_filter_name]);\r
779         }\r
780 \r
781         return $this;\r
782     }\r
783 \r
784     /**\r
785      * preg_replace callback to convert camelcase getter/setter to underscore property names\r
786      *\r
787      * @param  string $match match string\r
788      *\r
789      * @return string replacemant\r
790      */\r
791     private function replaceCamelcase($match)\r
792     {\r
793         return "_" . strtolower($match[1]);\r
794     }\r
795 \r
796     /**\r
797      * Handle unknown class methods\r
798      *\r
799      * @param string $name unknown method-name\r
800      * @param array  $args argument array\r
801      *\r
802      * @throws SmartyException\r
803      */\r
804     public function __call($name, $args)\r
805     {\r
806         static $_prefixes = array('set' => true, 'get' => true);\r
807         static $_resolved_property_name = array();\r
808         static $_resolved_property_source = array();\r
809 \r
810         // method of Smarty object?\r
811         if (method_exists($this->smarty, $name)) {\r
812             return call_user_func_array(array($this->smarty, $name), $args);\r
813         }\r
814         // see if this is a set/get for a property\r
815         $first3 = strtolower(substr($name, 0, 3));\r
816         if (isset($_prefixes[$first3]) && isset($name[3]) && $name[3] !== '_') {\r
817             if (isset($_resolved_property_name[$name])) {\r
818                 $property_name = $_resolved_property_name[$name];\r
819             } else {\r
820                 // try to keep case correct for future PHP 6.0 case-sensitive class methods\r
821                 // lcfirst() not available < PHP 5.3.0, so improvise\r
822                 $property_name = strtolower(substr($name, 3, 1)) . substr($name, 4);\r
823                 // convert camel case to underscored name\r
824                 $property_name = preg_replace_callback('/([A-Z])/', array($this, 'replaceCamelcase'), $property_name);\r
825                 $_resolved_property_name[$name] = $property_name;\r
826             }\r
827             if (isset($_resolved_property_source[$property_name])) {\r
828                 $_is_this = $_resolved_property_source[$property_name];\r
829             } else {\r
830                 $_is_this = null;\r
831                 if (property_exists($this, $property_name)) {\r
832                     $_is_this = true;\r
833                 } elseif (property_exists($this->smarty, $property_name)) {\r
834                     $_is_this = false;\r
835                 }\r
836                 $_resolved_property_source[$property_name] = $_is_this;\r
837             }\r
838             if ($_is_this) {\r
839                 if ($first3 == 'get') {\r
840                     return $this->$property_name;\r
841                 } else {\r
842                     return $this->$property_name = $args[0];\r
843                 }\r
844             } elseif ($_is_this === false) {\r
845                 if ($first3 == 'get') {\r
846                     return $this->smarty->$property_name;\r
847                 } else {\r
848                     return $this->smarty->$property_name = $args[0];\r
849                 }\r
850             } else {\r
851                 throw new SmartyException("property '$property_name' does not exist.");\r
852            }\r
853         }\r
854         if ($name == 'Smarty') {\r
855             throw new SmartyException("PHP5 requires you to call __construct() instead of Smarty()");\r
856         }\r
857         // must be unknown\r
858         throw new SmartyException("Call of unknown method '$name'.");\r
859     }\r
860 }\r