Source code for file /pattemplate/patTemplate.php
Documentation is available at patTemplate.php
* $Id: patTemplate.php 560 2005-10-19 17:22:00Z Jinx $
* powerful templating engine
* @link http://www.php-tools.net
// ** Following line Joomla! specific **
require_once( dirname( __FILE__
) .
'/patErrorManager.php' );
* template already exists
define( 'PATTEMPLATE_ERROR_TEMPLATE_EXISTS', 5010 );
* template does not exist
define ( 'PATTEMPLATE_WARNING_NO_TEMPLATE', 5011 );
define ( 'PATTEMPLATE_WARNING_UNKNOWN_TYPE', 5012 );
* base class for module could not be found
define( 'PATTEMPLATE_ERROR_BASECLASS_NOT_FOUND', 5050 );
* module could not be found
define( 'PATTEMPLATE_ERROR_MODULE_NOT_FOUND', 5051 );
define( 'PATTEMPLATE_ERROR_EXPECTED_ARRAY', 5052 );
define( 'PATTEMPLATE_ERROR_NO_INPUT', 6000 );
define( 'PATTEMPLATE_ERROR_RECURSION', 6010 );
* powerful templating engine
* @link http://www.php-tools.net
* standard system vars that identify pat tools
'appName' =>
'patTemplate',
* default attributes for new templates
var $_defaultAttributes =
array(
'visibility' =>
'visible',
* options for patTemplate
* Currently the following options are implemented:
* - maintainBc defines, whether patTemplate should be backwards compatible.
* This means, that you may use 'default' and 'empty' for subtemplates.
'root' =>
array('__default' =>
'.'),
'namespace' =>
'patTemplate',
'defaultFunction' =>
false
* directories, where modules can be stored
var $_moduleDirs =
array();
* stores all template names
var $_templateList =
array();
* stores all template data
var $_templates =
array();
* stores all global variables
* stores all local variables
* stores the name of the first template that has been
* output filters that should be used
var $_outputFilters =
array();
* input filters that should be used
var $_inputFilters =
array();
* template cache, that should be used
* placeholders, that have been discovered
var $_discoveredPlaceholders =
array();
* Create a new patTemplate instance.
* The constructor accepts the type of the templates as sole parameter.
* The type influences the tags you are using in your templates.
* @param string type (either html or tex)
if( !defined( 'PATTEMPLATE_INCLUDE_PATH' ) ) {
define( 'PATTEMPLATE_INCLUDE_PATH', dirname( __FILE__
) .
'/patTemplate' );
* Currently, the following options are supported
* - maintainBc (true|false)
* @param string option to set
* @param string value of the option
$this->_options[$option] =
$value;
* @param string option to get
* @return mixed value of the option
if (!isset
($this->_options[$option])) {
return $this->_options[$option];
* sets name of directory where templates are stored
* @param string dir where templates are stored
* @deprecated please use patTemplate::setRoot() instead
* sets root base for the template
* The parameter depends on the reader you are using.
* @param string root base of the templates
function setRoot($root, $reader =
'__default')
$this->_options['root'][$reader] =
$root;
* gets name of root base for the templates
* @return mixed root base
function getRoot($reader =
'__default')
return $this->_options['root'][$reader];
* sets namespace of patTemplate tags
* If you want to use more than one namespace, you may set this to
* an array. All tags in these namespaces will be treated as patTemplate
* @param string|array namespace(s)
$this->_options['namespace'] =
$ns;
* gets namespace of patTemplate tags
* @return string|array namespace(s)
return $this->_options['namespace'];
* @param string attribute name
* @param mixed attribute value
$this->_defaultAttributes[$name] =
$value;
* @param array attributes
$this->_defaultAttributes =
array_merge( $this->_defaultAttributes, $attributes );
* @return return default attributes
return $this->_defaultAttributes;
* set the type for the templates
* @param string type (html or tex)
* @return boolean true on success
"Unknown type '$type'. Please use 'html' or 'tex'."
* set the start and end tag for variables
* @param string start tag
* @return boolean true on success
function setTags( $startTag, $endTag )
$this->_options['startTag'] =
$startTag;
$this->_options['endTag'] =
$endTag;
$this->_startTag =
$startTag;
$this->_endTag =
$endTag;
* get start tag for variables
* @return string start tag
return $this->_options['startTag'];
* get end tag for variables
return $this->_options['endTag'];
* add a directory where patTemplate should search for
* You may either pass a string or an array of directories.
* patTemplate will be searching for a module in the same
* order you added them. If the module cannot be found in
* the custom folders, it will look in
* patTemplate/$moduleType.
* @param string module type
* @param string|array directory or directories to search.
if( !isset
( $this->_moduleDirs[$moduleType] ) )
$this->_moduleDirs[$moduleType] =
array();
$this->_moduleDirs[$moduleType] =
array_merge( $this->_moduleDirs[$moduleType], $dir );
array_push( $this->_moduleDirs[$moduleType], $dir );
* Sets an attribute of a template
* supported attributes: visibilty, loop, parse, unusedvars
* @param string $template name of the template
* @param string $attribute name of the attribute
* @param mixed $value value of the attribute
* @see setAttributes(),getAttribute(), clearAttribute()
if( !isset
( $this->_templates[$template] ) )
"Template '$template' does not exist."
$this->_templates[$template]['attributes'][$attribute] =
$value;
* Sets several attribute of a template
* $attributes has to be a assotiative arrays containing attribute/value pairs
* supported attributes: visibilty, loop, parse, unusedvars
* @param string $template name of the template
* @param array $attributes attribute/value pairs
* @see setAttribute(), getAttribute(), clearAttribute()
if( !isset
( $this->_templates[$template] ) )
"Template '$template' does not exist."
$this->_templates[$template]['attributes'] =
array_merge( $this->_templates[$template]['attributes'], $attributes );
* Get all attributes of a template
* @param string name of the template
* @return array attributes
if( !isset
( $this->_templates[$template] ) )
"Template '$template' does not exist."
return $this->_templates[$template]['attributes'];
* Gets an attribute of a template
* supported attributes: visibilty, loop, parse, unusedvars
* @param string $template name of the template
* @param string $attribute name of the attribute
* @return mixed value of the attribute
* @see setAttribute(), setAttributes(), clearAttribute()
if( !isset
( $this->_templates[$template] ) )
"Template '$template' does not exist."
return $this->_templates[$template]['attributes'][$attribute];
* Clears an attribute of a template
* supported attributes: visibilty, loop, parse, unusedvars
* @param string $template name of the template
* @param string $attribute name of the attribute
* @see setAttribute(), setAttributes(), getAttribute()
if( !isset
( $this->_templates[$template] ) )
"Template '$template' does not exist."
$this->_templates[$template]['attributes'][$attribute] =
'';;
* This can be used if you want to add variables to
* a template, that has not been loaded yet.
* @param string template name
if( !isset
( $this->_vars[$name] ) )
$this->_vars[$name] =
array(
* add a variable to a template
* A variable may also be an indexed array, but _not_
* @param string $template name of the template
* @param string $varname name of the variable
* @param mixed $value value of the variable
function addVar( $template, $varname, $value )
$this->_vars[$template]['scalar'][$varname] =
$value;
for ($i =
0; $i <
$cnt; $i++
) {
if (!isset
( $this->_vars[$template]['rows'][$i] )) {
$this->_vars[$template]['rows'][$i] =
array();
$this->_vars[$template]['rows'][$i][$varname] =
$value[$i];
* get the value of a variable
* @param string name of the template
* @param string name of the variable
* @return string value of the variable, null if the variable is not set
function getVar( $template, $varname )
if( isset
( $this->_vars[$template]['scalar'][$varname] ) )
return $this->_vars[$template]['scalar'][$varname];
if(!isset
($this->_vars[$template]['rows']))
$cnt =
count( $this->_vars[$template]['rows'] );
for( $i =
0; $i <
$cnt; $i++
)
if( !isset
( $this->_vars[$template]['rows'][$i][$varname] ) )
array_push( $value, $this->_vars[$template]['rows'][$i][$varname] );
* clear the value of a variable
* @param string name of the template
* @param string name of the variable
* @see clearVars(), clearTemplate()
function clearVar( $template, $varname )
if (isset
( $this->_vars[$template]['scalar'][$varname] )) {
unset
($this->_vars[$template]['scalar'][$varname]);
$cnt =
count( $this->_vars[$template]['rows'] );
for ($i =
0; $i <
$cnt; $i++
) {
if (!isset
($this->_vars[$template]['rows'][$i][$varname])) {
unset
($this->_vars[$template]['rows'][$i][$varname]);
* Adds several variables to a template
* Each Template can have an unlimited amount of its own variables
* $variables has to be an assotiative array containing variable/value pairs
* @param string $template name of the template
* @param array $variables assotiative array of the variables
* @param string $prefix prefix for all variable names
* @see addVar(), addRows(), addGlobalVar(), addGlobalVars()
function addVars( $template, $variables, $prefix =
'' )
foreach ($variables as $varname =>
$value) {
$varname =
$prefix.
$varname;
$this->_vars[$template]['scalar'][$varname] =
$value;
for( $i =
0; $i <
$cnt; $i++
) {
if( !isset
( $this->_vars[$template]['rows'][$i] ) )
$this->_vars[$template]['rows'][$i] =
array();
$this->_vars[$template]['rows'][$i][$varname] =
$value[$i];
* Clear all variables in a template
* This clears only variables, but does
* @param string $template name of the template
* @see clearVar(), clearTemplate()
$this->_vars[$template] =
array(
* Adds several rows of variables to a template
* Each Template can have an unlimited amount of its own variables
* Can be used to add a database result as variables to a template
* @param string $template name of the template
* @param array $rows array containing assotiative arrays with variable/value pairs
* @param string $prefix prefix for all variable names
* @see addVar(), addVars(), addGlobalVar(), addGlobalVars()
function addRows( $template, $rows, $prefix =
'' )
for( $i =
0; $i <
$cnt; $i++
)
if( !isset
( $this->_vars[$template]['rows'][$i] ) )
$this->_vars[$template]['rows'][$i] =
array();
foreach( $rows[$i] as $varname =>
$value )
$this->_vars[$template]['rows'][$i][$prefix.
$varname] =
$value;
* Adds an object to a template
* All properties of the object will be available as template variables.
* @param string name of the template
* @param object|array object or array of objects
* @param string prefix for all variable names
* @param boolean ignore private properties (starting with _)
* @see addVar(), addRows(), addGlobalVar(), addGlobalVars()
function addObject( $template, $object, $prefix =
'', $ignorePrivate =
false )
array_push( $rows, $this->getObjectVars($o, $ignorePrivate) );
return $this->addRows( $template, $rows, $prefix );
return $this->addVars( $template, $this->getObjectVars($object, $ignorePrivate), $prefix );
* get the vars from an object
* @param boolean ignore private properties (starting with _)
function getObjectVars($obj, $ignorePrivate =
false)
if ($ignorePrivate ===
false) {
foreach ($vars as $var =>
$value) {
* Global variables are valid in all templates of this object.
* A global variable has to be scalar, it will be converted to a string.
* @param string $varname name of the global variable
* @param string $value value of the variable
* @return boolean true on success
* @see addGlobalVars(), addVar(), addVars(), addRows()
$this->_globals[strtoupper( $varname )] = ( string )
$value;
* Clears a global variable
* @param string $varname name of the global variable
* @return boolean true on success
* @see clearVar(), clearVars(), clearGlobalVars()
if (!isset
($this->_globals[$varname])) {
unset
($this->_globals[$varname]);
* Clears all global variables
* @return boolean true on success
* @see clearVar(), clearVars(), clearGlobalVar()
$this->_globals =
array();
* Adds several global variables
* Global variables are valid in all templates of this object.
* $variables is an associative array, containing name/value pairs of the variables.
* @param array $variables array containing the variables
* @param string $prefix prefix for variable names
* @return boolean true on success
* @see addGlobalVar(), addVar(), addVars(), addRows()
foreach( $variables as $varname =>
$value )
$this->_globals[$prefix.
$varname] = ( string )
$value;
* get all global variables
* @return array global variables
* checks wether a template exists
* @param string name of the template
* @return boolean true, if the template exists, false otherwise
* enable a template cache
* A template cache will improve performace, as the templates
* do not have to be read on each request.
* @param string name of the template cache
* @param array parameters for the template cache
* @return boolean true on success, patError otherwise
$cache =
&$this->loadModule( 'TemplateCache', $cache, $params );
$this->_tmplCache =
&$cache;
* enable an output filter
* Output filters are used to modify the template
* result before it is sent to the browser.
* They are applied, when displayParsedTemplate() is called.
* @param string name of the output filter
* @param array parameters for the output filter
* @return boolean true on success, patError otherwise
$filter =
&$this->loadModule( 'OutputFilter', $filter, $params );
if ($template ===
null) {
$this->_outputFilters[] =
&$filter;
if (!$this->exists($template)) {
$this->_templates[$template]['attributes']['outputfilter'] =
&$filter;
* input filters are used to modify the template
* stream before it is split into smaller templates-
* @param string name of the input filter
* @param array parameters for the input filter
* @return boolean true on success, patError otherwise
$filter =
&$this->loadModule( 'InputFilter', $filter, $params );
$this->_inputFilters[] =
&$filter;
* open a file and parse for patTemplate tags
* @param name of the file
* @return true, if the template could be parsed
* @deprecated Use patTemplate::readTemplatesFromInput() instead, as the method name is misleading
* @see readTemplatesFromInput()
* open any input and parse for patTemplate tags
* @param string name of the input (filename, shm segment, etc.)
* @param string driver that is used as reader, you may also pass a Reader object
* @param array additional options that will only be used for this template
* @param string name of the template that should be used as a container, should not be used by public
* @return boolean true, if the template could be parsed, false otherwise
if ((string)
$input ===
'') {
$options =
$this->_options;
if ($this->_tmplCache !==
null) {
* get the unique cache key
$key =
$this->_tmplCache->getKey($input, $options);
$templates =
$this->_loadTemplatesFromCache( $input, $reader, $options, $key );
* check for error returned from cache
* templates have not been loaded from cache
if ($templates ===
false) {
if ($reader->isInUse()) {
$reader =
&$this->loadModule( 'Reader', $reader->getName(), array(), true);
$reader->setOptions($options);
* set the root attributes
$reader->setRootAttributes( $attributes );
$templates =
$reader->readTemplates( $input );
* check for error returned from reader
if( $this->_tmplCache !==
null )
$this->_tmplCache->write( $key, $templates );
foreach( $templates as $name =>
$spec )
if( $name ==
'__ptroot' )
if( $parseInto ===
false )
if( !in_array( $parseInto, $this->_templateList ) )
$spec['attributes'] =
$this->_templates[$parseInto]['attributes'];
* if this is the first template that has been loaded
* set it as the root template
if( $this->_root ===
null &&
is_null( $parseInto ) && isset
( $spec['isRoot'] ) &&
$spec['isRoot'] ==
true )
* set some default values
$spec['modifyVars'] =
array();
$spec['copyVars'] =
array();
$spec['defaultVars'] =
array();
$this->_templates[$name] =
$spec;
* store the default values of the variables
foreach( $spec['varspecs'] as $varname =>
$varspec )
if (isset
($varspec['modifier'])) {
$this->_templates[$name]['modifyVars'][$varname] =
$varspec['modifier'];
if( isset
( $varspec['copyfrom'] ) )
$this->_templates[$name]['copyVars'][$varname] =
$varspec['copyfrom'];
if( !isset
( $varspec['default'] ) )
$this->_templates[$name]['defaultVars'][$varname] =
$varspec['default'];
$this->addVar( $name, $varname, $varspec['default'] );
unset
($this->_templates[$name]['varspecs']);
* Some error management is needed here...
if( isset
( $this->_templates[$name]['attributes']['src'] ) &&
$this->_templates[$name]['attributes']['autoload'] ==
'on' )
if( $this->_templates[$name]['loaded'] !==
true )
if( $this->_templates[$name]['attributes']['parse'] ==
'on' )
$this->readTemplatesFromInput( $this->_templates[$name]['attributes']['src'], $this->_templates[$name]['attributes']['reader'], $options, $name );
$this->loadTemplateFromInput( $this->_templates[$name]['attributes']['src'], $this->_templates[$name]['attributes']['reader'], null, $name );
$this->_templates[$name]['loaded'] =
true;
* load from template cache
* @param string name of the input (filename, shm segment, etc.)
* @param string driver that is used as reader, you may also pass a Reader object
* @param array options for the reader
* @param string cache key
* @return array|boolean either an array containing the templates, or false
function _loadTemplatesFromCache( $input, &$reader, $options, $key )
$statName =
$reader->getName();
$stat->setOptions( $options );
$modTime =
$stat->getModificationTime( $input );
$templates =
$this->_tmplCache->load( $key, $modTime );
* open any input and load content into template
* @param string name of the input (filename, shm segment, etc.)
* @param string driver that is used as reader
* @param string name of the template that should be used as a container,
* @return boolean true, if the template could be parsed, false otherwise
$options =
$this->_options;
$reader =
&$this->loadModule( 'Reader', $reader );
$reader->setOptions($options);
$result =
$reader->loadTemplate( $input );
$this->_templates[$parseInto]['content'] .=
$result;
$this->_templates[$parseInto]['loaded'] =
true;
* load a template that had autoload="off"
* This is needed, if you change the source of a template and want to
* load it, after changing the attribute.
* @param string template name
* @return boolean true, if template could be loaded
if( !isset
( $this->_templates[$template] ) )
"Template '$template' does not exist."
if( $this->_templates[$template]['loaded'] ===
true )
if( $this->_templates[$template]['attributes']['parse'] ==
'on' )
return $this->readTemplatesFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
return $this->loadTemplateFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
* loads a patTemplate module
* Modules are located in the patTemplate folder and include:
* @param string moduleType (Reader|TemplateCache|Modifier|OutputFilter|InputFilter)
* @param string moduleName
* @param array parameters for the module
function &loadModule( $moduleType, $moduleName, $params =
array(), $new =
false )
if( !isset
( $this->_modules[$moduleType] ) )
$this->_modules[$moduleType] =
array();
if( isset
( $this->_modules[$moduleType][$sig] ) &&
$new ===
false ) {
return $this->_modules[$moduleType][$sig];
$baseClass =
'patTemplate_' .
$moduleType;
if( !file_exists( $baseFile ) or !include_once $baseFile )
$moduleClass =
'patTemplate_' .
$moduleType .
'_' .
$moduleName;
if( isset
( $this->_moduleDirs[$moduleType] ) )
$dirs =
$this->_moduleDirs[$moduleType];
if ( file_exists( $moduleFile ) and include_once $moduleFile) {
$this->_modules[$moduleType][$sig] =
&new $moduleClass;
if( method_exists( $this->_modules[$moduleType][$sig], 'setTemplateReference' ) )
$this->_modules[$moduleType][$sig]->setTemplateReference( $this );
$this->_modules[$moduleType][$sig]->setParams( $params );
return $this->_modules[$moduleType][$sig];
* checks whether a module exists.
* Modules are located in the patTemplate folder and include:
* @param string moduleType (Reader|TemplateCache|Modifier|OutputFilter|InputFilter)
* @param string moduleName
// !!!JOOMLA VARIATION!!!
if (isset
($this->_moduleDirs[$moduleType])) {
$dirs =
$this->_moduleDirs[$moduleType];
foreach ($dirs as $dir) {
if (!isset
( $paths[$moduleFile] ))
$paths[$moduleFile] =
false;
$paths[$moduleFile] =
false;
$paths[$moduleFile] =
true;
if (!$paths[$moduleFile]) {
* Parses a template and stores the parsed content.
* mode can be "w" for write (delete already parsed content) or "a" for append (appends the
* new parsed content to the already parsed content)
* @param string name of the template
* @param string mode for the parsing
if (!isset
($this->_templates[$template])) {
"Template '$template' does not exist."
* template is not visible
if ($this->_templates[$template]['attributes']['visibility'] ==
'hidden') {
$this->_templates[$template]['result'] =
'';
$this->_templates[$template]['parsed'] =
true;
* check, if the template has been loaded
* and load it if necessary.
if ($this->_templates[$template]['loaded'] !==
true) {
if ($this->_templates[$template]['attributes']['parse'] ==
'on') {
$result =
$this->readTemplatesFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
$result =
$this->loadTemplateFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
isset
( $this->_templates[$template]['attributes']['autoclear'] ) &&
$this->_templates[$template]['attributes']['autoclear'] ==
'yes' &&
$this->_templates[$template]['lastMode'] !=
'a'
$this->_templates[$template]['parsed'] =
false;
* template has been parsed and mode is not 'append'
if ($this->_templates[$template]['parsed'] ===
true &&
$mode ===
'w') {
$this->_templates[$template]['lastMode'] =
$mode;
$this->_initTemplate( $template );
if (!isset
($this->_vars[$template]['rows'])) {
$this->_vars[$template]['rows'] =
array();
$loop =
count( $this->_vars[$template]['rows'] );
* loop at least one times
if (isset
($this->_templates[$template]['attributes']['maxloop'])) {
$loop =
ceil( $loop /
$this->_templates[$template]['attributes']['maxloop'] ) *
$this->_templates[$template]['attributes']['maxloop'];
$this->_templates[$template]['loop'] =
max( $this->_templates[$template]['attributes']['loop'], $loop );
if (isset
($this->_templates[$template]['attributes']['limit'])) {
$p =
strpos( $this->_templates[$template]['attributes']['limit'], ',' );
$this->_templates[$template]['loop'] =
min( $this->_templates[$template]['loop'], $this->_templates[$template]['attributes']['limit'] );
$start =
substr( $this->_templates[$template]['attributes']['limit'], 0, $p );
$end =
substr( $this->_templates[$template]['attributes']['limit'], $p+
1 )+
$start;
$this->_templates[$template]['loop'] =
min( $this->_templates[$template]['loop'], $end );
* template should be cleared before parsing
$this->_templates[$template]['result'] =
'';
$this->_templates[$template]['iteration'] =
$start;
for ($i =
$start; $i <
$this->_templates[$template]['loop']; $i++
) {
unset
( $this->_templates[$template]['vars'] );
$this->_fetchVariables( $template );
$result =
$this->_fetchTemplate($template);
$this->_templates[$template]['iteration']++
;
$this->_parseVariables( $template );
$result =
$this->_parseDependencies( $template );
$this->_templates[$template]['result'] .=
$this->_templates[$template]['work'];
$this->_templates[$template]['iteration']++
;
* check for maximum loops
if (isset
($this->_templates[$template]['attributes']['maxloop'])) {
if ($loopCount ==
$this->_templates[$template]['attributes']['maxloop'] &&
$i <
($loop-
1)) {
$this->_templates[$template]['parsed'] =
true;
$this->parseTemplate( $this->_templates[$template]['attributes']['parent'], 'a' );
$this->_templates[$template]['parsed'] =
false;
$this->_templates[$template]['result'] =
'';
if (!$finished && isset
($this->_templates[$template]['attributes']['maxloop'])) {
$this->_templates[$template]['parsed'] =
true;
$this->parseTemplate( $this->_templates[$template]['attributes']['parent'], 'a', false );
$this->_templates[$template]['parsed'] =
false;
$this->_templates[$template]['result'] =
'';
$this->_templates[$this->_templates[$template]['attributes']['parent']]['work'] =
'';
$this->_parseGlobals($template);
$this->_handleUnusedVars($template);
$this->_templates[$template]['parsed'] =
true;
if (isset
($this->_templates[$template]['attributes']['autoclear']) &&
$this->_templates[$template]['attributes']['autoclear'] ==
'yes') {
$this->_vars[$template] =
array(
if (isset
($this->_templates[$template]['attributes']['outputfilter'])) {
if (is_object($this->_templates[$template]['attributes']['outputfilter'])) {
$filter =
&$this->_templates[$template]['attributes']['outputfilter'];
$filter =
&$this->loadModule('OutputFilter', $this->_templates[$template]['attributes']['outputfilter']);
$this->_templates[$template]['result'] =
$filter->apply($this->_templates[$template]['result']);
* This method checks the variable specifications and
* copys variables from other templates.
* @param string name of the template
* @return boolean true on success
function _initTemplate( $template )
foreach( $this->_templates[$template]['copyVars'] as $dest =>
$src )
* copy from the same template
$srcTemplate =
$template;
* copy from another template
if( isset
( $this->_vars[$srcTemplate] ) )
if( isset
( $this->_vars[$srcTemplate]['scalar'][$srcVar] ) )
$this->_vars[$template]['scalar'][$dest] =
$this->_vars[$srcTemplate]['scalar'][$srcVar];
$rows =
count( $this->_vars[$srcTemplate]['rows'] );
for( $i =
0; $i <
$rows; $i++
)
if( !isset
( $this->_vars[$srcTemplate]['rows'][$i][$srcVar] ) )
if( !isset
( $this->_vars[$template]['rows'][$i] ) )
$this->_vars[$template]['rows'][$i] =
array();
$this->_vars[$template]['rows'][$i][$dest] =
$this->_vars[$srcTemplate]['rows'][$i][$srcVar];
if( !$copied && isset
( $this->_globals[$srcVar] ))
$this->_vars[$template]['scalar'][$dest] =
$this->_globals[$srcVar];
* parse all variables in a template
function _parseVariables( $template )
* modify variables before parsing
$this->_applyModifers($template, $this->_templates[$template]['vars']);
foreach( $this->_templates[$template]['vars'] as $key =>
$value )
if( count( $this->_templates[$template]['currentDependencies'] ) ==
1 )
$child =
$this->_templates[$template]['currentDependencies'][0];
if( isset
( $this->_templates[$template]['attributes']['child'] ) )
$child =
$this->_templates[$template]['attributes']['child'];
$this->addVar( $child, $key, $value );
$var =
$this->_startTag.
$key.
$this->_endTag;
$this->_templates[$template]['work'] =
str_replace( $var, $value, $this->_templates[$template]['work'] );
* parse global variables in the template
* @param string name of the template
function _parseGlobals($template)
$globalVars =
$this->_globals;
$this->_applyModifers($template, $globalVars);
foreach( $globalVars as $key =>
$value )
$var =
$this->_startTag.
$key.
$this->_endTag;
$this->_templates[$template]['result'] =
str_replace( $var, $value, $this->_templates[$template]['result'] );
* apply variable modifiers
* The variables will be passed by reference.
* @param string name of the template (use modifiers from this template)
* @param array variables to which the modifiers should be applied
function _applyModifers($template, &$vars)
foreach ($this->_templates[$template]['modifyVars'] as $varname =>
$modifier) {
if (!isset
($vars[$varname])) {
if (($modifier['type'] ===
'php' ||
$modifier['type'] ===
'auto' ) &&
is_callable($modifier['mod'])) {
if ($modifier['type'] ===
'php') {
$vars[$varname] =
$mod->modify( $vars[$varname], $modifier['params'] );
// apply the default modifier
if (isset
($this->_templates[$template]['attributes']['defaultmodifier'])) {
$defaultModifier =
$this->_templates[$template]['attributes']['defaultmodifier'];
if (isset
($this->_templates[$template]['modifyVars'][$varname])) {
$vars[$varname] =
$defaultModifier->modify($vars[$varname], array());
* parse all dependencies in a template
function _parseDependencies($template)
$countDep =
count( $this->_templates[$template]['currentDependencies'] );
for ($i =
0; $i <
$countDep; $i++
) {
$depTemplate =
$this->_templates[$template]['currentDependencies'][$i];
if ($depTemplate ==
$template) {
$var =
$this->_startTag.
'TMPL:'.
strtoupper( $depTemplate) .
$this->_endTag;
$this->_templates[$template]['work'] =
str_replace( $var, $this->_templates[$depTemplate]['result'], $this->_templates[$template]['work'] );
* The template content will be stored in the template
* configuration so it can be used by other
* @param string template name
function _fetchTemplate( $template )
switch( $this->_templates[$template]['attributes']['type'] )
$value =
$this->_getConditionValue($template, $this->_templates[$template]['attributes']['conditionvar']);
$this->_templates[$template]['work'] =
'';
$this->_templates[$template]['currentDependencies'] =
array();
$this->_templates[$template]['work'] =
$this->_templates[$template]['subtemplates'][$value]['data'];
$this->_templates[$template]['currentDependencies'] =
$this->_templates[$template]['subtemplates'][$value]['dependencies'];
foreach( $this->_templates[$template]['attributes']['requiredvars'] as $var )
// different template scope
if( $var[0] !==
$template ) {
$this->_fetchVariables($var[0]);
// fetch the local variable
if( isset
( $this->_templates[$var[0]]['vars'][$var[1]] )
&&
strlen( $this->_templates[$var[0]]['vars'][$var[1]] ) >
0 ) {
$value =
$this->_templates[$var[0]]['vars'][$var[1]];
if (isset
($this->_templates[$template]['attributes']['useglobals'])) {
if(isset
($this->_globals[$var[1]]) &&
strlen($this->_globals[$var[1]]) >
1) {
$value =
$this->_globals[$var[1]];
// Joomla! addition 23-June-2005
// value wrapped in ## uses regex for comparison
if (substr( $condition, 0, 1 ) ==
'#' &&
substr( $condition, -
1, 1 ) ==
'#' ) {
} else if ($condition ==
$value) {
$this->_templates[$template]['work'] =
'';
$this->_templates[$template]['currentDependencies'] =
array();
$this->_templates[$template]['work'] =
$this->_templates[$template]['content'];
$this->_templates[$template]['currentDependencies'] =
$this->_templates[$template]['dependencies'];
// check for empty template
if ($this->_hasVariables($template)) {
$value = (string)
($this->_templates[$template]['iteration'] +
1 ) %
$this->_templates[$template]['attributes']['modulo'];
$value =
$this->_getConditionValue($template, $value, false);
$this->_templates[$template]['work'] =
'';
$this->_templates[$template]['currentDependencies'] =
array();
$this->_templates[$template]['work'] =
$this->_templates[$template]['subtemplates'][$value]['data'];
$this->_templates[$template]['currentDependencies'] =
$this->_templates[$template]['subtemplates'][$value]['dependencies'];
$this->_templates[$template]['work'] =
$this->_templates[$template]['content'];
$this->_templates[$template]['currentDependencies'] =
$this->_templates[$template]['dependencies'];
* check, whether a template contains variables
* @param string template name
function _hasVariables($template)
if (!empty($this->_vars[$template]['scalar'])) {
if (isset
($this->_vars[$template]['rows'][$this->_templates[$template]['iteration']])) {
* fetch the value of a condition variable
* _fetchVariables() has to be called before this
* method is being called.
* @param string template name
* @param string condition value
* @param boolean flag that indicates whether value is the name of the variable that should be resolved
* @todo split this method into smaller check methods that will be called according to
function _getConditionValue( $template, $value, $isVar =
true )
if (isset
($this->_templates[$template]['attributes']['conditiontmpl'])) {
$_template =
$this->_templates[$template]['attributes']['conditiontmpl'];
$this->_fetchVariables($_template);
* get the value from the template variables
if (!isset
($this->_templates[$_template]['vars'][$value]) ||
strlen($this->_templates[$_template]['vars'][$value]) ===
0) {
if ($this->_templates[$template]['attributes']['useglobals'] ==
'yes' ||
$this->_templates[$template]['attributes']['useglobals'] ==
'useglobals') {
if (isset
( $this->_globals[$value] ) &&
strlen( $this->_globals[$value] ) >
0) {
$value =
$this->_globals[$value];
$value =
$this->_templates[$_template]['vars'][$value];
// if value is empty and a template for empty has been defined, this
if ($value ===
'__empty' && isset
($this->_templates[$template]['subtemplates']['__empty'])) {
// only one iteration (but not empty), use the __single condition
if ($value !==
'__empty' &&
$this->_templates[$_template]['loop'] ===
1) {
if( isset
($this->_templates[$template]['subtemplates']['__single'])) {
if( $this->_templates[$_template]['iteration'] ==
0 ) {
if( isset
( $this->_templates[$template]['subtemplates']['__first'] ) ) {
if (isset
($this->_templates[$_template]['loop'])) {
$max =
$this->_templates[$_template]['loop'] -
1;
if( $this->_templates[$_template]['iteration'] ==
$max ) {
if( isset
( $this->_templates[$template]['subtemplates']['__last'] ) ) {
// search for exact match
foreach (array_keys($this->_templates[$template]['subtemplates']) as $key) {
if (isset
($this->_templates[$template]['subtemplates'][$key]['attributes']['var'])) {
$var =
$this->_templates[$template]['subtemplates'][$key]['attributes']['var'];
if (isset
($this->_templates[$template]['vars'][$var])) {
$current =
$this->_templates[$template]['vars'][$var];
if ((string)
$value === (string)
$current) {
if( isset
( $this->_templates[$template]['subtemplates']['__default'] ) ) {
* fetch variables for a template
* The variables will be stored in the template
* configuration so they can be used by other
* @param string template name
function _fetchVariables( $template )
* variables already have been fetched
if (isset
($this->_templates[$template]['vars'])) {
$iteration =
$this->_templates[$template]['iteration'];
if( isset
( $this->_templates[$template]['attributes']['varscope'] ) )
if (!is_array($this->_templates[$template]['attributes']['varscope'])) {
$this->_templates[$template]['attributes']['varscope'] =
array($this->_templates[$template]['attributes']['varscope']);
foreach ($this->_templates[$template]['attributes']['varscope'] as $scopeTemplate) {
if ($this->exists($scopeTemplate)) {
$this->_fetchVariables( $scopeTemplate );
$vars =
array_merge($this->_templates[$scopeTemplate]['vars'], $vars);
* get the scalar variables
if( isset
( $this->_vars[$template] ) && isset
( $this->_vars[$template]['scalar'] ) )
$vars =
array_merge( $vars, $this->_vars[$template]['scalar'] );
if( isset
( $this->_vars[$template]['rows'][$iteration] ) )
$vars =
array_merge( $vars, $this->_vars[$template]['rows'][$iteration] );
* add some system variables
$currentRow =
$iteration +
$this->_templates[$template]['attributes']['rowoffset'];
$vars['PAT_ROW_VAR'] =
$currentRow;
if( $this->_templates[$template]['attributes']['type'] ==
'modulo' )
$vars['PAT_MODULO_REP'] =
ceil( $currentRow /
$this->_templates[$template]['attributes']['modulo'] );
$vars['PAT_MODULO'] =
( $this->_templates[$template]['iteration'] +
1 ) %
$this->_templates[$template]['attributes']['modulo'];
if( $this->_templates[$template]['attributes']['addsystemvars'] !==
false )
$vars['PATTEMPLATE_VERSION'] =
$this->_systemVars['appVersion'];
$vars['PAT_LOOPS'] =
$this->_templates[$template]['loop'];
switch ($this->_templates[$template]['attributes']['addsystemvars'])
$trueValue =
$this->_templates[$template]['attributes']['addsystemvars'];
$vars['PAT_IS_ODD'] =
( $currentRow %
2 ==
1 ) ?
$trueValue :
$falseValue;
$vars['PAT_IS_EVEN'] =
( $currentRow %
2 ==
0 ) ?
$trueValue :
$falseValue;
$vars['PAT_IS_FIRST'] =
( $currentRow ==
1 ) ?
$trueValue :
$falseValue;
$vars['PAT_IS_LAST'] =
( $currentRow ==
$this->_templates[$template]['loop'] ) ?
$trueValue :
$falseValue;
$vars['PAT_ROW_TYPE'] =
( $currentRow %
2 ==
1 ) ?
'odd' :
'even';
$this->_templates[$template]['vars'] =
$vars;
* handle all unused variables in a template
* This is influenced by the 'unusedvars' attribute of the
function _handleUnusedVars( $template )
$regexp =
'/([^\\\])('.
$this->_startTag.
'[^a-z]+[^\\\]'.
$this->_endTag.
')/U';
switch( $this->_templates[$template]['attributes']['unusedvars'] )
$this->_templates[$template]['result'] =
preg_replace( $regexp, '<!-- \\1\\2 -->', $this->_templates[$template]['result'] );
$this->_templates[$template]['result'] =
preg_replace( $regexp, '\\1', $this->_templates[$template]['result'] );
$this->_templates[$template]['result'] =
preg_replace( $regexp, '\\1 ', $this->_templates[$template]['result'] );
$this->_templates[$template]['result'] =
preg_replace( $regexp, '\\1'.
$this->_templates[$template]['attributes']['unusedvars'], $this->_templates[$template]['result'] );
// replace quoted variables
$regexp =
'/[\\\]'.
$this->_startTag.
'([^a-z]+)[\\\]'.
$this->_endTag.
'/U';
$this->_templates[$template]['result'] =
preg_replace( $regexp, $this->_startTag.
'\\1'.
$this->_endTag, $this->_templates[$template]['result'] );
* returns a parsed Template
* If the template already has been parsed, it just returns the parsed template.
* If the template has not been loaded, it will be loaded.
* @param string name of the template
* @param boolean whether to apply output filters
* @return string Content of the parsed template
* @see displayParsedTemplate()
if ($applyFilters ===
false) {
return $this->_templates[$name]['result'];
$result =
$this->_templates[$name]['result'];
$cnt =
count ($this->_outputFilters);
for ($i =
0; $i <
$cnt; $i++
) {
$result =
$this->_outputFilters[$i]->apply( $result );
* displays a parsed Template
* If the template has not been loaded, it will be loaded.
* @see getParsedTemplate()
* @param string name of the template
* @param boolean whether to apply output filters
* @return boolean true on success
* parse a template and push the result into a variable of any other
* If the template already has been parsed, it will just be pushed into the variable.
* If the template has not been loaded, it will be loaded.
* @param string name of the template
* @return string Content of the parsed template
* @param boolean if set to true, the value will be appended to the value already stored.
* @see getParsedTemplate()
function parseIntoVar( $srcTmpl, $destTmpl, $var, $append =
false )
if( $append !==
true ||
!isset
( $this->_vars[$destTmpl]['scalar'][$var] ) )
$this->_vars[$destTmpl]['scalar'][$var] =
'';
$this->_vars[$destTmpl]['scalar'][$var] .=
$this->_templates[$srcTmpl]['result'];
* clears a parsed Template
* Parsed Content, variables and the loop attribute are cleared
* If you will not be using this template anymore, then you should
* @param string name of the template
* @param boolean set this to true to clear all child templates, too
* @see clearAllTemplates()
$this->_templates[$name]['parsed'] =
false;
$this->_templates[$name]['work'] =
'';
$this->_templates[$name]['iteration'] =
0;
$this->_templates[$name]['result'] =
'';
$this->_vars[$name] =
array(
if (!empty($this->_templates[$name]['defaultVars'])) {
foreach ($this->_templates[$name]['defaultVars'] as $varname =>
$value) {
$this->addVar($name, $varname, $value);
* clear child templates as well
if( $recursive ===
true )
$deps =
$this->_getDependencies( $name );
$cnt =
count( $templates );
for( $i =
0; $i <
$cnt; $i++
)
* All memory consumed by the template
* @param string name of the template
* @param boolean clear dependencies of the template
* @see freeAllTemplates()
"Template '$name' does not exist."
unset
( $this->_templateList[$key] );
$this->_templateList =
array_values( $this->_templateList );
* free child templates as well
if( $recursive ===
true )
$deps =
$this->_getDependencies( $name );
unset
( $this->_templates[$name] );
unset
( $this->_vars[$name] );
if (isset
($this->_discoveredPlaceholders[$name])) {
unset
($this->_discoveredPlaceholders[$name]);
* All memory consumed by the templates
$this->_templates =
array();
$this->_templateList =
array();
* get _all_ dependencies of a template,
* regardless of the subtemplates
* @param string template name
* @return array list of all subtemplates
function _getDependencies( $template )
if( isset
( $this->_templates[$template]['dependencies'] ) )
$deps =
$this->_templates[$template]['dependencies'];
if( isset
( $this->_templates[$template]['subtemplates'] ) )
foreach( $this->_templates[$template]['subtemplates'] as $sub )
if( isset
( $sub['dependencies'] ) )
* Displays useful information about all or named templates
* This method breaks BC, as it now awaits an array instead of
* @param mixed array of templates that should be dumped, or null if you
* want all templates to be dumped
function dump( $restrict =
null, $dumper =
'Html' )
$restrict =
array( $restrict );
$templates =
$this->_templates;
$restrict =
array_map( 'strtolower', $restrict );
foreach( $this->_templates as $name =>
$spec )
$templates[$name] =
$spec;
$vars[$name] =
$this->_vars[$name];
$dumper->displayHeader();
$dumper->dumpGlobals( $this->_globals );
$dumper->dumpTemplates( $templates, $vars );
$dumper->displayFooter();
return PATTEMPLATE_INCLUDE_PATH;
* apply input filters that have been set
* This is being called by the readers.
* @return string filtered templeta
$cnt =
count( $this->_inputFilters );
for( $i =
0; $i <
$cnt; $i++
)
$template =
$this->_inputFilters[$i]->apply( $template );
* checks, whether a placeholder exists in a template
* @param string name of the placeholder
* @param string name of the template
* @param boolean whether to use the cached result of a previous call
if (isset
($this->_discoveredPlaceholders[$tmpl]) && isset
($this->_discoveredPlaceholders[$tmpl][$placeholder])) {
return $this->_discoveredPlaceholders[$tmpl][$placeholder];
if (isset
($this->_templates[$tmpl]['subtemplates'])) {
foreach ($this->_templates[$tmpl]['subtemplates'] as $temp) {
if (!isset
($temp['data'])) {
$content .=
$temp['data'];
$content =
$this->_templates[$tmpl]['content'];
$search =
$this->_startTag .
$placeholder .
$this->_endTag;
if (strstr($content, $search) !==
false) {
$this->_discoveredPlaceholders[$tmpl][$placeholder] =
true;
$this->_discoveredPlaceholders[$tmpl][$placeholder] =
false;
* Convert the template to its string representation.
* This method allows you to just echo the patTemplate
* object in order to display the template.
* $tmpl = new patTemplate();
* $tmpl->readTemplatesFromFile( 'myfile.tmpl' );