merge revisions i missed... hopefully not breaking things - did not check every change.
[phpbb.git] / phpBB / includes / template.php
blob814d6d2e505bed7d656000fa0b1f15698012a0a7
1 <?php
2 /**
4 * @package phpBB3
5 * @version $Id$
6 * @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
12 * @ignore
14 if (!defined('IN_PHPBB'))
16 exit;
19 /**
20 * Base Template class.
21 * @package phpBB3
23 class template
25 /** variable that holds all the data we'll be substituting into
26 * the compiled templates. Takes form:
27 * --> $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value
28 * if it's a root-level variable, it'll be like this:
29 * --> $this->_tpldata[.][0][varname] == value
31 private $_tpldata = array('.' => array(0 => array()));
32 private $_rootref;
34 // Root dir and hash of filenames for each template handle.
35 private $root = '';
36 public $cachepath = '';
37 public $files = array();
38 public $filename = array();
40 /**
41 * Set template location
42 * @access public
44 public function set_template()
46 global $user;
48 if (file_exists(PHPBB_ROOT_PATH . 'styles/' . $user->theme['template_path'] . '/template'))
50 $this->root = PHPBB_ROOT_PATH . 'styles/' . $user->theme['template_path'] . '/template';
51 $this->cachepath = PHPBB_ROOT_PATH . 'cache/tpl_' . $user->theme['template_path'] . '_';
53 else
55 trigger_error('Template path could not be found: styles/' . $user->theme['template_path'] . '/template', E_USER_ERROR);
58 $this->_rootref = &$this->_tpldata['.'][0];
60 return true;
63 /**
64 * Set custom template location (able to use directory outside of phpBB)
65 * @access public
67 public function set_custom_template($template_path, $template_name)
69 $this->root = $template_path;
70 $this->cachepath = PHPBB_ROOT_PATH . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_';
72 return true;
75 /**
76 * Sets the template filenames for handles. $filename_array
77 * should be a hash of handle => filename pairs.
78 * @access public
80 public function set_filenames(array $filename_array)
82 foreach ($filename_array as $handle => $filename)
84 if (empty($filename))
86 trigger_error("template->set_filenames: Empty filename specified for $handle", E_USER_ERROR);
89 $this->filename[$handle] = $filename;
90 $this->files[$handle] = $this->root . '/' . $filename;
93 return true;
96 /**
97 * Destroy template data set
98 * @access public
100 function __destruct()
102 $this->_tpldata = array('.' => array(0 => array()));
106 * Reset/empty complete block
107 * @access public
109 public function destroy_block_vars($blockname)
111 if (strpos($blockname, '.') !== false)
113 // Nested block.
114 $blocks = explode('.', $blockname);
115 $blockcount = sizeof($blocks) - 1;
117 $str = &$this->_tpldata;
118 for ($i = 0; $i < $blockcount; $i++)
120 $str = &$str[$blocks[$i]];
121 $str = &$str[sizeof($str) - 1];
124 unset($str[$blocks[$blockcount]]);
126 else
128 // Top-level block.
129 unset($this->_tpldata[$blockname]);
132 return true;
136 * Display handle
137 * @access public
139 public function display($handle, $include_once = true)
141 global $user, $phpbb_hook;
143 if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once))
145 if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
147 return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
151 /* if (defined('IN_ERROR_HANDLER'))
153 if ((E_NOTICE & error_reporting()) == E_NOTICE)
155 //error_reporting(error_reporting() ^ E_NOTICE);
159 $_tpldata = &$this->_tpldata;
160 $_rootref = &$this->_rootref;
161 $_lang = &$user->lang;
163 // These _are_ used the included files.
164 $_tpldata; $_rootref; $_lang;
166 if (($filename = $this->_tpl_load($handle)) !== false)
168 ($include_once) ? include_once($filename) : include($filename);
170 else if (($code = $this->_tpl_eval($handle)) !== false)
172 $code = ' ?> ' . $code . ' <?php ';
173 eval($code);
175 else
177 // if we could not eval AND the file exists, something horrific has occured
178 return false;
181 return true;
185 * Display the handle and assign the output to a template variable or return the compiled result.
186 * @access public
188 public function assign_display($handle, $template_var = '', $return_content = true, $include_once = false)
190 ob_start();
191 $this->display($handle, $include_once);
192 $contents = ob_get_clean();
194 if ($return_content)
196 return $contents;
199 $this->assign_var($template_var, $contents);
201 return true;
205 * Load a compiled template if possible, if not, recompile it
206 * @access private
208 private function _tpl_load(&$handle)
210 global $config;
212 $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . PHP_EXT;
214 $recompile = (($config['load_tplcompile'] && @filemtime($filename) < filemtime($this->files[$handle])) || !file_exists($filename) || @filesize($filename) === 0) ? true : false;
216 // Recompile page if the original template is newer, otherwise load the compiled version
217 if ($recompile)
219 if (!class_exists('template_compile'))
221 include(PHPBB_ROOT_PATH . 'includes/functions_template.' . PHP_EXT);
224 $compile = new template_compile($this);
226 // If we don't have a file assigned to this handle, die.
227 if (!isset($this->files[$handle]))
229 trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR);
232 if ($compile->_tpl_load_file($handle) === false)
234 return false;
238 return $filename;
242 * This code should only run when some high level error prevents us from writing to the cache.
243 * @access private
245 private function _tpl_eval(&$handle)
247 // global $user, $config;
249 if (!class_exists('template_compile'))
251 include(PHPBB_ROOT_PATH . 'includes/functions_template.' . PHP_EXT);
254 $compile = new template_compile($this);
256 // If we don't have a file assigned to this handle, die.
257 if (!isset($this->files[$handle]))
259 trigger_error("template->_tpl_eval(): No file specified for handle $handle", E_USER_ERROR);
262 if (($code = $compile->_tpl_gen_src($handle)) === false)
264 return false;
267 return $code;
271 * Assign key variable pairs from an array
272 * @access public
274 public function assign_vars(array $vararray)
276 foreach ($vararray as $key => $val)
278 $this->_rootref[$key] = $val;
281 return true;
285 * Assign a single variable to a single key
286 * @access public
288 public function assign_var($varname, $varval)
290 $this->_rootref[$varname] = $varval;
292 return true;
296 * Assign key variable pairs from an array to a specified block
297 * @access public
299 public function assign_block_vars($blockname, array $vararray)
301 if (strpos($blockname, '.') !== false)
303 // Nested block.
304 $blocks = explode('.', $blockname);
305 $blockcount = sizeof($blocks) - 1;
307 $str = &$this->_tpldata;
308 for ($i = 0; $i < $blockcount; $i++)
310 $str = &$str[$blocks[$i]];
311 $str = &$str[sizeof($str) - 1];
314 $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0;
315 $vararray['S_ROW_COUNT'] = $s_row_count;
317 // Assign S_FIRST_ROW
318 if (!$s_row_count)
320 $vararray['S_FIRST_ROW'] = true;
323 // Now the tricky part, we always assign S_LAST_ROW and remove the entry before
324 // This is much more clever than going through the complete template data on display (phew)
325 $vararray['S_LAST_ROW'] = true;
326 if ($s_row_count > 0)
328 unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']);
331 // Now we add the block that we're actually assigning to.
332 // We're adding a new iteration to this block with the given
333 // variable assignments.
334 $str[$blocks[$blockcount]][] = $vararray;
336 else
338 // Top-level block.
339 $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0;
340 $vararray['S_ROW_COUNT'] = $s_row_count;
342 // Assign S_FIRST_ROW
343 if (!$s_row_count)
345 $vararray['S_FIRST_ROW'] = true;
348 // We always assign S_LAST_ROW and remove the entry before
349 $vararray['S_LAST_ROW'] = true;
350 if ($s_row_count > 0)
352 unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']);
355 // Add a new iteration to this block with the variable assignments we were given.
356 $this->_tpldata[$blockname][] = $vararray;
359 return true;
363 * Change already assigned key variable pair (one-dimensional - single loop entry)
365 * An example of how to use this function:
366 * {@example alter_block_array.php}
368 * @param string $blockname the blockname, for example 'loop'
369 * @param array $vararray the var array to insert/add or merge
370 * @param mixed $key Key to search for
372 * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
374 * int: Position [the position to change or insert at directly given]
376 * If key is false the position is set to 0
377 * If key is true the position is set to the last entry
379 * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
381 * If insert, the vararray is inserted at the given position (position counting from zero).
382 * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value).
384 * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
385 * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
387 * @return bool false on error, true on success
388 * @access public
390 public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert')
392 if (strpos($blockname, '.') !== false)
394 // Nested blocks are not supported
395 return false;
398 // Change key to zero (change first position) if false and to last position if true
399 if ($key === false || $key === true)
401 $key = ($key === false) ? 0 : sizeof($this->_tpldata[$blockname]);
404 // Get correct position if array given
405 if (is_array($key))
407 // Search array to get correct position
408 list($search_key, $search_value) = @each($key);
410 $key = NULL;
411 foreach ($this->_tpldata[$blockname] as $i => $val_ary)
413 if ($val_ary[$search_key] === $search_value)
415 $key = $i;
416 break;
420 // key/value pair not found
421 if ($key === NULL)
423 return false;
427 // Insert Block
428 if ($mode == 'insert')
430 // Make sure we are not exceeding the last iteration
431 if ($key >= sizeof($this->_tpldata[$blockname]))
433 $key = sizeof($this->_tpldata[$blockname]);
434 unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']);
435 $vararray['S_LAST_ROW'] = true;
437 else if ($key === 0)
439 unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']);
440 $vararray['S_FIRST_ROW'] = true;
443 // Re-position template blocks
444 for ($i = sizeof($this->_tpldata[$blockname]); $i > $key; $i--)
446 $this->_tpldata[$blockname][$i] = $this->_tpldata[$blockname][$i-1];
447 $this->_tpldata[$blockname][$i]['S_ROW_COUNT'] = $i;
450 // Insert vararray at given position
451 $vararray['S_ROW_COUNT'] = $key;
452 $this->_tpldata[$blockname][$key] = $vararray;
454 return true;
457 // Which block to change?
458 if ($mode == 'change')
460 if ($key == sizeof($this->_tpldata[$blockname]))
462 $key--;
465 $this->_tpldata[$blockname][$key] = array_merge($this->_tpldata[$blockname][$key], $vararray);
466 return true;
469 return false;
473 * Include a separate template
474 * @access private
476 public function _tpl_include($filename, $include = true)
478 $handle = $filename;
479 $this->filename[$handle] = $filename;
480 $this->files[$handle] = $this->root . '/' . $filename;
482 $filename = $this->_tpl_load($handle);
484 if ($include)
486 global $user;
488 $_tpldata = &$this->_tpldata;
489 $_rootref = &$this->_rootref;
490 $_lang = &$user->lang;
492 // These _are_ used the included files.
493 $_tpldata; $_rootref; $_lang;
495 if ($filename)
497 include($filename);
498 return;
500 else
502 if (!class_exists('template_compile'))
504 include(PHPBB_ROOT_PATH . 'includes/functions_template.' . PHP_EXT);
507 $compile = new template_compile($this);
509 if (($code = $compile->_tpl_gen_src($handle)) !== false)
511 $code = ' ?> ' . $code . ' <?php ';
512 eval($code);