pre_parse_hook - Name of the function to execute on * a template before the parsing occurs * * @author Blue Static * @copyright Copyright ©2002 - [#]year[#], Blue Static * @version $Revision$ * @package ISSO * */ class Template { /** * Framework registry object * @var object * @access private */ var $registry = null; /** * Name of the database table templates are in * @var string * @access private */ var $tablename = ''; /** * Name of the table column template names are in * @var string * @access private */ var $namecolumn = ''; /** * Name of the table column templates are in * @var string * @access private */ var $datacolumn = ''; /** * Additional WHERE clauses for the template fetch SQL * @var string * @access private */ var $extrawhere = ''; /** * The name of the function phrases are fetched with * @var string * @access private */ var $langcall = 'gettext'; /** * The name of the function phrases are sprintf() parsed with * @var string * @access private */ var $langconst = 'sprintf'; /** * Array of pre-compiled templates that are stored to decrease server load * @var array * @access private */ var $cache = array(); /** * A list of the number of times each template has been used * @var array * @access private */ var $usage = array(); /** * A list of templates that weren't cached, but are still used * @var array * @access private */ var $uncached = array(); /** * Whether or not the page has been flush()'d already * @var bool * @access private */ var $doneflush = false; /** * The name of a function that is called before template parsing of phrases and conditionals occurs * @var string * @access private */ var $pre_parse_hook = ':=NO METHOD=:'; // ################################################################### /** * Constructor */ function __construct(&$registry) { $this->registry =& $registry; } // ################################################################### /** * (PHP 4) Constructor */ function Template(&$registry) { $this->__construct($registry); } // ################################################################### /** * Initializes the class and all subclasses under a common package name * * @access protected * * @return string The package name */ function init_as_package() { return 'template'; } // ################################################################### /** * Sets tablename * * @access public * * @param string Table name */ function setTableName($name) { $this->tablename = $name; } // ################################################################### /** * Sets namecolumn * * @access public * * @param string Name column name */ function setNameColumn($name) { $this->namecolumn = $name; } // ################################################################### /** * Sets datacolumn * * @access public * * @param string Data column name */ function setDataColumn($name) { $this->datacolumn = $name; } // ################################################################### /** * Sets extrawhere * * @access public * * @param string Extra WHERE SQL clause */ function setExtraWhere($sql) { $this->extrawhere = $sql; } // ################################################################### /** * Sets the pre-parse hook * * @access public * * @param string Method name */ function setPreParseHook($name) { $this->pre_parse_hook = $name; } // ################################################################### /** * Takes an array of template names, loads them, and then stores a * parsed version for optimum speed. * * @access public * * @param array List of template names to be cached */ function cache($namearray) { if (sizeof($this->cache) > 0) { trigger_error('You cannot cache templates more than once per initialization', E_USER_WARNING); } else { $templates = $this->registry->modules[ISSO_DB_LAYER]->query("SELECT * FROM " . $this->tablename . " WHERE " . $this->namecolumn . " IN ('" . implode("', '", $namearray) . "')" . ($this->extrawhere ? ' ' . $this->extrawhere : '')); while ($template = $this->registry->modules[ISSO_DB_LAYER]->fetch_array($templates)) { $this->cache[ $template[ $this->namecolumn ] ] = $this->_parse($template[ $this->datacolumn ]); $this->usage[ $template[ $this->namecolumn ] ] = 0; } } } // ################################################################### /** * Loads a template from the cache or the _load function and stores the * parsed version of it * * @access public * * @param string The name of the template * * @return string A parsed and loaded template */ function fetch($name) { if (isset($this->cache["$name"])) { $template = $this->cache["$name"]; } else { $this->uncached[] = $name; $this->registry->debug("Manually loading template `$name`"); $template = $this->_load($name); $template = $this->_parse($template); } if (!isset($this->usage["$name"])) { $this->usage["$name"] = 0; } $this->usage["$name"]++; return $template; } // ################################################################### /** * Output a template fully compiled to the browser * * @access public * * @param string Compiled and ready template */ function flush($template) { ob_start(); if (empty($template)) { trigger_error('There was no output to print', E_USER_ERROR); exit; } if ($this->registry->debug AND isset($_GET['query'])) { if (is_array($this->registry->modules[ISSO_DB_LAYER]->history)) { foreach ($this->registry->modules[ISSO_DB_LAYER]->history AS $query) { echo $this->registry->modules[ISSO_DB_LAYER]->construct_query_debug($query); } } exit; } if ($this->doneflush) { trigger_error('A template has already been sent to the output buffer', E_USER_ERROR); exit; } $template = str_replace('', $this->registry->construct_debug_block(true) . '', $template); print($template); } // ################################################################### /** * Loads an additional template from the database * * @access private * * @param string The name of the template * * @return string Template data from the database */ function _load($name) { if ($template = $this->registry->modules[ISSO_DB_LAYER]->query_first("SELECT * FROM " . $this->tablename . " WHERE " . $this->namecolumn . " = '$name'" . ($this->extrawhere ? ' ' . $this->extrawhere : ''))) { return $template[ $this->datacolumn ]; } else { trigger_error("The template '$name' could not be loaded", E_USER_ERROR); exit; } } // ################################################################### /** * A wrapper for all the parsing functions and compiling functins * * @access protected * * @param string Unparsed template data * * @return string Parsed template data */ function _parse($template) { $template = str_replace('"', '\"', $template); if (function_exists($this->pre_parse_hook)) { $template = call_user_func($this->pre_parse_hook, $template); } $template = $this->_parse_phrases($template); $template = $this->_parse_conditionals($template); return $template; } // ################################################################### /** * Prepares language and locale information inside templates * * @access private * * @param string Template data to be processed * * @return string Language-ready template data */ function _parse_phrases($template) { $tag_start = ' $close_of_open = strpos($phrase_bunch, $tag_start_end); if ($close_of_open === false) { break; } // Extract the opening tag so it can be parsed $init_tag = substr($phrase_bunch, 0, ($close_of_open + strlen($tag_start_end))); $init_tag = str_replace($tag_start, '', $init_tag); $init_tag = substr($init_tag, 0, strlen($init_tag) - 1); // Get the args out of the tag $args = preg_split('#([0-9].*?)=#', $init_tag); foreach ($args AS $arg) { if ($arg AND $arg != ' ') { $arg = trim($arg); $arg = substr($arg, 2); $arg = substr($arg, 0, strlen($arg) - 2); $arglist[] = $arg; } } // Just get the phrase name $phrase_name = preg_replace('#(.*?)#i', '$2', $phrase_bunch); // Wrap the parsed data into the build function $function_wrap = '" . ' . $this->langconst . '("' . /*str_replace(array('\"', "'"), array('"', "\'"),*/ $phrase_name/*)*/ . '", "' . implode('", "', $arglist) . '") . "'; // Replace the fully-parsed string back into the template $template = substr_replace($template, $function_wrap, $location_start, $location_end + strlen($tag_end) - $location_start); unset($arglist); } // Process the empty phrase objects -- do this now so we don't have to worry about it when we're parsing later $template = preg_replace('#\{@\\\"(.*?)\\\"\}#ise', '$this->_phrase_string(\'$1\')', $template); return $template; } // ################################################################### /** * Turns a localized phrase tag into a function call * * @access private * * @param string Phrase text * * @return string Function call for phrase text */ function _phrase_string($text) { return '" . ' . $this->langcall . '(\'' . str_replace(array('\\\"', "'"), array('"', "\'"), $text) . '\') . "'; } // ################################################################### /** * Parser for in-line template conditionals * * @access private * * @param string Template data awaiting processing * * @return string Parsed template data */ function _parse_conditionals($template) { // tag data $tag_start = ' $relpos = $tag_full['else'] - $tag_full['posi']; // calculate the length of the expression and opening tag $length = strlen($parsed[0]) + strlen($tag_start) + strlen($tag_start_end); // relative to the start of iftrue $elsepos = $relpos - $length; $parsed[1] = substr($conditional, 0, $elsepos); $parsed[2] = substr($conditional, $elsepos + strlen($tag_else)); } // no else to handle else { $parsed[1] = $conditional; $parsed[2] = ''; } #var_dump($parsed); // final parsed output $parsed = '" . ((' . stripslashes($parsed[0]) . ') ? "' . $parsed[1] . '" : "' . $parsed[2] . '") . "'; // replace the conditional $template = str_replace($fullspread, $parsed, $template); // reset the parser $offset = $tag_full['posi'] + strlen($tag_start) + strlen($tag_start_end); $tag_full = array(); $stack = array(); $parsed = array(); unset($fullspread, $conditional, $temp_end, $relpos, $length, $elsepos); break; } } } return $template; } } // ################################################################### /** * Debugging function used to print characters in a string that are * around a certain position. * * @access private * * @param string The haystack string * @param integer Position to print around */ function print_around($str, $pos) { echo '>>> PA >>>>>>>>['; echo htmlspecialchars($str[ $pos - 5 ]); echo htmlspecialchars($str[ $pos - 4 ]); echo htmlspecialchars($str[ $pos - 3 ]); echo htmlspecialchars($str[ $pos - 2 ]); echo htmlspecialchars($str[ $pos - 1 ]); echo '©'; echo htmlspecialchars($str[ $pos + 0 ]); echo htmlspecialchars($str[ $pos + 1 ]); echo htmlspecialchars($str[ $pos + 2 ]); echo htmlspecialchars($str[ $pos + 3 ]); echo htmlspecialchars($str[ $pos + 4 ]); echo htmlspecialchars($str[ $pos + 5 ]); echo ']<<<<<<<< PA <<<'; } /*=====================================================================*\ || ################################################################### || # $HeadURL$ || # $Id$ || ################################################################### \*=====================================================================*/ ?>