Содержимое файла | Последнее изменение | Открыть журнал | RSS
Редакция | Автор | № строки | Строка |
---|---|---|---|
304 | alex-w | 1 | <?php |
2 | /** |
||
3 | * Smarty Internal Plugin Smarty Template Compiler Base |
||
4 | * |
||
5 | * This file contains the basic classes and methodes for compiling Smarty templates with lexer/parser |
||
6 | * |
||
7 | * @package Smarty |
||
8 | * @subpackage Compiler |
||
9 | * @author Uwe Tews |
||
10 | */ |
||
11 | /** |
||
12 | * Main compiler class |
||
13 | */ |
||
14 | class Smarty_Internal_TemplateCompilerBase { |
||
15 | // compile tag objects |
||
16 | static $_tag_objects = array(); |
||
17 | // tag stack |
||
18 | public $_tag_stack = array(); |
||
19 | // current template |
||
20 | public $template = null; |
||
21 | |||
22 | /** |
||
23 | * Initialize compiler |
||
24 | */ |
||
25 | public function __construct() |
||
26 | { |
||
27 | } |
||
28 | // abstract function doCompile($_content); |
||
29 | /** |
||
30 | * Methode to compile a Smarty template |
||
31 | * |
||
32 | * @param $template template object to compile |
||
33 | * @return bool true if compiling succeeded, false if it failed |
||
34 | */ |
||
35 | public function compileTemplate($template) |
||
36 | { |
||
37 | /* here is where the compiling takes place. Smarty |
||
38 | tags in the templates are replaces with PHP code, |
||
39 | then written to compiled files. */ |
||
40 | if (!is_object($template->cacher_object)) { |
||
41 | $this->smarty->loadPlugin($template->cacher_class); |
||
42 | $template->cacher_object = new $template->cacher_class($this->smarty); |
||
43 | } |
||
44 | // flag for nochache sections |
||
45 | $this->nocache = false; |
||
46 | $this->tag_nocache = false; |
||
47 | // assume successfull compiling |
||
48 | $this->compile_error = false; |
||
49 | // save template object in compiler class |
||
50 | $this->template = $template; |
||
51 | // template header code |
||
52 | $template_header = ''; |
||
53 | if (!$template->suppressHeader) { |
||
54 | $template_header .= "<?php /* Smarty version " . Smarty::$_version . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n"; |
||
55 | $template_header .= " compiled from \"" . $this->template->getTemplateFilepath() . "\" */ ?>\n"; |
||
56 | } |
||
57 | |||
58 | do { |
||
59 | // flag for aborting current and start recompile |
||
60 | $this->abort_and_recompile = false; |
||
61 | // get template source |
||
62 | $_content = $template->getTemplateSource(); |
||
63 | // run prefilter if required |
||
64 | if (isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) { |
||
65 | $_content = $this->smarty->filter_handler->execute('pre', $_content); |
||
66 | } |
||
67 | // on empty template just return header |
||
68 | if ($_content == '') { |
||
69 | $template->compiled_template = $template->createPropertyHeader() . $template_header; |
||
70 | return true; |
||
71 | } |
||
72 | // init cacher plugin |
||
73 | $template->cacher_object->initCacher($this); |
||
74 | // call compiler |
||
75 | $_compiled_code = $this->doCompile($_content); |
||
76 | } while ($this->abort_and_recompile); |
||
77 | |||
78 | if (!$this->compile_error) { |
||
79 | // close cacher and return compiled template |
||
80 | $template->compiled_template = $template->createPropertyHeader() . $template_header . $template->cacher_object->closeCacher($this, $_compiled_code); |
||
81 | // run postfilter if required |
||
82 | if (isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) { |
||
83 | $template->compiled_template = $this->smarty->filter_handler->execute('post', $template->compiled_template); |
||
84 | } |
||
85 | return true; |
||
86 | } else { |
||
87 | // compilation error |
||
88 | return false; |
||
89 | } |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Compile Tag |
||
94 | * |
||
95 | * This is a call back from the lexer/parser |
||
96 | * It executes the required compile plugin for the Smarty tag |
||
97 | * |
||
98 | * @param string $tag tag name |
||
99 | * @param array $args array with tag attributes |
||
100 | * @return string compiled code |
||
101 | */ |
||
102 | public function compileTag($tag, $args) |
||
103 | { |
||
104 | // $args contains the attributes parsed and compiled by the lexer/parser |
||
105 | // assume that tag does compile into code, but creates no HTML output |
||
106 | $this->has_code = true; |
||
107 | $this->has_output = false; |
||
108 | // compile the smarty tag (required compile classes to compile the tag are autoloaded) |
||
109 | if (($_output = $this->$tag($args, $this)) === false) { |
||
110 | if (isset($this->smarty->template_functions[$tag])) { |
||
111 | // template defined by {template} tag |
||
112 | $args['name'] = $tag; |
||
113 | $tag = 'internal_function_call'; |
||
114 | $_output = $this->$tag($args, $this); |
||
115 | } |
||
116 | } |
||
117 | if ($_output !== false) { |
||
118 | if ($_output !== true) { |
||
119 | // did we get compiled code |
||
120 | if ($this->has_code) { |
||
121 | // Does it create output? |
||
122 | if ($this->has_output) { |
||
123 | $_output .= "\n"; |
||
124 | } |
||
125 | // return compiled code |
||
126 | return $_output; |
||
127 | } |
||
128 | } |
||
129 | // tag did not produce compiled code |
||
130 | return ''; |
||
131 | } else { |
||
132 | // not an internal compiler tag |
||
133 | // check if tag is a registered object |
||
134 | if (isset($this->smarty->registered_objects[$tag]) && isset($args['object_methode'])) { |
||
135 | $methode = $args['object_methode']; |
||
136 | unset ($args['object_methode']); |
||
137 | if (!in_array($methode, $this->smarty->registered_objects[$tag][3]) && |
||
138 | (empty($this->smarty->registered_objects[$tag][1]) || in_array($methode, $this->smarty->registered_objects[$tag][1]))) { |
||
139 | return $this->object_function($args, $tag, $methode, $this); |
||
140 | } elseif (in_array($methode, $this->smarty->registered_objects[$tag][3])) { |
||
141 | return $this->object_block_function($args, $tag, $methode, $this); |
||
142 | } else { |
||
143 | return $this->trigger_template_error ('unallowed methode "' . $methode . '" in registered object "' . $tag . '"'); |
||
144 | } |
||
145 | } |
||
146 | // check if tag is registered or is Smarty plugin |
||
147 | $this->smarty->plugin_handler->loadSmartyPlugin($tag, $this->smarty->plugin_search_order); |
||
148 | if (isset($this->smarty->registered_plugins[$tag])) { |
||
149 | // if compiler function plugin call it now |
||
150 | if ($this->smarty->registered_plugins[$tag][0] == 'compiler') { |
||
151 | if (!$this->smarty->registered_plugins[$tag][2]) { |
||
152 | $this->tag_nocache = true; |
||
153 | } |
||
154 | return call_user_func_array($this->smarty->registered_plugins[$tag][1], array($args, $this)); |
||
155 | } |
||
156 | // compile function or block plugin |
||
157 | $plugin_type = $this->smarty->registered_plugins[$tag][0] . '_plugin'; |
||
158 | return $this->$plugin_type($args, $tag, $this); |
||
159 | } |
||
160 | // compile closing tag of block function |
||
161 | if (strlen($tag) > 5 && substr_compare($tag, 'close', -5, 5) == 0) { |
||
162 | $base_tag = substr($tag, 0, -5); |
||
163 | // check if closing tag is a registered object |
||
164 | if (isset($this->smarty->registered_objects[$base_tag]) && isset($args['object_methode'])) { |
||
165 | $methode = $args['object_methode']; |
||
166 | unset ($args['object_methode']); |
||
167 | if (in_array($methode, $this->smarty->registered_objects[$base_tag][3])) { |
||
168 | return $this->object_block_function($args, $tag, $methode, $this); |
||
169 | } else { |
||
170 | return $this->trigger_template_error ('unallowed closing tag methode "' . $methode . '" in registered object "' . $base_tag . '"'); |
||
171 | } |
||
172 | } |
||
173 | // plugin ? |
||
174 | if (isset($this->smarty->registered_plugins[$base_tag]) && $this->smarty->registered_plugins[$base_tag][0] == 'block') { |
||
175 | return $this->block_plugin($args, $tag, $this); |
||
176 | } |
||
177 | } |
||
178 | $this->trigger_template_error ("unknown tag \"" . $tag . "\""); |
||
179 | } |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * lazy loads internal compile plugin for tag and calls the compile methode |
||
184 | * |
||
185 | * compile objects cached for reuse. |
||
186 | * class name format: Smarty_Internal_Compile_TagName |
||
187 | * plugin filename format: internal.compile_tagname.php |
||
188 | * |
||
189 | * @param $tag string tag name |
||
190 | * @param $args array with tag attributes |
||
191 | * @return string compiled code |
||
192 | */ |
||
193 | public function __call($name, $args) |
||
194 | { |
||
195 | // re-use object if already exists |
||
196 | if (isset(self::$_tag_objects[$name])) { |
||
197 | // compile this tag |
||
198 | return call_user_func_array(array(self::$_tag_objects[$name], 'compile'), $args); |
||
199 | } |
||
200 | // lazy load internal compiler plugin |
||
201 | $class_name = "Smarty_Internal_Compile_{$name}"; |
||
202 | if ($this->smarty->loadPlugin($class_name)) { |
||
203 | // use plugin if found |
||
204 | self::$_tag_objects[$name] = new $class_name; |
||
205 | // compile this tag |
||
206 | return call_user_func_array(array(self::$_tag_objects[$name], 'compile'), $args); |
||
207 | } |
||
208 | // no internal compile plugin for this tag |
||
209 | return false; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * display compiler error messages without dying |
||
214 | * |
||
215 | * If parameter $args is empty it is a parser detected syntax error. |
||
216 | * In this case the parser is called to obtain information about expected tokens. |
||
217 | * |
||
218 | * If parameter $args contains a string this is used as error message |
||
219 | * |
||
220 | * @todo output exact position of parse error in source line |
||
221 | * @param $args string individual error message or null |
||
222 | */ |
||
223 | public function trigger_template_error($args = null) |
||
224 | { |
||
225 | $this->lex = Smarty_Internal_Templatelexer::instance(); |
||
226 | $this->parser = Smarty_Internal_Templateparser::instance(); |
||
227 | // get template source line which has error |
||
228 | $line = $this->lex->line; |
||
229 | if (isset($args)) { |
||
230 | // $line--; |
||
231 | } |
||
232 | $match = preg_split("/\n/", $this->lex->data); |
||
233 | $error_text = 'Syntax Error in template "' . $this->template->getTemplateFilepath() . '" on line ' . $line . ' "' . $match[$line-1] . '" '; |
||
234 | |||
235 | if (isset($args)) { |
||
236 | // individual error message |
||
237 | $error_text .= $args; |
||
238 | } else { |
||
239 | // expected token from parser |
||
240 | foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) { |
||
241 | $exp_token = $this->parser->yyTokenName[$token]; |
||
242 | if (isset($this->lex->smarty_token_names[$exp_token])) { |
||
243 | // token type from lexer |
||
244 | $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"'; |
||
245 | } else { |
||
246 | // otherwise internal token name |
||
247 | $expect[] = $this->parser->yyTokenName[$token]; |
||
248 | } |
||
249 | } |
||
250 | // output parser error message |
||
251 | $error_text .= ' - Unexpected "' . $this->lex->value . '", expected one of: ' . implode(' , ', $expect); |
||
252 | } |
||
253 | throw new Exception($error_text); |
||
254 | // set error flag |
||
255 | $this->compile_error = true; |
||
256 | } |
||
257 | } |
||
258 | |||
259 | ?> |