94b47c30 |
1 | <?php |
4b4abf93 |
2 | |
94b47c30 |
3 | /** |
4 | * Copyright 2003, Paul James |
94b47c30 |
5 | * |
6 | * This file contains some methods from the Smarty templating engine version |
7 | * 2.5.0 by Monte Ohrt <monte@ispi.net> and Andrei Zmievski <andrei@php.net>. |
8 | * |
94b47c30 |
9 | * The SquirrelMail (Foowd) template implementation. |
10 | * Derived from the foowd template implementation and adapted |
11 | * for squirrelmail |
47ccfad4 |
12 | * @copyright © 2005-2006 The SquirrelMail Project Team |
4b4abf93 |
13 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
9f7d2fa9 |
14 | * @version $Id$ |
e045ce66 |
15 | * @package squirrelmail |
94b47c30 |
16 | */ |
17 | |
18 | /** |
19 | * The SquirrelMail (Foowd) template class. |
20 | * |
21 | * Basic template class for capturing values and pluging them into a template. |
22 | * This class uses a similar API to Smarty. |
23 | * |
24 | * @author Paul James |
4b4abf93 |
25 | * @author Monte Ohrt <monte at ispi.net> |
26 | * @author Andrei Zmievski <andrei at php.net> |
9f7d2fa9 |
27 | * @package squirrelmail |
94b47c30 |
28 | */ |
29 | class Template |
30 | { |
31 | /** |
32 | * The templates values array |
33 | * |
34 | * @var array |
35 | */ |
36 | var $values = array(); |
37 | |
38 | /** |
39 | * The template directory to use |
40 | * |
41 | * @var string |
42 | */ |
49ea2d20 |
43 | var $template_dir = ''; |
94b47c30 |
44 | |
7186732c |
45 | /** |
46 | * The default template directory |
47 | * |
48 | * @var string |
49 | */ |
50 | var $default_template_dir = 'templates/default/'; |
51 | |
44452136 |
52 | /** |
53 | * Template files provided by this template set |
7bc3ddff |
54 | * |
44452136 |
55 | * @var array |
56 | */ |
57 | var $templates_provided = array(); |
7bc3ddff |
58 | |
44452136 |
59 | /** |
60 | * Javascript files required by the template |
7bc3ddff |
61 | * |
44452136 |
62 | * @var array |
63 | */ |
64 | var $required_js_files = array(); |
7bc3ddff |
65 | |
44452136 |
66 | /** |
67 | * Javascript files provided by the template. If a JS file is required, but |
7bc3ddff |
68 | * not provided, the js file by the same name will be included from the |
44452136 |
69 | * default template directory. |
7bc3ddff |
70 | * |
44452136 |
71 | * @var array |
72 | */ |
73 | var $provided_js_files = array(); |
7bc3ddff |
74 | |
3cecf1cd |
75 | /** |
76 | * Additional stylesheets provided by the template. This allows template |
b28e7303 |
77 | * authors to provide additional CSS sheets to templates while using the |
78 | * default template set stylesheet for other definitions. |
3cecf1cd |
79 | */ |
7bc3ddff |
80 | var $additional_css_sheets = array(); |
81 | |
4407b2e4 |
82 | /** |
83 | * Constructor |
84 | * |
85 | * @param string $sTplDir where the template set is located |
86 | */ |
87 | function Template($sTplDir) { |
88 | $this->template_dir = $sTplDir; |
7bc3ddff |
89 | |
4407b2e4 |
90 | // Pull in the tempalte config file |
91 | if (!file_exists($this->template_dir . 'template.php')) { |
92 | trigger_error('No template.php could be found in the requested template directory ("'.$this->template_dir.'")', E_USER_ERROR); |
93 | } else { |
94 | include ($this->template_dir . 'template.php'); |
95 | $this->templates_provided = is_array($templates_provided) ? $templates_provided : array(); |
96 | $this->required_js_files = is_array($required_js_files) ? $required_js_files : array(); |
97 | $this->provided_js_files = is_array($provided_js_files) ? $provided_js_files: array(); |
98 | $this->additional_css_sheets = is_array($additional_css_sheets) ? $additional_css_sheets : array(); |
99 | } |
94b47c30 |
100 | } |
101 | |
102 | |
103 | /** |
104 | * Assigns values to template variables |
105 | * |
106 | * @param array|string $tpl_var the template variable name(s) |
107 | * @param mixed $value the value to assign |
108 | */ |
109 | function assign($tpl_var, $value = NULL) { |
110 | if (is_array($tpl_var)) |
111 | { |
112 | foreach ($tpl_var as $key => $val) |
113 | { |
114 | if ($key != '') |
115 | $this->values[$key] = $val; |
116 | } |
117 | } |
118 | else |
119 | { |
120 | if ($tpl_var != '') |
121 | $this->values[$tpl_var] = $value; |
122 | } |
123 | } |
124 | |
125 | /** |
126 | * Assigns values to template variables by reference |
127 | * |
128 | * @param string $tpl_var the template variable name |
129 | * @param mixed $value the referenced value to assign |
130 | */ |
131 | function assign_by_ref($tpl_var, &$value) |
132 | { |
133 | if ($tpl_var != '') |
134 | $this->values[$tpl_var] = &$value; |
135 | } |
136 | |
137 | /** |
138 | * Appends values to template variables |
139 | * |
140 | * @param array|string $tpl_var the template variable name(s) |
141 | * @param mixed $value the value to append |
b28e7303 |
142 | * @param boolean $merge when $value is given as an array, |
143 | * this indicates whether or not that |
144 | * array itself should be appended as |
145 | * a new template variable value or if |
146 | * that array's values should be merged |
147 | * into the existing array of template |
148 | * variable values |
94b47c30 |
149 | */ |
150 | function append($tpl_var, $value = NULL, $merge = FALSE) |
151 | { |
152 | if (is_array($tpl_var)) |
153 | { |
b28e7303 |
154 | //FIXME: $tpl_var is supposed to be a list of template var names, |
155 | // so we should be looking at the values NOT the keys! |
94b47c30 |
156 | foreach ($tpl_var as $_key => $_val) |
157 | { |
158 | if ($_key != '') |
159 | { |
160 | if(isset($this->values[$_key]) && !is_array($this->values[$_key])) |
161 | settype($this->values[$_key],'array'); |
162 | |
b28e7303 |
163 | //FIXME: we should be iterating the $value array here not the values of the |
164 | // list of template variable names! I think this is totally broken |
165 | // This might just be a matter of needing to clarify the method's API; |
166 | // values may have been meant to be passed in $tpl_var in the case that |
167 | // $tpl_var is an array. Ugly and non-intuitive. |
168 | // PROPOSAL: API should be as such: |
169 | // if (is_string($tpl_var)) then $values are added/merged as already done |
170 | // if (is_array($tpl_var)) then $values is required to be an array whose |
171 | // keys must match up with $tpl_var keys and |
172 | // whose values are then what is added to |
173 | // each template variable value (array or |
174 | // strings, doesn't matter) |
94b47c30 |
175 | if($merge && is_array($_val)) |
176 | { |
177 | foreach($_val as $_mkey => $_mval) |
178 | $this->values[$_key][$_mkey] = $_mval; |
179 | } |
180 | else |
181 | $this->values[$_key][] = $_val; |
182 | } |
183 | } |
184 | } |
185 | else |
186 | { |
187 | if ($tpl_var != '' && isset($value)) |
188 | { |
189 | if(isset($this->values[$tpl_var]) && !is_array($this->values[$tpl_var])) |
190 | settype($this->values[$tpl_var],'array'); |
191 | |
192 | if($merge && is_array($value)) |
193 | { |
194 | foreach($value as $_mkey => $_mval) |
195 | $this->values[$tpl_var][$_mkey] = $_mval; |
196 | } |
197 | else |
198 | $this->values[$tpl_var][] = $value; |
199 | } |
200 | } |
201 | } |
202 | |
203 | /** |
204 | * Appends values to template variables by reference |
205 | * |
206 | * @param string $tpl_var the template variable name |
207 | * @param mixed $value the referenced value to append |
b28e7303 |
208 | * @param boolean $merge when $value is given as an array, |
209 | * this indicates whether or not that |
210 | * array itself should be appended as |
211 | * a new template variable value or if |
212 | * that array's values should be merged |
213 | * into the existing array of template |
214 | * variable values |
94b47c30 |
215 | */ |
216 | function append_by_ref($tpl_var, &$value, $merge = FALSE) |
217 | { |
218 | if ($tpl_var != '' && isset($value)) |
219 | { |
220 | if(!@is_array($this->values[$tpl_var])) |
221 | settype($this->values[$tpl_var],'array'); |
222 | |
223 | if ($merge && is_array($value)) |
224 | { |
225 | foreach($value as $_key => $_val) |
226 | $this->values[$tpl_var][$_key] = &$value[$_key]; |
227 | } |
228 | else |
229 | $this->values[$tpl_var][] = &$value; |
230 | } |
231 | } |
232 | |
7186732c |
233 | |
234 | /** |
235 | * |
236 | * Return the relative template directory path for this template set. |
237 | * |
238 | * @return string The relative path to the template directory based |
239 | * from the main SquirrelMail directory (SM_PATH). |
240 | * |
241 | */ |
242 | function get_template_file_directory() { |
243 | |
244 | //FIXME: temporarily parse off SM_PATH from the template dir class attribute until we can change the entire template subsystem such that the template dir is derived internally in this class from the template ID/name/attributes |
245 | return substr($this->template_dir, strlen(SM_PATH)); |
246 | return $this->template_dir; |
247 | |
4407b2e4 |
248 | } |
94b47c30 |
249 | |
7186732c |
250 | |
251 | /** |
252 | * |
253 | * Return the relative template directory path for the DEFAULT template set. |
254 | * |
255 | * @return string The relative path to the default template directory based |
256 | * from the main SquirrelMail directory (SM_PATH). |
257 | * |
258 | */ |
259 | function get_default_template_file_directory() { |
260 | |
261 | return $this->default_template_dir; |
262 | |
263 | } |
264 | |
265 | |
266 | /** |
267 | * |
268 | * Find the right template file. |
269 | * |
270 | * Templates are expected to be found in the template set directory |
271 | * (for example SM_PATH/templates/<template name>/) or, in the case |
272 | * of plugin templates, in a plugin directory in the template set |
273 | * directory (for example, |
274 | * SM_PATH/templates/<template name>/plugins/<plugin name>/) *OR* in |
275 | * a template directory in the plugin as a fallback (for example, |
276 | * SM_PATH/plugins/<plugin name>/templates/<template name>/). If |
277 | * the correct file is not found for the current template set, a |
278 | * default template is loaded, which is expected to be found in the |
279 | * default template directory (for example, SM_PATH/templates/default/) |
280 | * or for plugins, in a plugin directory in the default template set |
281 | * (for example, SM_PATH/templates/default/plugins/<plugin name>/), |
282 | * *OR* in a default template directory in the plugin as a fallback |
283 | * (for example, SM_PATH/plugins/<plugin name>/templates/default/). |
284 | * |
285 | * @param string $filename The name of the template file, |
286 | * possibly prefaced with |
287 | * "plugins/<plugin name>/" |
288 | * indicating that it is a plugin |
289 | * template. |
290 | * |
291 | * @return string The full path to the template file; if |
292 | * not found, an empty string. The caller |
293 | * is responsible for throwing erros or |
294 | * other actions if template file is not found. |
295 | * |
296 | */ |
297 | function get_template_file_path($filename) { |
298 | |
299 | // is the template found in the normal template directory? |
300 | // |
301 | $filepath = SM_PATH . $this->get_template_file_directory() . $filename; |
302 | if (!file_exists($filepath)) { |
303 | |
304 | // no, so now we have to get the default template... |
305 | // however, in the case of a plugin template, let's |
306 | // give one more try to find the right template as |
307 | // provided by the plugin |
308 | // |
309 | if (strpos($filename, 'plugins/') === 0) { |
310 | |
311 | $plugin_name = substr($filename, 8, strpos($filename, '/', 8) - 8); |
312 | $filepath = SM_PATH . 'plugins/' . $plugin_name . '/' |
313 | . $this->get_template_file_directory() |
314 | . substr($filename, strlen($plugin_name) + 9); |
315 | |
316 | // no go, we have to get the default template |
317 | // from the plugin |
318 | // |
319 | if (!file_exists($filepath)) { |
320 | |
321 | $filepath = SM_PATH . 'plugins/' . $plugin_name . '/' |
322 | . $this->get_default_template_file_directory() |
323 | . substr($filename, strlen($plugin_name) + 9); |
324 | |
325 | // no dice whatsoever, return empty string |
326 | // |
327 | if (!file_exists($filepath)) { |
328 | $filepath = ''; |
329 | } |
330 | |
331 | } |
332 | |
333 | |
334 | // get default template for non-plugin templates |
335 | // |
336 | } else { |
337 | |
338 | $filepath = SM_PATH . $this->get_default_template_file_directory() |
339 | . $filename; |
340 | |
341 | // no dice whatsoever, return empty string |
342 | // |
343 | if (!file_exists($filepath)) { |
344 | $filepath = ''; |
345 | } |
346 | |
347 | } |
348 | |
349 | } |
350 | |
351 | return $filepath; |
352 | |
353 | } |
354 | |
355 | |
356 | /** |
357 | * Display the template |
358 | * |
359 | * @param string $file The template file to use |
360 | */ |
361 | function display($file) |
362 | { |
363 | // Pull in our config file |
364 | $t = &$this->values; // place values array directly in scope |
365 | |
366 | // Get right template file |
367 | $template = $this->get_template_file_path($file); |
368 | if (empty($template)) { |
369 | trigger_error('The template "'.htmlspecialchars($file).'" could not be displayed!', E_USER_ERROR); |
370 | } else { |
371 | ob_start(); |
372 | include($template); |
373 | ob_end_flush(); |
374 | } |
375 | } |
376 | |
377 | /** |
378 | * Return the results of applying a template. |
379 | * |
380 | * @param string $file The template file to use |
381 | * @return string A string of the results |
382 | */ |
383 | function fetch($file) { |
384 | $t = &$this->values; // place values array directly in scope |
385 | |
386 | // Get right template file |
387 | $template = $this->get_template_file_path($file); |
388 | if (!file_exists($template)) { |
389 | trigger_error('The template "'.htmlspecialchars($file).'" could not be fetched!', E_USER_ERROR); |
390 | } else { |
391 | ob_start(); |
392 | include($template); |
393 | $contents = ob_get_contents(); |
394 | ob_end_clean(); |
395 | return $contents; |
396 | } |
4407b2e4 |
397 | } |
94b47c30 |
398 | |
44452136 |
399 | /** |
7bc3ddff |
400 | * Return paths to the required javascript files. Used when generating page |
44452136 |
401 | * header. |
7bc3ddff |
402 | * |
44452136 |
403 | * @return array $paths |
404 | */ |
405 | function getJavascriptIncludes () { |
406 | $paths = array(); |
407 | foreach ($this->required_js_files as $file) { |
408 | if (in_array($file, $this->provided_js_files)) |
409 | $paths[] = './'.$this->template_dir.'js/'.basename($file); |
410 | else $paths[] = SM_PATH .'templates/default/js/'.basename($file); |
411 | } |
7bc3ddff |
412 | |
44452136 |
413 | return $paths; |
414 | } |
3cecf1cd |
415 | |
416 | /** |
417 | * Return any additional stylsheets provided by the template. Used when |
418 | * generating page headers. |
7bc3ddff |
419 | * |
3cecf1cd |
420 | * @return array $paths |
421 | */ |
422 | function getAdditionalStyleSheets () { |
423 | $paths = array(); |
424 | foreach ($this->additional_css_sheets as $css) { |
425 | $css = basename($css); |
426 | if (strtolower($css) == 'stylesheet.tpl') { |
427 | continue; |
428 | } |
429 | $paths[] = $css; |
430 | } |
431 | return $paths; |
432 | } |
94b47c30 |
433 | } |