Code

fixed property
[gosa.git] / gosa-core / include / smarty / sysplugins / smarty_internal_templatecompilerbase.php
1 <?php\r
2 /**\r
3  * Smarty Internal Plugin Smarty Template Compiler Base\r
4  * \r
5  * This file contains the basic classes and methodes for compiling Smarty templates with lexer/parser\r
6  * \r
7  * @package Smarty\r
8  * @subpackage Compiler\r
9  * @author Uwe Tews \r
10  */\r
11 /**\r
12  * Main compiler class\r
13  */\r
14 class Smarty_Internal_TemplateCompilerBase {\r
15     // hash for nocache sections\r
16     private $nocache_hash = null; \r
17     // suppress generation of nocache code\r
18     public $suppressNocacheProcessing = false; \r
19     // compile tag objects\r
20     static $_tag_objects = array(); \r
21     // tag stack\r
22     public $_tag_stack = array(); \r
23     // current template\r
24     public $template = null;\r
25 \r
26     /**\r
27      * Initialize compiler\r
28      */\r
29     public function __construct()\r
30     {\r
31         $this->nocache_hash = str_replace('.', '-', uniqid(rand(), true));\r
32     } \r
33     // abstract function doCompile($_content);\r
34     /**\r
35      * Methode to compile a Smarty template\r
36      * \r
37      * @param  $template template object to compile\r
38      * @return bool true if compiling succeeded, false if it failed\r
39      */\r
40     public function compileTemplate($template)\r
41     {\r
42         if (empty($template->properties['nocache_hash'])) {\r
43             $template->properties['nocache_hash'] = $this->nocache_hash;\r
44         } else {\r
45             $this->nocache_hash = $template->properties['nocache_hash'];\r
46         } \r
47         /* here is where the compiling takes place. Smarty\r
48        tags in the templates are replaces with PHP code,\r
49        then written to compiled files. */\r
50         // flag for nochache sections\r
51         $this->nocache = false;\r
52         $this->tag_nocache = false; \r
53         // save template object in compiler class\r
54         $this->template = $template;\r
55         $this->smarty->_current_file = $this->template->getTemplateFilepath(); \r
56         // template header code\r
57         $template_header = '';\r
58         if (!$template->suppressHeader) {\r
59             $template_header .= "<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n";\r
60             $template_header .= "         compiled from \"" . $this->template->getTemplateFilepath() . "\" */ ?>\n";\r
61         } \r
62 \r
63         do {\r
64             // flag for aborting current and start recompile\r
65             $this->abort_and_recompile = false; \r
66             // get template source\r
67             $_content = $template->getTemplateSource(); \r
68             // run prefilter if required\r
69             if (isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) {\r
70                 $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $this->smarty, $template);\r
71             } \r
72             // on empty template just return header\r
73             if ($_content == '') {\r
74                 if ($template->suppressFileDependency) {\r
75                     $template->compiled_template = '';\r
76                 } else {\r
77                     $template->compiled_template = $template_header . $template->createPropertyHeader();\r
78                 } \r
79                 return true;\r
80             } \r
81             // call compiler\r
82             $_compiled_code = $this->doCompile($_content);\r
83         } while ($this->abort_and_recompile); \r
84         // return compiled code to template object\r
85         if ($template->suppressFileDependency) {\r
86             $template->compiled_template = $_compiled_code;\r
87         } else {\r
88             $template->compiled_template = $template_header . $template->createPropertyHeader() . $_compiled_code;\r
89         } \r
90         // run postfilter if required\r
91         if (isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) {\r
92             $template->compiled_template = Smarty_Internal_Filter_Handler::runFilter('post', $template->compiled_template, $this->smarty, $template);\r
93         } \r
94     } \r
95 \r
96     /**\r
97      * Compile Tag\r
98      * \r
99      * This is a call back from the lexer/parser\r
100      * It executes the required compile plugin for the Smarty tag\r
101      * \r
102      * @param string $tag tag name\r
103      * @param array $args array with tag attributes\r
104      * @return string compiled code\r
105      */\r
106     public function compileTag($tag, $args)\r
107     { \r
108         // $args contains the attributes parsed and compiled by the lexer/parser\r
109         // assume that tag does compile into code, but creates no HTML output\r
110         $this->has_code = true;\r
111         $this->has_output = false; \r
112         // compile the smarty tag (required compile classes to compile the tag are autoloaded)\r
113         if (($_output = $this->callTagCompiler($tag, $args)) === false) {\r
114             if (isset($this->smarty->template_functions[$tag])) {\r
115                 // template defined by {template} tag\r
116                 $args['name'] = "'" . $tag . "'";\r
117                 $_output = $this->callTagCompiler('call', $args);\r
118             } \r
119         } \r
120         if ($_output !== false) {\r
121             if ($_output !== true) {\r
122                 // did we get compiled code\r
123                 if ($this->has_code) {\r
124                     // Does it create output?\r
125                     if ($this->has_output) {\r
126                         $_output .= "\n";\r
127                     } \r
128                     // return compiled code\r
129                     return $_output;\r
130                 } \r
131             } \r
132             // tag did not produce compiled code\r
133             return '';\r
134         } else {\r
135             // not an internal compiler tag\r
136             if (strlen($tag) < 6 || substr_compare($tag, 'close', -5, 5) != 0) {\r
137                 // check if tag is a registered object\r
138                 if (isset($this->smarty->registered_objects[$tag]) && isset($args['object_methode'])) {\r
139                     $methode = $args['object_methode'];\r
140                     unset ($args['object_methode']);\r
141                     if (!in_array($methode, $this->smarty->registered_objects[$tag][3]) &&\r
142                             (empty($this->smarty->registered_objects[$tag][1]) || in_array($methode, $this->smarty->registered_objects[$tag][1]))) {\r
143                         return $this->callTagCompiler('private_object_function', $args, $tag, $methode);\r
144                     } elseif (in_array($methode, $this->smarty->registered_objects[$tag][3])) {\r
145                         return $this->callTagCompiler('private_object_block_function', $args, $tag, $methode);\r
146                     } else {\r
147                         return $this->trigger_template_error ('unallowed methode "' . $methode . '" in registered object "' . $tag . '"', $this->lex->taglineno);\r
148                     } \r
149                 } \r
150                 // check if tag is registered\r
151                 foreach (array('compiler', 'function', 'block') as $type) {\r
152                     if (isset($this->smarty->registered_plugins[$type][$tag])) {\r
153                         // if compiler function plugin call it now\r
154                         if ($type == 'compiler') {\r
155                             if (!$this->smarty->registered_plugins[$type][$tag][1]) {\r
156                                 $this->tag_nocache = true;\r
157                             } \r
158                             return call_user_func_array($this->smarty->registered_plugins[$type][$tag][0], array($args, $this));\r
159                         } \r
160                         // compile registered function or block function\r
161                         if ($type == 'function' || $type == 'block') {\r
162                             return $this->callTagCompiler('private_registered_' . $type, $args, $tag);\r
163                         } \r
164                     } \r
165                 } \r
166                 // check plugins from plugins folder\r
167                 foreach ($this->smarty->plugin_search_order as $plugin_type) {\r
168                     if ($plugin_type == 'compiler' && $this->smarty->loadPlugin('smarty_compiler_' . $tag)) {\r
169                         $plugin = 'smarty_compiler_' . $tag;\r
170                         if (is_callable($plugin)) {\r
171                             return $plugin($args, $this->smarty);\r
172                         } \r
173                         if (class_exists($plugin, false)) {\r
174                             $plugin_object = new $plugin;\r
175                             if (method_exists($plugin_object, 'compile')) {\r
176                                 return $plugin_object->compile($args, $this);\r
177                             } \r
178                         } \r
179                         throw new Exception("Plugin \"{$tag}\" not callable");\r
180                     } else {\r
181                         if ($function = $this->getPlugin($tag, $plugin_type)) {\r
182                             return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $tag, $function);\r
183                         } \r
184                     } \r
185                 } \r
186             } else {\r
187                 // compile closing tag of block function\r
188                 $base_tag = substr($tag, 0, -5); \r
189                 // check if closing tag is a registered object\r
190                 if (isset($this->smarty->registered_objects[$base_tag]) && isset($args['object_methode'])) {\r
191                     $methode = $args['object_methode'];\r
192                     unset ($args['object_methode']);\r
193                     if (in_array($methode, $this->smarty->registered_objects[$base_tag][3])) {\r
194                         return $this->callTagCompiler('private_object_block_function', $args, $tag, $methode);\r
195                     } else {\r
196                         return $this->trigger_template_error ('unallowed closing tag methode "' . $methode . '" in registered object "' . $base_tag . '"', $this->lex->taglineno);\r
197                     } \r
198                 } \r
199                 // registered block tag ?\r
200                 if (isset($this->smarty->registered_plugins['block'][$base_tag])) {\r
201                     return $this->callTagCompiler('private_registered_block', $args, $tag);\r
202                 } \r
203                 // block plugin?\r
204                 if ($function = $this->getPlugin($base_tag, 'block')) {\r
205                     return $this->callTagCompiler('private_block_plugin', $args, $tag, $function);\r
206                 } \r
207                 if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {\r
208                     $plugin = 'smarty_compiler_' . $tag;\r
209                     if (is_callable($plugin)) {\r
210                         return $plugin($args, $this->smarty);\r
211                     } \r
212                     if (class_exists($plugin, false)) {\r
213                         $plugin_object = new $plugin;\r
214                         if (method_exists($plugin_object, 'compile')) {\r
215                             return $plugin_object->compile($args, $this);\r
216                         } \r
217                     } \r
218                     throw new Exception("Plugin \"{$tag}\" not callable");\r
219                 } \r
220             } \r
221             $this->trigger_template_error ("unknown tag \"" . $tag . "\"", $this->lex->taglineno);\r
222         } \r
223     } \r
224 \r
225     /**\r
226      * lazy loads internal compile plugin for tag and calls the compile methode\r
227      * \r
228      * compile objects cached for reuse.\r
229      * class name format:  Smarty_Internal_Compile_TagName\r
230      * plugin filename format: Smarty_Internal_Tagname.php\r
231      * \r
232      * @param  $tag string tag name\r
233      * @param  $args array with tag attributes\r
234      * @param  $param1 optional parameter\r
235      * @param  $param2 optional parameter\r
236      * @param  $param3 optional parameter\r
237      * @return string compiled code\r
238      */\r
239     public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)\r
240     { \r
241         // re-use object if already exists\r
242         if (isset(self::$_tag_objects[$tag])) {\r
243             // compile this tag\r
244             return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);\r
245         } \r
246         // lazy load internal compiler plugin\r
247         $class_name = 'Smarty_Internal_Compile_' . $tag;\r
248         if ($this->smarty->loadPlugin($class_name)) {\r
249             // use plugin if found\r
250             self::$_tag_objects[$tag] = new $class_name; \r
251             // compile this tag\r
252             return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);\r
253         } \r
254         // no internal compile plugin for this tag\r
255         return false;\r
256     } \r
257 \r
258     /**\r
259      * Check for plugins and return function name\r
260      * \r
261      * @param  $pugin_name string name of plugin or function\r
262      * @param  $type string type of plugin\r
263      * @return string call name of function\r
264      */\r
265     public function getPlugin($plugin_name, $type)\r
266     {\r
267         $function = null;\r
268         if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {\r
269             if (isset($this->template->required_plugins['nocache'][$plugin_name][$type])) {\r
270                 $function = $this->template->required_plugins['nocache'][$plugin_name][$type]['function'];\r
271             } else if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {\r
272                 $this->template->required_plugins['nocache'][$plugin_name][$type] = $this->template->required_plugins['compiled'][$plugin_name][$type];\r
273                 $function = $this->template->required_plugins['nocache'][$plugin_name][$type]['function'];\r
274             } \r
275         } else {\r
276             if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {\r
277                 $function = $this->template->required_plugins['compiled'][$plugin_name][$type]['function'];\r
278             } else if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {\r
279                 $this->template->required_plugins['compiled'][$plugin_name][$type] = $this->template->required_plugins['nocache'][$plugin_name][$type];\r
280                 $function = $this->template->required_plugins['compiled'][$plugin_name][$type]['function'];\r
281             } \r
282         } \r
283         if (isset($function)) {\r
284             if ($type == 'modifier') {\r
285                 $this->template->saved_modifier[$plugin_name] = true;\r
286             } \r
287             return $function;\r
288         } \r
289         /**\r
290          * if (isset($this->template->required_plugins_call[$plugin_name][$type])) {\r
291          * if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {\r
292          * if (isset($this->template->required_plugins['compiled'][$plugin_name])) {\r
293          * $this->template->required_plugins['cache'][$plugin_name] = $this->template->required_plugins['compiled'][$plugin_name];\r
294          * } \r
295          * } else {\r
296          * if (isset($this->template->required_plugins['cache'][$plugin_name])) {\r
297          * $this->template->required_plugins['compiled'][$plugin_name] = $this->template->required_plugins['cache'][$plugin_name];\r
298          * } \r
299          * } \r
300          * if ($type == 'modifier') {\r
301          * $this->template->saved_modifier[$plugin_name] = true;\r
302          * } \r
303          * return $this->template->required_plugins_call[$plugin_name][$type];\r
304          * }\r
305          */\r
306         // loop through plugin dirs and find the plugin\r
307         $function = 'smarty_' . $type . '_' . $plugin_name;\r
308         $found = false;\r
309         foreach((array)$this->smarty->plugins_dir as $_plugin_dir) {\r
310             $file = rtrim($_plugin_dir, '/\\') . DS . $type . '.' . $plugin_name . '.php';\r
311             if (file_exists($file)) {\r
312                 // require_once($file);\r
313                 $found = true;\r
314                 break;\r
315             } \r
316         } \r
317         if ($found) {\r
318             // if (is_callable($plugin)) {\r
319             if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {\r
320                 $this->template->required_plugins['nocache'][$plugin_name][$type]['file'] = $file;\r
321                 $this->template->required_plugins['nocache'][$plugin_name][$type]['function'] = $function;\r
322             } else {\r
323                 $this->template->required_plugins['compiled'][$plugin_name][$type]['file'] = $file;\r
324                 $this->template->required_plugins['compiled'][$plugin_name][$type]['function'] = $function;\r
325             } \r
326             /**\r
327              * $this->template->required_plugins_call[$plugin_name][$type] = $plugin;\r
328              * if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {\r
329              * $this->template->required_plugins['cache'][$plugin_name]['file'] = $file;\r
330              * $this->template->required_plugins['cache'][$plugin_name]['type'] = $type;\r
331              * } else {\r
332              * $this->template->required_plugins['compiled'][$plugin_name]['file'] = $file;\r
333              * $this->template->required_plugins['compiled'][$plugin_name]['type'] = $type;\r
334              * }\r
335              */\r
336             if ($type == 'modifier') {\r
337                 $this->template->saved_modifier[$plugin_name] = true;\r
338             } \r
339             return $function;\r
340         } \r
341         if (is_callable($function)) {\r
342             // plugin function is defined in the script\r
343             return $function;\r
344         } \r
345         return false;\r
346     } \r
347     /**\r
348      * Inject inline code for nocache template sections\r
349      * \r
350      * This method gets the content of each template element from the parser.\r
351      * If the content is compiled code and it should be not cached the code is injected\r
352      * into the rendered output.\r
353      * \r
354      * @param string $content content of template element\r
355      * @param boolean $tag_nocache true if the parser detected a nocache situation\r
356      * @param boolean $is_code true if content is compiled code\r
357      * @return string content\r
358      */\r
359     public function processNocacheCode ($content, $is_code)\r
360     { \r
361         // If the template is not evaluated and we have a nocache section and or a nocache tag\r
362         if ($is_code && !empty($content)) {\r
363             // generate replacement code\r
364             if ((!$this->template->resource_object->isEvaluated || $this->template->forceNocache) && $this->template->caching && !$this->suppressNocacheProcessing &&\r
365                     ($this->nocache || $this->tag_nocache || $this->template->forceNocache == 2)) {\r
366                 $this->tag_nocache = false;\r
367                 $this->template->has_nocache_code = true;\r
368                 $_output = str_replace("'", "\'", $content);\r
369                 $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>"; \r
370                 // make sure we include modifer plugins for nocache code\r
371                 if (isset($this->template->saved_modifier)) {\r
372                     foreach ($this->template->saved_modifier as $plugin_name => $dummy) {\r
373                         if (isset($this->template->required_plugins['compiled'][$plugin_name]['modifier'])) {\r
374                             $this->template->required_plugins['nocache'][$plugin_name]['modifier'] = $this->template->required_plugins['compiled'][$plugin_name]['modifier'];\r
375                         } \r
376                     } \r
377                     $this->template->saved_modifier = null;\r
378                 } \r
379             } else {\r
380                 $_output = $content;\r
381             } \r
382         } else {\r
383             $_output = $content;\r
384         } \r
385         $this->suppressNocacheProcessing = false;\r
386         return $_output;\r
387     } \r
388     /**\r
389      * display compiler error messages without dying\r
390      * \r
391      * If parameter $args is empty it is a parser detected syntax error.\r
392      * In this case the parser is called to obtain information about expected tokens.\r
393      * \r
394      * If parameter $args contains a string this is used as error message\r
395      * \r
396      * @param  $args string individual error message or null\r
397      */\r
398     public function trigger_template_error($args = null, $line = null)\r
399     { \r
400         // get template source line which has error\r
401         if (!isset($line)) {\r
402             $line = $this->lex->line;\r
403         } \r
404         $match = preg_split("/\n/", $this->lex->data);\r
405         $error_text = 'Syntax Error in template "' . $this->template->getTemplateFilepath() . '"  on line ' . $line . ' "' . htmlspecialchars($match[$line-1]) . '" ';\r
406         if (isset($args)) {\r
407             // individual error message\r
408             $error_text .= $args;\r
409         } else {\r
410             // expected token from parser\r
411             foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {\r
412                 $exp_token = $this->parser->yyTokenName[$token];\r
413                 if (isset($this->lex->smarty_token_names[$exp_token])) {\r
414                     // token type from lexer\r
415                     $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"';\r
416                 } else {\r
417                     // otherwise internal token name\r
418                     $expect[] = $this->parser->yyTokenName[$token];\r
419                 } \r
420             } \r
421             // output parser error message\r
422             $error_text .= ' - Unexpected "' . $this->lex->value . '", expected one of: ' . implode(' , ', $expect);\r
423         } \r
424         throw new Exception($error_text);\r
425     } \r
426\r
427 \r
428 ?>