Source for file Template.php
Documentation is available at Template.php
* DotBoost Technologies Inc.
* DotKernel Application Framework
* @copyright Copyright (c) 2009 DotBoost Technologies (http://www.dotboost.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @version $Id: Template.php 158 2010-06-25 08:59:20Z teo $
* Template engine, based on PHPLIB library
* @author DotKernel Team <team@dotkernel.com>
* If set, echo assignments
* If set, echo blocks time parse
* Relative filenames are relative to this pathname
* $file[handle] = 'filename';
* fallback paths that should be defined in a child class
* $varvals[key] = 'value';
* 'remove' => remove undefined variables
* 'comment' => replace undefined variables with comments
* 'keep' => keep undefined variables
* 'report' => report error, continue,
* 'no' => ignore error quietly
* The last error message is retained here
* Determines whether Template outputs filename comments.
* false = no filename outputs
* true = HTML comments (e.g. <!-- START FILE $filename -->) placed in output
* Determines the regular expression used to find unknown variable tags.
* 'loose' = traditional match all curly braces with no whitespace between
* 'strict' = adopts PHP's variable naming rules
protected static $_instance = null;
* Singleton pattern implementation makes 'new' unavailable
* @param string $root Template root directory
* @param string $unknowns How to handle unknown variables
* @param array $fallback Fallback paths
protected function __construct($root = '.', $unknowns = 'remove', $fallback= '')
* Singleton pattern implementation makes 'clone' unavailable
* Returns an instance of Dot_View
* Singleton pattern implementation
* @param string $root Template root directory
* @param string $unknowns How to handle unknown variables
* @param array $fallback Fallback paths
public static function getInstance($root = '.', $unknowns = 'remove', $fallback= '')
if (null === self::$_instance)
self::$_instance = new self($root, $unknowns, $fallback);
* Checks that $root is a valid directory and if so sets this directory as the
* base directory from which templates are loaded by storing the value in
* $this->root. Relative filenames are prepended with the path in $this->root.
if(preg_match('-/$-', $root))
$this->halt("setRoot: $root is not a directory.");
* Start the time to measure something
$mtime = $mtime[1] + $mtime[0];
$mtime = $mtime[1] + $mtime[0];
* Sets the policy for dealing with unresolved variable names.
* @param string $unknowns - default = 'remove'
* Inspired From PEAR HTML_Template_PHPLIB 1.4.0
* Checks if the given variable exists.
* When an array is given, it is checked if all variables exist.
* @param string|array$var Variable to check
foreach ($var as $varname) {
$isset = $isset & isset ($this->varVals[$varname]);
return isset ($this->varVals[$var]);
* Defines a filename for the initial value of a variable.
* It may be passed either a varname and a file name as two strings or
* a hash of strings with the key being the varname and the value
* The new mappings are stored in the array $this->file.
* The files are not loaded yet, but only when needed.
* USAGE: setFile(array $filelist = (string $varname => string $filename))
* USAGE: setFile(string $varname, string $filename)
* @param string $filename
public function setFile($varname, $filename = '')
$this->halt('setFile: For varname '. $varname . 'filename is empty.');
if ($this->file[$varname] === false) {
while(list ($v, $f) = each($varname))
$this->halt('setFile: For varname '. $v. ' filename is empty.');
* A variable $parent may contain a variable block defined by:
* <!-- BEGIN $varname --> content <!-- END $varname -->.
* This public function removes that block from $parent and replaces it
* with a variable reference named $name.
* The block is inserted into the varkeys and varvals hashes. If $name is
* omitted, it is assumed to be the same as $varname.
* Blocks may be nested but care must be taken to extract the blocks in order
* from the innermost block to the outermost block.
* USAGE: setBlock(string $parent, string $varname, [string $name = ''])
public function setBlock($parent, $varname, $name = '')
$this->halt('setBlock: unable to load '. $parent);
$str = $this->getVar($parent);
$reg = '/[ \t]*<!--\s+BEGIN '. $varname. '\s+-->\s*?\n?(\s*.*?\n?)'
. '\s*<!--\s+END '. $varname. '\s+-->\s*?\n?/sm';
$this->halt('setBlock: unable to set block '. $varname);
$this->setVar($varname, $m[1][0]);
* Sets the value of a variable.
* It may be called with either a varname and a value as two strings or an
* an associative array with the key being the varname and the value being
* the new variable value.
* The public function inserts the new value of the variable into the $varkeys and
* $varvals hashes. It is not necessary for a variable to exist in these hashes
* before calling this public function.
* An optional third parameter allows the value for each varname to be appended
* to the existing variable instead of replacing it. The default is to replace.
* This feature was introduced after the 7.2d release.
* USAGE: setVar(string $varname, [string $value = ''], [boolean $append = false])
* USAGE: setVar(array $varname = (string $varname => string $value),
* [mixed $dummy_var], [boolean $append = false])
public function setVar($varname, $value = '', $append = false)
printf("<b>setVar:</b> (with scalar) <b>%s</b> = '%s'<br>\n", $varname, htmlentities($value));
if ($append && isset ($this->varvals[$varname]))
$this->varvals[$varname] .= $value;
else $this->varvals[$varname] = $value;
while(list ($k, $v) = each($varname))
if ($append && isset ($this->varvals[$k]))
* Unsets a variable completely.
* It may be called with either a varname as a string or an array with the
* values being the varnames to be cleared.
* The public function removes the variable from the $varkeys and $varvals hashes.
* It is not necessary for a variable to exist in these hashes before calling
* USAGE: unsetVar(string $varname)
* USAGE: unsetVar(array $varname = (string $varname))
printf("<b>unsetVar:</b> (with scalar) <b>%s</b><br>\n", $varname);
while(list ($k, $v) = each($varname))
printf("<b>unsetVar:</b> (with array) <b>%s</b><br>\n", $v);
* Fills in all the variables contained within the variable named
* $varname. The resulting value is returned as the public function result and the
* original value of the variable varname is not changed. The resulting string
* RETURNS: the value of the variable $varname with all variables substituted or FALSE if halted
* USAGE: subst(string $varname)
public function subst($varname)
$varvals_quoted = array();
$this->halt('subst: unable to load '. $varname);
// quote the replacement strings to prevent bogus stripping of special chars
$varvals_quoted[$k] = preg_replace(array('/\\\\/', '/\$/'), array('\\\\\\\\', '\\\\$'), $v);
$str = $this->getVar($varname);
* This is shorthand for print $this->subst($varname). See subst for further details.
* USAGE: psubst(string $varname)
public function psubst($varname)
print $this->subst($varname);
* Substitutes the values of all defined variables in the variable
* named $varname and stores or appends the result in the variable named $target.
* It may be called with either a target and a varname as two strings or a
* target as a string and an array of variable names in varname.
* The public function inserts the new value of the variable into the $varkeys and
* $varvals hashes. It is not necessary for a variable to exist in these hashes
* before calling this public function.
* An optional third parameter allows the value for each varname to be appended
* to the existing target variable instead of replacing it. The default is to
* If $target and $varname are both strings, the substituted value of the
* variable $varname is inserted into or appended to $target.
* If $handle is an array of variable names the variables named by $handle are
* sequentially substituted and the result of each substitution step is
* inserted into or appended to in $target. The resulting substitution is
* available in the variable named by $target, as is each intermediate step
* for the next $varname in sequence. Note that while it is possible, it
* is only rarely desirable to call this public function with an array of varnames
* and with $append = true.
* USAGE: parse(string $target, string $varname, [boolean $append])
* USAGE: parse(string $target, array $varname = (string $varname), [boolean $append])
public function parse($target, $varname, $append = false)
$str = $this->subst($varname);
while(list ($i, $v) = each($varname))
return $this->getVar($target);
* This is shorthand for print $this->parse(...) and is public functionally identical.
* USAGE: pparse(string $target, string $varname, [boolean $append])
* USAGE: pparse(string $target, array $varname = (string $varname), [boolean $append])
public function pparse($target, $varname, $append = false)
$totalTimeBlock += $this->endTime[$ky];
printf("<b>block:</b> <b>%s</b> = '%f'<br>\n", $ky,$this->endTime[$ky]);
printf("<b>Total time for blocks:</b> '%f'<br>\n", $totalTimeBlock);
print $this->finish($this->parse($target, $varname, $append));
* Returns an associative array of all defined variables with the
* name as the key and the value of the variable as the value.
* This is mostly useful for debugging. Also note that $this->debug can be used
* to echo all variable assignments as they occur and to trace execution.
$result[$k] = $this->getVar($k);
* Returns the value of the variable named by $varname.
* If $varname references a file and that file has not been loaded yet, the
* variable will be reported as empty.
* When called with an array of variable names this public function will return a a
* hash of variable values keyed by their names.
* USAGE: getVar(string $varname)
* USAGE: getVar(array $varname)
public function getVar($varname)
$str = (isset ($this->varvals[$varname]))? $this->varvals[$varname]: '';
printf ("<b>getVar</b> (with scalar) <b>%s</b> = '%s'<br>\n", $varname, htmlentities($str));
while(list ($k, $v) = each($varname))
* Returns a hash of unresolved variable names in $varname, keyed
* by their names (that is, the hash has the form $a[$name] = $name).
* USAGE: getUndefined(string $varname)
$this->halt('getUndefined: unable to load '. $varname);
(('loose' == $this->unknownRegexp) ? "/{([^ \t\r\n}]+)}/" : "/{([_a-zA-Z]\\w+)}/"),
while(list ($k, $v) = each($m))
if (isset ($result) && count($result))
* Returns the finished version of $str.
* USAGE: finish(string $str)
(('loose' == $this->unknownRegexp) ? "/{([^ \t\r\n}]+)}/" : "/{([_a-zA-Z]\\w+)}/"),
(('loose' == $this->unknownRegexp) ? "/{([^ \t\r\n}]+)}/" : "/{([_a-zA-Z]\\w+)}/"),
"<!-- Template variable \\1 undefined -->",
* Prints the finished version of the value of the variable named by $varname.
* USAGE: p(string $varname)
public function p($varname)
* Returns the finished version of the value of the variable named by $varname.
* USAGE: get(string $varname)
public function get($varname)
* When called with a relative pathname, this function will return the pathname
* with $this->root prepended. Absolute pathnames are returned unchanged.
* RETURNS: a string containing an absolute pathname.
* USAGE: filename(string $filename)
* @param string $filename
if (substr($filename, 0, 1) != '/'
&& substr($filename, 0, 1) != '\\'
&& substr($filename, 1, 2) != ':\\'
&& substr($filename, 1, 2) != ':/'
$filename = $this->root. '/'. $filename;
$this->halt('filename: file '. $filename. ' does not exist.');
* Will construct a regexp for a given variable name with any special
* If a variable's value is undefined and the variable has a filename stored in
* $this->file[$varname] then the backing file will be loaded and the file's
* contents will be assigned as the variable's value.
* USAGE: loadFile(string $varname)
if (!isset ($this->file[$varname]))
// $varname does not reference a file so return
if (isset ($this->varvals[$varname]))
// will only be unset if varname was created with setFile and has never been loaded
// $varname has already been loaded so return
$filename = $this->file[$varname];
// use @file here to avoid leaking filesystem information if there is an error
$this->halt('loadFile: While loading $varname, '. $filename. ' does not exist or is empty.');
$str = "<!-- START FILE ". $filename. " -->\n$str<!-- END FILE ". $filename. " -->\n";
$this->setVar($varname, $str);
* Is called whenever an error occurs and will handle the error according
* to the policy defined in $this->haltOnError. Additionally the error message will be saved
* USAGE: halt(string $msg)
private function halt($msg)
* Prints an error message.
* It can be overridden by your subclass of Template. It will be called with an
* error message to display.
* USAGE: haltMsg(string $msg)
$the_error .= "\n\n ". $msg. "\n\n";
$the_error .= "Date: ". date("l dS of F Y h:i:s A");
$out = "<html><head><title>Template Error</title>
<style>P,BODY{ font-family: trebuchet MS,sans-serif; font-size:11px;
}</style></head><body> <br><br><blockquote><b>There is an error with the
template system.</b><br><b>Error Returned: </b><br>
<form name='mysql'><textarea rows=\"5\" cols=\"60\">". htmlspecialchars($the_error). "</textarea></form></blockquote></body></html>";
* Returns the last error message if any
* @return boolean|stringLast error message if any
* Initialize the value of a variable.
* It may be called with either a varname and a value as two strings or an
* an associative array with the key being the varname and the value being
* the new variable value.
* The public function inserts the new value of the variable into the $varkeys and
* $varvals hashes. It is not necessary for a variable to exist in these hashes
* before calling this public function.
* An optional third parameter allows the value for each varname to be appended
* to the existing variable instead of replacing it. The default is to replace.
* USAGE: initVar(string $varname, [string $value = ''], [boolean $append = false])
* USAGE: initVar(array $varname = (string $varname => string $value),
* [mixed $dummy_var], [boolean $append = false])
* USAGE: initVar(array $varname = (string $value),
* [mixed $dummy_var], [boolean $append = false])
public function initVar($varname, $value = '', $append = false)
$this->setVar($varname, $value, $append);
while(list ($k, $v) = each($varname))
$this->setVar($v, $value, $append);
$this->setVar($k, $v, $append);
elseif ($this->debug & 1)
printf("<b>initVar:</b> (with scalar) <b>%s</b> = '%s'<br>\n", $varname, htmlentities($value));
* A variable $parent may contain a variable block defined by:
* <!-- BEGIN $varname --> content <!-- END $varname -->.
* This public function removes that block from $parent and replaces it
* with a variable reference named $name.
* The block is inserted into the varkeys and varvals hashes. If $name is
* omitted, it is assumed to be the same as $varname.
* Blocks may be nested but care must be taken to extract the blocks in order
* from the innermost block to the outermost block.
* USAGE: setBlock(string $parent, string $varname, [string $name = ''])
public function initBlock($target, $value = '', $append = false)
$this->parse($target, $value, $append);
while(list ($k, $v) = each($target))
$this->parse($v, $value, $append);
$this->parse($k, $v, $append);
else $this->setVar($target, $str);
|