/lib/eztemplate/classes/eztemplate.php
PHP | 2720 lines | 1862 code | 229 blank | 629 comment | 266 complexity | 066270e1b01b7237178b8dde811833f7 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * File containing the eZTemplate class.
- *
- * @copyright Copyright (C) eZ Systems AS. All rights reserved.
- * @license For full copyright and license information view LICENSE file distributed with this source code.
- * @version //autogentag//
- * @package lib
- */
- /*! \defgroup eZTemplate Template system */
- /*!
- \class eZTemplate eztemplate.php
- \ingroup eZTemplate
- \brief The main manager for templates
- The template systems allows for separation of code and
- layout by moving the layout part into template files. These
- template files are parsed and processed with template variables set
- by the PHP code.
- The template system in itself is does not do much, it parses template files
- according to a rule set sets up a tree hierarchy and process the data
- using functions and operators. The standard template system comes with only
- a few functions and no operators, it is meant for these functions and operators
- to be specified by the users of the template system. But for simplicity a few
- help classes is available which can be easily enabled.
- The classes are:
- - eZTemplateDelimitFunction - Inserts the left and right delimiter which are normally parsed.
- - eZTemplateSectionFunction - Allows for conditional blocks and loops.
- - eZTemplateIncludeFunction - Includes external templates
- - eZTemplateSequenceFunction - Creates sequences arrays
- - eZTemplateSwitchFunction - Conditional output of template
- - eZTemplatePHPOperator - Allows for easy redirection of operator names to PHP functions.
- - eZTemplateLocaleOperator - Allows for locale conversions.
- - eZTemplateArrayOperator - Creates arrays
- - eZTemplateAttributeOperator - Displays contents of template variables, useful for debugging
- - eZTemplateImageOperator - Converts text to image
- - eZTemplateLogicOperator - Various logical operators for boolean handling
- - eZTemplateUnitOperator - Unit conversion and display
- To enable these functions and operator use registerFunction and registerOperator.
- In keeping with the spirit of being simple the template system does not know how
- to get the template files itself. Instead it relies on resource handlers, these
- handlers fetches the template files using different kind of transport mechanism.
- For simplicity a default resource class is available, eZTemplateFileResource fetches
- templates from the filesystem.
- The parser process consists of three passes, each pass adds a new level of complexity.
- The first pass strips text from template blocks which starts with a left delimiter and
- ends with a right delimiter (default is { and } ), and places them in an array.
- The second pass iterates the text and block elements and removes newlines from
- text before function blocks and text after function blocks.
- The third pass builds the tree according the function rules.
- Processing is done by iterating over the root of the tree, if a text block is found
- the text is appended to the result text. If a variable or contant is it's data is extracted
- and any operators found are run on it before fetching the result and appending it to
- the result text. If a function is found the function is called with the parameters
- and it's up to the function handle children if any.
- Constants and template variables will usually be called variables since there's little
- difference. A template variable expression will start with a $ and consists of a
- namespace (optional) a name and attribues(optional). The variable expression
- \verbatim $root:var.attr1 \endverbatim exists in the "root" namespace, has the name "var" and uses the
- attribute "attr1". Some functions will create variables on demand, to avoid name conflicts
- namespaces were introduced, each function will place the new variables in a namespace
- specified in the template file. Attribues are used for fetching parts of the variable,
- for instance an element in an array or data in an object. Since the syntax is the
- same for arrays and objects the PHP code can use simple arrays when speed is required,
- the template code will not care.
- A different syntax is also available when you want to access an attribute using a variable.
- For instance \verbatim $root:var[$attr_var] \endverbatim, if the variable $attr_var contains "attr1" it would
- access the same attribute as in the first example.
- The syntax for operators is a | and a name, optionally parameters can be specified with
- ( and ) delimited with ,. Valid operators are \verbatim |upcase, |l10n(date) \endverbatim.
- Functions look a lot like HTML/XML tags. The function consists of a name and parameters
- which are assigned using the param=value syntax. Some parameters may be required while
- others may be optionally, the exact behaviour is specified by each function.
- Valid functions are \verbatim "section name=abc loop=4" \endverbatim
- Example of usage:
- \code
- // Init template
- $tpl = eZTemplate::instance();
- $tpl->registerOperators( new eZTemplatePHPOperator( array( "upcase" => "strtoupper",
- "reverse" => "strrev" ) ) );
- $tpl->registerOperators( new eZTemplateLocaleOperator() );
- $tpl->registerFunction( "section", new eZTemplateSectionFunction( "section" ) );
- $tpl->registerFunctions( new eZTemplateDelimitFunction() );
- $tpl->setVariable( "my_var", "{this value set by variable}", "test" );
- $tpl->setVariable( "my_arr", array( "1st", "2nd", "third", "fjerde" ) );
- $tpl->setVariable( "multidim", array( array( "a", "b" ),
- array( "c", "d" ),
- array( "e", "f" ),
- array( "g", "h" ) ) );
- class mytest
- {
- function mytest( $n, $s )
- {
- $this->n = $n;
- $this->s = $s;
- }
- function hasAttribute( $attr )
- {
- return ( $attr == "name" || $attr == "size" );
- }
- function attribute( $attr )
- {
- switch ( $attr )
- {
- case "name";
- return $this->n;
- case "size";
- return $this->s;
- default:
- $retAttr = null;
- return $retAttr;
- }
- }
- }
- $tpl->setVariable( "multidim_obj", array( new mytest( "jan", 200 ),
- new mytest( "feb", 200 ),
- new mytest( "john", 200 ),
- new mytest( "doe", 50 ) ) );
- $tpl->setVariable( "curdate", time() );
- $tpl->display( "lib/eztemplate/example/test.tpl" );
- // test.tpl
- {section name=outer loop=4}
- 123
- {delimit}::{/delimit}
- {/section}
- {literal test=1} This is some {blah arg1="" arg2="abc" /} {/literal}
- <title>This is a test</title>
- <table border="1">
- <tr><th>{$test:my_var}
- {"some text!!!"|upcase|reverse}</th></tr>
- {section name=abc loop=$my_arr}
- <tr><td>{$abc:item}</td></tr>
- {/section}
- </table>
- <table border="1">
- {section name=outer loop=$multidim}
- <tr>
- {section name=inner loop=$outer:item}
- <td>{$inner:item}</td>
- {/section}
- </tr>
- {/section}
- </table>
- <table border="1">
- {section name=outer loop=$multidim_obj}
- <tr>
- <td>{$outer:item.name}</td>
- <td>{$outer:item.size}</td>
- </tr>
- {/section}
- </table>
- {section name=outer loop=$nonexistingvar}
- <b><i>Dette skal ikke vises</b></i>
- {section-else}
- <b><i>This is shown when the {ldelim}$loop{rdelim} variable is non-existant</b></i>
- {/section}
- Denne koster {1.4|l10n(currency)}<br>
- {-123456789|l10n(number)}<br>
- {$curdate|l10n(date)}<br>
- {$curdate|l10n(shortdate)}<br>
- {$curdate|l10n(time)}<br>
- {$curdate|l10n(shorttime)}<br>
- {include file="test2.tpl"/}
- \endcode
- */
- class eZTemplate
- {
- const RESOURCE_FETCH = 1;
- const RESOURCE_QUERY = 2;
- const ELEMENT_TEXT = 1;
- const ELEMENT_SINGLE_TAG = 2;
- const ELEMENT_NORMAL_TAG = 3;
- const ELEMENT_END_TAG = 4;
- const ELEMENT_VARIABLE = 5;
- const ELEMENT_COMMENT = 6;
- const NODE_ROOT = 1;
- const NODE_TEXT = 2;
- const NODE_VARIABLE = 3;
- const NODE_FUNCTION = 4;
- const NODE_OPERATOR = 5;
- const NODE_INTERNAL = 100;
- const NODE_INTERNAL_CODE_PIECE = 101;
- const NODE_INTERNAL_VARIABLE_SET = 105;
- const NODE_INTERNAL_VARIABLE_UNSET = 102;
- const NODE_INTERNAL_NAMESPACE_CHANGE = 103;
- const NODE_INTERNAL_NAMESPACE_RESTORE = 104;
- const NODE_INTERNAL_WARNING = 120;
- const NODE_INTERNAL_ERROR = 121;
- const NODE_INTERNAL_RESOURCE_ACQUISITION = 140;
- const NODE_OPTIMIZED_RESOURCE_ACQUISITION = 141;
- const NODE_INTERNAL_OUTPUT_ASSIGN = 150;
- const NODE_INTERNAL_OUTPUT_READ = 151;
- const NODE_INTERNAL_OUTPUT_INCREASE = 152;
- const NODE_INTERNAL_OUTPUT_DECREASE = 153;
- const NODE_INTERNAL_OUTPUT_SPACING_INCREASE = 160;
- const NODE_INTERNAL_SPACING_DECREASE = 161;
- const NODE_OPTIMIZED_INIT = 201;
- const NODE_USER_CUSTOM = 1000;
- const TYPE_VOID = 0;
- const TYPE_STRING = 1;
- const TYPE_NUMERIC = 2;
- const TYPE_IDENTIFIER = 3;
- const TYPE_VARIABLE = 4;
- const TYPE_ATTRIBUTE = 5;
- const TYPE_OPERATOR = 6;
- const TYPE_BOOLEAN = 7;
- const TYPE_ARRAY = 8;
- const TYPE_DYNAMIC_ARRAY = 9;
- const TYPE_INTERNAL = 100;
- const TYPE_INTERNAL_CODE_PIECE = 101;
- const TYPE_PHP_VARIABLE = 102;
- const TYPE_OPTIMIZED_NODE = 201;
- const TYPE_OPTIMIZED_ARRAY_LOOKUP = 202;
- const TYPE_OPTIMIZED_CONTENT_CALL = 203;
- const TYPE_OPTIMIZED_ATTRIBUTE_LOOKUP = 204;
- const TYPE_INTERNAL_STOP = 999;
- const TYPE_STRING_BIT = 1;
- const TYPE_NUMERIC_BIT = 2;
- const TYPE_IDENTIFIER_BIT = 4;
- const TYPE_VARIABLE_BIT = 8;
- const TYPE_ATTRIBUTE_BIT = 16;
- const TYPE_OPERATOR_BIT = 32;
- const TYPE_NONE = 0;
- const TYPE_ALL = 63;
- const TYPE_BASIC = 47;
- const TYPE_MODIFIER_MASK = 48;
- const NAMESPACE_SCOPE_GLOBAL = 1;
- const NAMESPACE_SCOPE_LOCAL = 2;
- const NAMESPACE_SCOPE_RELATIVE = 3;
- const DEBUG_INTERNALS = false;
- const FILE_ERRORS = 1;
- /**
- * Intializes the template with left and right delimiters being { and }, and a file resource.
- * The literal tag "literal" is also registered.
- */
- public function __construct()
- {
- $this->Tree = array( eZTemplate::NODE_ROOT, false );
- $this->LDelim = "{";
- $this->RDelim = "}";
- $this->IncludeText = array();
- $this->IncludeOutput = array();
- $this->registerLiteral( "literal" );
- $res = new eZTemplateFileResource();
- $this->DefaultResource = $res;
- $this->registerResource( $res );
- $this->Resources = array();
- $this->Text = null;
- $this->IsCachingAllowed = true;
- $this->resetErrorLog();
- $this->AutoloadPathList = array( 'lib/eztemplate/classes/' );
- $this->Variables = array();
- $this->LocalVariablesNamesStack = array();
- $this->CurrentLocalVariablesNames = null;
- $this->Functions = array();
- $this->FunctionAttributes = array();
- $this->TestCompile = false;
- $ini = eZINI::instance( 'template.ini' );
- if ( $ini->hasVariable( 'ControlSettings', 'MaxLevel' ) )
- $this->MaxLevel = $ini->variable( 'ControlSettings', 'MaxLevel' );
- $this->MaxLevelWarning = ezpI18n::tr( 'lib/template',
- 'The maximum nesting level of %max has been reached. The execution is stopped to avoid infinite recursion.',
- '',
- array( '%max' => $this->MaxLevel ) );
- eZDebug::createAccumulatorGroup( 'template_total', 'Template Total' );
- $this->TemplatesUsageStatistics = array();
- // Array of templates which are used in a single fetch()
- $this->TemplateFetchList = array();
- $this->ForeachCounter = 0;
- $this->ForCounter = 0;
- $this->WhileCounter = 0;
- $this->DoCounter = 0;
- $this->ElseifCounter = 0;
- }
- /*!
- Returns the left delimiter being used.
- */
- function leftDelimiter()
- {
- return $this->LDelim;
- }
- /*!
- Returns the right delimiter being used.
- */
- function rightDelimiter()
- {
- return $this->RDelim;
- }
- /*!
- Sets the left delimiter.
- */
- function setLeftDelimiter( $delim )
- {
- $this->LDelim = $delim;
- }
- /*!
- Sets the right delimiter.
- */
- function setRightDelimiter( $delim )
- {
- $this->RDelim = $delim;
- }
- /*!
- Fetches the result of the template file and displays it.
- If $template is supplied it will load this template file first.
- */
- function display( $template = false, $extraParameters = false )
- {
- $output = $this->fetch( $template, $extraParameters );
- if ( $this->ShowDetails )
- {
- echo '<h1>Result:</h1>' . "\n";
- echo '<hr/>' . "\n";
- }
- echo "$output";
- if ( $this->ShowDetails )
- {
- echo '<hr/>' . "\n";
- }
- if ( $this->ShowDetails )
- {
- echo "<h1>Template data:</h1>";
- echo "<p class=\"filename\">" . $template . "</p>";
- echo "<pre class=\"example\">" . htmlspecialchars( $this->Text ) . "</pre>";
- reset( $this->IncludeText );
- while ( ( $key = key( $this->IncludeText ) ) !== null )
- {
- $item = $this->IncludeText[$key];
- echo "<p class=\"filename\">" . $key . "</p>";
- echo "<pre class=\"example\">" . htmlspecialchars( $item ) . "</pre>";
- next( $this->IncludeText );
- }
- echo "<h1>Result text:</h1>";
- echo "<p class=\"filename\">" . $template . "</p>";
- echo "<pre class=\"example\">" . htmlspecialchars( $output ) . "</pre>";
- reset( $this->IncludeOutput );
- while ( ( $key = key( $this->IncludeOutput ) ) !== null )
- {
- $item = $this->IncludeOutput[$key];
- echo "<p class=\"filename\">" . $key . "</p>";
- echo "<pre class=\"example\">" . htmlspecialchars( $item ) . "</pre>";
- next( $this->IncludeOutput );
- }
- }
- }
- /*!
- * Initialize list of local variables for the current template.
- * The list contains only names of variables.
- */
- function createLocalVariablesList()
- {
- $this->LocalVariablesNamesStack[] = array();
- $this->CurrentLocalVariablesNames =& $this->LocalVariablesNamesStack[ count( $this->LocalVariablesNamesStack ) - 1];
- }
- /*!
- * Check if the given local variable exists.
- */
- function hasLocalVariable( $varName, $rootNamespace )
- {
- return ( array_key_exists( $rootNamespace, $this->CurrentLocalVariablesNames ) &&
- array_key_exists( $varName, $this->CurrentLocalVariablesNames[$rootNamespace] ) );
- }
- /*!
- * Create a local variable.
- */
- function setLocalVariable( $varName, $varValue, $rootNamespace )
- {
- $this->CurrentLocalVariablesNames[$rootNamespace][$varName] = 1;
- $this->setVariable( $varName, $varValue, $rootNamespace );
- }
- /*!
- * Destroy a local variable.
- */
- function unsetLocalVariable( $varName, $rootNamespace )
- {
- if ( !$this->hasLocalVariable( $varName, $rootNamespace ) )
- return;
- $this->unsetVariable( $varName, $rootNamespace );
- unset( $this->CurrentLocalVariablesNames[$rootNamespace][$varName] );
- }
- /*!
- * Destroy all local variables defined in the current template.
- */
- function unsetLocalVariables()
- {
- foreach ( $this->CurrentLocalVariablesNames as $ns => $vars )
- {
- foreach ( $vars as $var => $val )
- $this->unsetLocalVariable( $var, $ns );
- }
- }
- /*!
- * Destroy list of local variables defined in the current (innermost) template.
- */
- function destroyLocalVariablesList()
- {
- array_pop( $this->LocalVariablesNamesStack );
- if ( $this->LocalVariablesNamesStack )
- $this->CurrentLocalVariablesNames =& $this->LocalVariablesNamesStack[ count( $this->LocalVariablesNamesStack ) - 1];
- else
- unset( $this->CurrentLocalVariablesNames );
- }
- /*!
- Tries to fetch the result of the template file and returns it.
- If $template is supplied it will load this template file first.
- */
- function fetch( $template = false, $extraParameters = false, $returnResourceData = false )
- {
- $this->resetErrorLog();
- // Reset fetch list when a new fetch is started
- $this->TemplateFetchList = array();
- eZDebug::accumulatorStart( 'template_total' );
- eZDebug::accumulatorStart( 'template_load', 'template_total', 'Template load' );
- $root = null;
- if ( is_string( $template ) )
- {
- $resourceData = $this->loadURIRoot( $template, true, $extraParameters );
- if ( $resourceData and
- $resourceData['root-node'] !== null )
- $root =& $resourceData['root-node'];
- }
- eZDebug::accumulatorStop( 'template_load' );
- if ( $resourceData['locales'] && !empty( $resourceData['locales'] ) )
- {
- $savedLocale = setlocale( LC_CTYPE, null );
- setlocale( LC_CTYPE, $resourceData['locales'] );
- }
- $text = "";
- if ( $root !== null or
- $resourceData['compiled-template'] )
- {
- if ( $this->ShowDetails )
- eZDebug::addTimingPoint( "Process" );
- eZDebug::accumulatorStart( 'template_processing', 'template_total', 'Template processing' );
- $templateCompilationUsed = false;
- if ( $resourceData['compiled-template'] )
- {
- $textElements = array();
- if ( $this->executeCompiledTemplate( $resourceData, $textElements, "", "", $extraParameters ) )
- {
- $text = implode( '', $textElements );
- $templateCompilationUsed = true;
- }
- }
- if ( !$templateCompilationUsed )
- {
- if ( eZTemplate::isDebugEnabled() )
- {
- $fname = $resourceData['template-filename'];
- eZDebug::writeDebug( "FETCH START URI: $template, $fname" );
- }
- $this->process( $root, $text, "", "" );
- if ( eZTemplate::isDebugEnabled() )
- eZDebug::writeDebug( "FETCH END URI: $template, $fname" );
- }
- eZDebug::accumulatorStop( 'template_processing' );
- if ( $this->ShowDetails )
- eZDebug::addTimingPoint( "Process done" );
- }
- eZDebug::accumulatorStop( 'template_total' );
- if ( $resourceData['locales'] && !empty( $resourceData['locales'] ) )
- {
- setlocale( LC_CTYPE, $savedLocale );
- }
- if ( $returnResourceData )
- {
- $resourceData['result_text'] = $text;
- return $resourceData;
- }
- return $text;
- }
- function process( $root, &$text, $rootNamespace, $currentNamespace )
- {
- $this->createLocalVariablesList();
- $textElements = array();
- $this->processNode( $root, $textElements, $rootNamespace, $currentNamespace );
- if ( is_array( $textElements ) )
- $text = implode( '', $textElements );
- else
- $text = $textElements;
- $this->unsetLocalVariables();
- $this->destroyLocalVariablesList();
- }
- function processNode( $node, &$textElements, $rootNamespace, $currentNamespace )
- {
- $rslt = null;
- $nodeType = $node[0];
- if ( $nodeType == eZTemplate::NODE_ROOT )
- {
- $children = $node[1];
- if ( $children )
- {
- foreach ( $children as $child )
- {
- $this->processNode( $child, $textElements, $rootNamespace, $currentNamespace );
- if ( !is_array( $textElements ) )
- eZDebug::writeError( "Textelements is no longer array: '$textElements'", __METHOD__ . '::root' );
- }
- }
- }
- else if ( $nodeType == eZTemplate::NODE_TEXT )
- {
- $textElements[] = $node[2];
- }
- else if ( $nodeType == eZTemplate::NODE_VARIABLE )
- {
- $variableData = $node[2];
- $variablePlacement = $node[3];
- $this->processVariable( $textElements, $variableData, $variablePlacement, $rootNamespace, $currentNamespace );
- if ( !is_array( $textElements ) )
- eZDebug::writeError( "Textelements is no longer array: '$textElements'", __METHOD__ . '::variable' );
- }
- else if ( $nodeType == eZTemplate::NODE_FUNCTION )
- {
- $functionChildren = $node[1];
- $functionName = $node[2];
- $functionParameters = $node[3];
- $functionPlacement = $node[4];
- $rslt = $this->processFunction( $functionName, $textElements, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace );
- if ( !is_array( $textElements ) )
- eZDebug::writeError( "Textelements is no longer array: '$textElements'", __METHOD__ . "::function( '$functionName' )" );
- }
- return $rslt;
- }
- function processVariable( &$textElements, $variableData, $variablePlacement, $rootNamespace, $currentNamespace )
- {
- $value = $this->elementValue( $variableData, $rootNamespace, $currentNamespace, $variablePlacement );
- $this->appendElementText( $textElements, $value, $rootNamespace, $currentNamespace );
- }
- function processFunction( $functionName, &$textElements, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace )
- {
- // Note: This code piece is replicated in the eZTemplateCompiler,
- // if this code is changed the replicated code must be updated as well.
- $func = $this->Functions[$functionName];
- if ( is_array( $func ) )
- {
- $this->loadAndRegisterFunctions( $this->Functions[$functionName] );
- $func = $this->Functions[$functionName];
- }
- if ( isset( $func ) and
- is_object( $func ) )
- {
- if ( eZTemplate::isMethodDebugEnabled() )
- eZDebug::writeDebug( "START FUNCTION: $functionName" );
- $value = $func->process( $this, $textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace );
- if ( eZTemplate::isMethodDebugEnabled() )
- eZDebug::writeDebug( "END FUNCTION: $functionName" );
- return $value;
- }
- else
- {
- $this->warning( "", "Function \"$functionName\" is not registered" );
- return null;
- }
- }
- function fetchFunctionObject( $functionName )
- {
- $func = $this->Functions[$functionName];
- if ( is_array( $func ) )
- {
- $this->loadAndRegisterFunctions( $this->Functions[$functionName] );
- $func = $this->Functions[$functionName];
- }
- return $func;
- }
- /*!
- Loads the template using the URI $uri and parses it.
- \return The root node of the tree if \a $returnResourceData is false,
- if \c true the entire resource data structure.
- */
- function load( $uri, $extraParameters = false, $returnResourceData = false )
- {
- $resourceData = $this->loadURIRoot( $uri, true, $extraParameters );
- if ( !$resourceData or
- $resourceData['root-node'] === null )
- {
- $retValue = null;
- return $retValue;
- }
- else
- return $resourceData['root-node'];
- }
- function parse( $sourceText, &$rootElement, $rootNamespace, &$resourceData )
- {
- $parser = eZTemplateMultiPassParser::instance();
- $parser->parse( $this, $sourceText, $rootElement, $rootNamespace, $resourceData );
- }
- function loadURIData( $resourceObject, $uri, $resourceName, $template, &$extraParameters, $displayErrors = true )
- {
- $resourceData = $this->resourceData( $resourceObject, $uri, $resourceName, $template );
- $resourceData['text'] = null;
- $resourceData['root-node'] = null;
- $resourceData['compiled-template'] = false;
- $resourceData['time-stamp'] = null;
- $resourceData['key-data'] = null;
- $resourceData['locales'] = null;
- if ( !$resourceObject->handleResource( $this, $resourceData, eZTemplate::RESOURCE_FETCH, $extraParameters ) )
- {
- $resourceData = null;
- if ( $displayErrors )
- $this->warning( "", "No template could be loaded for \"$template\" using resource \"$resourceName\"" );
- }
- return $resourceData;
- }
- /*!
- \static
- Creates a resource data structure of the parameters and returns it.
- This structure is passed to various parts of the template system.
- \note If you only have the URI you should call resourceFor() first to
- figure out the resource handler.
- */
- function resourceData( $resourceObject, $uri, $resourceName, $templateName )
- {
- $resourceData = array();
- $resourceData['uri'] = $uri;
- $resourceData['resource'] = $resourceName;
- $resourceData['template-name'] = $templateName;
- $resourceData['template-filename'] = $templateName;
- $resourceData['handler'] = $resourceObject;
- $resourceData['test-compile'] = $this->TestCompile;
- return $resourceData;
- }
- /*!
- Loads the template using the URI $uri and returns a structure with the text and timestamp,
- false otherwise.
- The structure keys are:
- - "text", the text.
- - "time-stamp", the timestamp.
- */
- function loadURIRoot( $uri, $displayErrors = true, &$extraParameters )
- {
- $res = "";
- $template = "";
- $resobj = $this->resourceFor( $uri, $res, $template );
- if ( !is_object( $resobj ) )
- {
- if ( $displayErrors )
- $this->warning( "", "No resource handler for \"$res\" and no default resource handler, aborting." );
- return null;
- }
- $canCache = true;
- if ( !$resobj->servesStaticData() )
- $canCache = false;
- if ( !$this->isCachingAllowed() )
- $canCache = false;
- $resourceData = $this->loadURIData( $resobj, $uri, $res, $template, $extraParameters, $displayErrors );
- if ( $resourceData )
- {
- eZTemplate::appendTemplateToStatisticsIfNeeded( $resourceData['template-name'], $resourceData['template-filename'] );
- $this->appendTemplateFetch( $resourceData['template-filename'] );
- if ( !$resourceData['compiled-template'] and
- $resourceData['root-node'] === null )
- {
- $resourceData['root-node'] = array( eZTemplate::NODE_ROOT, false );
- $templateText = $resourceData["text"];
- $keyData = $resourceData['key-data'];
- $this->setIncludeText( $uri, $templateText );
- $rootNamespace = '';
- $this->parse( $templateText, $resourceData['root-node'], $rootNamespace, $resourceData );
- if ( eZTemplate::isDebugEnabled() )
- {
- $this->appendDebugNodes( $resourceData['root-node'], $resourceData );
- }
- if ( $canCache )
- $resobj->setCachedTemplateTree( $keyData, $uri, $res, $template, $extraParameters, $resourceData['root-node'] );
- }
- if ( !$resourceData['compiled-template'] and
- $canCache and
- $this->canCompileTemplate( $resourceData, $extraParameters ) )
- {
- $generateStatus = $this->compileTemplate( $resourceData, $extraParameters );
- if ( $generateStatus )
- $resourceData['compiled-template'] = true;
- }
- }
- return $resourceData;
- }
- function processURI( $uri, $displayErrors = true, &$extraParameters,
- &$textElements, $rootNamespace, $currentNamespace )
- {
- $this->Level++;
- if ( $this->Level > $this->MaxLevel )
- {
- eZDebug::writeError( $this->MaxLevelWarning, __METHOD__ . " Level: $this->Level @ $uri" );
- $textElements[] = $this->MaxLevelWarning;
- $this->Level--;
- return;
- }
- $resourceData = $this->loadURIRoot( $uri, $displayErrors, $extraParameters );
- if ( !$resourceData or
- ( !$resourceData['compiled-template'] and
- $resourceData['root-node'] === null ) )
- {
- $this->Level--;
- return;
- }
- $templateCompilationUsed = false;
- if ( $resourceData['locales'] && !empty( $resourceData['locales'] ) )
- {
- $savedLocale = setlocale( LC_CTYPE, null );
- setlocale( LC_CTYPE, $resourceData['locales'] );
- }
- if ( $resourceData['compiled-template'] )
- {
- if ( $this->executeCompiledTemplate( $resourceData, $textElements, $rootNamespace, $currentNamespace, $extraParameters ) )
- $templateCompilationUsed = true;
- }
- if ( !$templateCompilationUsed )
- {
- $text = null;
- if ( eZTemplate::isDebugEnabled() )
- {
- $fname = $resourceData['template-filename'];
- eZDebug::writeDebug( "START URI: $uri, $fname" );
- }
- $this->process( $resourceData['root-node'], $text, $rootNamespace, $currentNamespace );
- if ( eZTemplate::isDebugEnabled() )
- eZDebug::writeDebug( "END URI: $uri, $fname" );
- $this->setIncludeOutput( $uri, $text );
- $textElements[] = $text;
- }
- if ( $resourceData['locales'] && !empty( $resourceData['locales'] ) )
- {
- setlocale( LC_CTYPE, $savedLocale );
- }
- $this->Level--;
- }
- function canCompileTemplate( $resourceData, &$extraParameters )
- {
- $resourceObject = $resourceData['handler'];
- if ( !$resourceObject )
- return false;
- $canGenerate = $resourceObject->canCompileTemplate( $this, $resourceData, $extraParameters );
- return $canGenerate;
- }
- /*!
- Validates the template file \a $file and returns \c true if the file has correct syntax.
- \param $returnResourceData If \c true then the returned value will be the resourcedata structure
- \sa compileTemplateFile(), fetch()
- */
- function validateTemplateFile( $file, $returnResourceData = false )
- {
- $this->resetErrorLog();
- if ( !file_exists( $file ) )
- return false;
- $resourceHandler = $this->resourceFor( $file, $resourceName, $templateName );
- if ( !$resourceHandler )
- return false;
- $resourceData = $this->resourceData( $resourceHandler, $file, $resourceName, $templateName );
- $resourceData['key-data'] = "file:" . $file;
- $extraParameters = array();
- // Disable caching/compiling while fetchin the resource
- // It will be restored afterwards
- $isCachingAllowed = $this->IsCachingAllowed;
- $this->IsCachingAllowed = false;
- $resourceHandler->handleResource( $this, $resourceData, eZTemplate::RESOURCE_FETCH, $extraParameters );
- // Restore previous caching flag
- $this->IsCachingAllowed = $isCachingAllowed;
- $root =& $resourceData['root-node'];
- $root = array( eZTemplate::NODE_ROOT, false );
- $templateText = $resourceData["text"];
- $rootNamespace = '';
- $this->parse( $templateText, $root, $rootNamespace, $resourceData );
- if ( eZTemplate::isDebugEnabled() )
- {
- $this->appendDebugNodes( $root, $resourceData );
- }
- $result = !$this->hasErrors() and !$this->hasWarnings();
- if ( $returnResourceData )
- {
- $resourceData['result'] = $result;
- $resourceData['errors'] = $this->ErrorLog();
- $resourceData['warnings'] = $this->WarningLog();
- return $resourceData;
- }
- return $result;
- }
- /*!
- Compiles the template file \a $file and returns \c true if the compilation was OK.
- \param $returnResourceData If \c true then the returned value will be the resourcedata structure
- \sa validateTemplateFile(), fetch()
- */
- function compileTemplateFile( $file, $returnResourceData = false )
- {
- $this->resetErrorLog();
- if ( !file_exists( $file ) )
- return false;
- $resourceHandler = $this->resourceFor( $file, $resourceName, $templateName );
- if ( !$resourceHandler )
- return false;
- $resourceData = $this->resourceData( $resourceHandler, $file, $resourceName, $templateName );
- $resourceData['key-data'] = "file:" . $file;
- $key = md5( $resourceData['key-data'] );
- $extraParameters = array();
- $resourceHandler->handleResource( $this, $resourceData, eZTemplate::RESOURCE_FETCH, $extraParameters );
- $isCompiled = false;
- if ( isset( $resourceData['compiled-template'] ) )
- $isCompiled = $resourceData['compiled-template'];
- if ( !$isCompiled )
- {
- $root =& $resourceData['root-node'];
- $root = array( eZTemplate::NODE_ROOT, false );
- $templateText = $resourceData["text"];
- $rootNamespace = '';
- $this->parse( $templateText, $root, $rootNamespace, $resourceData );
- if ( eZTemplate::isDebugEnabled() )
- {
- $this->appendDebugNodes( $root, $resourceData );
- }
- $result = eZTemplateCompiler::compileTemplate( $this, $key, $resourceData );
- }
- else
- {
- $result = true;
- }
- if ( $returnResourceData )
- {
- $resourceData['result'] = $result;
- return $resourceData;
- }
- return $result;
- }
- function compileTemplate( &$resourceData, &$extraParameters )
- {
- $resourceObject = $resourceData['handler'];
- if ( !$resourceObject )
- return false;
- $keyData = $resourceData['key-data'];
- $uri = $resourceData['uri'];
- $resourceName = $resourceData['resource'];
- $templatePath = $resourceData['template-name'];
- return $resourceObject->compileTemplate( $this, $keyData, $uri, $resourceName, $templatePath, $extraParameters, $resourceData );
- }
- function executeCompiledTemplate( &$resourceData, &$textElements, $rootNamespace, $currentNamespace, &$extraParameters )
- {
- $resourceObject = $resourceData['handler'];
- if ( !$resourceObject )
- return false;
- $keyData = $resourceData['key-data'];
- $uri = $resourceData['uri'];
- $resourceName = $resourceData['resource'];
- $templatePath = $resourceData['template-name'];
- $timestamp = $resourceData['time-stamp'];
- return $resourceObject->executeCompiledTemplate( $this, $textElements,
- $keyData, $uri, $resourceData, $templatePath,
- $extraParameters, $timestamp,
- $rootNamespace, $currentNamespace );
- }
- /*!
- Returns the resource object for URI $uri. If a resource type is specified
- in the URI it is extracted and set in $res. The template name is set in $template
- without any resource specifier. To specify a resource the name and a ":" is
- prepended to the URI, for instance file:my.tpl.
- If no resource type is found the URI the default resource handler is used.
- */
- function resourceFor( $uri, &$res, &$template )
- {
- $args = explode( ":", $uri );
- if ( isset( $args[1] ) )
- {
- $res = $args[0];
- $template = $args[1];
- }
- else
- $template = $uri;
- if ( eZTemplate::isDebugEnabled() )
- {
- eZDebug::writeNotice( "eZTemplate: Loading template \"$template\" with resource \"$res\"" );
- }
- if ( isset( $this->Resources[$res] ) and is_object( $this->Resources[$res] ) )
- {
- return $this->Resources[$res];
- }
- return $this->DefaultResource;
- }
- /*!
- \return The resource handler object for resource name \a $resourceName.
- \sa resourceFor
- */
- function resourceHandler( $resourceName )
- {
- if ( isset( $this->Resources[$resourceName] ) &&
- is_object( $this->Resources[$resourceName] ) )
- {
- return $this->Resources[$resourceName];
- }
- return $this->DefaultResource;
- }
- function hasChildren( &$function, $functionName )
- {
- $hasChildren = $function->hasChildren();
- if ( is_array( $hasChildren ) )
- return $hasChildren[$functionName];
- else
- return $hasChildren;
- }
- /*!
- Returns the empty variable type.
- */
- function emptyVariable()
- {
- return array( "type" => "null" );
- }
- /*!
- \static
- */
- function mergeNamespace( $rootNamespace, $additionalNamespace )
- {
- $namespace = $rootNamespace;
- if ( $namespace == '' )
- $namespace = $additionalNamespace;
- else if ( $additionalNamespace != '' )
- $namespace = "$namespace:$additionalNamespace";
- return $namespace;
- }
- /*!
- Returns the actual value of a template type or null if an unknown type.
- */
- function elementValue( &$dataElements, $rootNamespace, $currentNamespace, $placement = false,
- $checkExistance = false, $checkForProxy = false )
- {
- /*
- * We use a small dirty hack in this function...
- * To help the caller to determine if the value was a proxy object,
- * we store boolean true to $dataElements['proxy-object-found'] in this case.
- * (it's up to caller to remove this garbage from $dataElements...)
- * This behaviour is enabled by $checkForProxy parameter.
- */
- $value = null;
- if ( !is_array( $dataElements ) )
- {
- $this->error( "elementValue",
- "Missing array data structure, got " . gettype( $dataElements ),
- $placement );
- return null;
- }
- foreach ( $dataElements as $dataElement )
- {
- if ( $dataElement === null )
- {
- return null;
- }
- $dataType = $dataElement[0];
- switch ( $dataType )
- {
- case eZTemplate::TYPE_VOID:
- {
- if ( !$checkExistance )
- $this->warning( 'elementValue',
- 'Found void datatype, should not be used' );
- else
- {
- return null;
- }
- } break;
- case eZTemplate::TYPE_STRING:
- case eZTemplate::TYPE_NUMERIC:
- case eZTemplate::TYPE_IDENTIFIER:
- case eZTemplate::TYPE_BOOLEAN:
- case eZTemplate::TYPE_ARRAY:
- {
- $value = $dataElement[1];
- } break;
- case eZTemplate::TYPE_VARIABLE:
- {
- $variableData = $dataElement[1];
- $variableNamespace = $variableData[0];
- $variableNamespaceScope = $variableData[1];
- $variableName = $variableData[2];
- if ( $variableNamespaceScope == eZTemplate::NAMESPACE_SCOPE_GLOBAL )
- $namespace = $variableNamespace;
- else if ( $variableNamespaceScope == eZTemplate::NAMESPACE_SCOPE_LOCAL )
- $namespace = $this->mergeNamespace( $rootNamespace, $variableNamespace );
- else if ( $variableNamespaceScope == eZTemplate::NAMESPACE_SCOPE_RELATIVE )
- $namespace = $this->mergeNamespace( $currentNamespace, $variableNamespace );
- else
- $namespace = false;
- if ( $this->hasVariable( $variableName, $namespace ) )
- {
- $value = $this->variable( $variableName, $namespace );
- }
- else
- {
- if ( !$checkExistance )
- $this->error( '', "Unknown template variable '$variableName' in namespace '$namespace'", $placement );
- {
- return null;
- }
- }
- } break;
- case eZTemplate::TYPE_ATTRIBUTE:
- {
- $attributeData = $dataElement[1];
- $attributeValue = $this->elementValue( $attributeData, $rootNamespace, $currentNamespace, $placement, $checkExistance );
- if ( $attributeValue !== null )
- {
- if ( !is_numeric( $attributeValue ) and
- !is_string( $attributeValue ) and
- !is_bool( $attributeValue ) )
- {
- if ( !$checkExistance )
- $this->error( "",
- "Cannot use type " . gettype( $attributeValue ) . " for attribute lookup", $placement );
- {
- return null;
- }
- }
- if ( is_array( $value ) )
- {
- if ( array_key_exists( $attributeValue, $value ) )
- {
- $value = $value[$attributeValue];
- }
- else
- {
- if ( !$checkExistance )
- {
- $arrayAttributeList = array_keys( $value );
- $arrayCount = count( $arrayAttributeList );
- $errorMessage = "No such attribute for array($arrayCount): $attributeValue";
- $chooseText = "Choose one of following: ";
- $errorMessage .= "\n$chooseText";
- $errorMessage .= $this->expandAttributes( $arrayAttributeList, $chooseText, 25 );
- $this->error( "",
- $errorMessage, $placement );
- }
- return null;
- }
- }
- else if ( is_object( $value ) )
- {
- if ( method_exists( $value, "attribute" ) and
- method_exists( $value, "hasAttribute" ) )
- {
- if ( $value->hasAttribute( $attributeValue ) )
- {
- $value = $value->attribute( $attributeValue );
- }
- else
- {
- if ( !$checkExistance )
- {
- $objectAttributeList = array();
- if ( method_exists( $value, 'attributes' ) )
- $objectAttributeList = $value->attributes();
- $objectClass= get_class( $value );
- $errorMessage = "No such attribute for object($objectClass): $attributeValue";
- $chooseText = "Choose one of following: ";
- $errorMessage .= "\n$chooseText";
- $errorMessage .= $this->expandAttributes( $objectAttributeList, $chooseText, 25 );
- $this->error( "",
- $errorMessage, $placement );
- }
- return null;
- }
- }
- else
- {
- if ( !$checkExistance )
- $this->error( "",
- "Cannot retrieve attribute of object(" . get_class( $value ) .
- "), no attribute functions available",
- $placement );
- return null;
- }
- }
- else
- {
- if ( !$checkExistance )
- $this->error( "",
- "Cannot retrieve attribute of a " . gettype( $value ),
- $placement );
- return null;
- }
- }
- else
- {
- if ( !$checkExistance )
- $this->error( '',
- 'Attribute value was null, cannot get attribute',
- $placement );
- return null;
- }
- } break;
- case eZTemplate::TYPE_OPERATOR:
- {
- $operatorParameters = $dataElement[1];
- $operatorName = $operatorParameters[0];
- $operatorParameters = array_splice( $operatorParameters, 1 );
- if ( is_object( $value ) and
- method_exists( $value, 'templateValue' ) )
- {
- if ( $checkForProxy )
- $dataElements['proxy-object-found'] = true;
- $value = $value->templateValue();
- }
- $valueData = array( 'value' => $value );
- $this->processOperator( $operatorName, $operatorParameters, $rootNamespace, $currentNamespace,
- $valueData, $placement, $checkExistance );
- $value = $valueData['value'];
- } break;
- default:
- {
- if ( !$checkExistance )
- $this->error( "elementValue",
- "Unknown data type: '$dataType'",
- $placement );
- return null;
- }
- }
- }
- if ( is_object( $value ) and
- method_exists( $value, 'templateValue' ) )
- {
- if ( $checkForProxy )
- $dataElements['proxy-object-found'] = true;
- return $value->templateValue();
- }
- return $value;
- }
- function expandAttributes( $attributeList, $chooseText, $maxThreshold, $minThreshold = 1 )
- {
- $errorMessage = '';
- $attributeCount = count( $attributeList );
- if ( $attributeCount < $minThreshold )
- return $errorMessage;
- if ( $attributeCount < $maxThreshold )
- {
- $chooseLength = strlen( $chooseText );
- $attributeText = '';
- $i = 0;
- foreach ( $attributeList as $attributeName )
- {
- if ( $i > 0 )
- $attributeText .= ",";
- if ( strlen( $attributeText ) > 40 )
- {
- $attributeText .= "\n";
- $errorMessage .= $attributeText;
- $errorMessage .= str_repeat( ' ', $chooseLength );
- $attributeText = '';
- }
- else if ( $i > 0 )
- $attributeText .= " ";
- $attributeText .= $attributeName;
- ++$i;
- }
- $errorMessage .= $attributeText;
- }
- return $errorMessage;
- }
- function processOperator( $operatorName, $operatorParameters, $rootNamespace, $currentNamespace,
- &$valueData, $placement = false, $checkExistance = false )
- {
- $namedParameters = array();
- $operatorParameterDefinition = $this->operatorParameterList( $operatorName );
- $i = 0;
- foreach ( $operatorParameterDefinition as $parameterName => $parameterType )
- {
- if ( !isset( $operatorParameters[$i] ) or
- !isset( $operatorParameters[$i][0] ) or
- $operatorParameters[$i][0] == eZTemplate::TYPE_VOID )
- {
- if ( $parameterType["required"] )
- {
- if ( !$checkExistance )
- $this->warning( "eZTemplateOperatorElement", "Par…
Large files files are truncated, but you can click here to view the full file