|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZTemplate class 00004 // 00005 // Created on: <01-Mar-2002 13:49:57 amos> 00006 // 00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00008 // SOFTWARE NAME: eZ Publish 00009 // SOFTWARE RELEASE: 4.0.x 00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS 00011 // SOFTWARE LICENSE: GNU General Public License v2.0 00012 // NOTICE: > 00013 // This program is free software; you can redistribute it and/or 00014 // modify it under the terms of version 2.0 of the GNU General 00015 // Public License as published by the Free Software Foundation. 00016 // 00017 // This program is distributed in the hope that it will be useful, 00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 // GNU General Public License for more details. 00021 // 00022 // You should have received a copy of version 2.0 of the GNU General 00023 // Public License along with this program; if not, write to the Free 00024 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00025 // MA 02110-1301, USA. 00026 // 00027 // 00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00029 // 00030 00031 /*! \file eztemplate.php 00032 Template system manager. 00033 */ 00034 00035 /*! \defgroup eZTemplate Template system */ 00036 00037 /*! 00038 \class eZTemplate eztemplate.php 00039 \ingroup eZTemplate 00040 \brief The main manager for templates 00041 00042 The template systems allows for separation of code and 00043 layout by moving the layout part into template files. These 00044 template files are parsed and processed with template variables set 00045 by the PHP code. 00046 00047 The template system in itself is does not do much, it parses template files 00048 according to a rule set sets up a tree hierarchy and process the data 00049 using functions and operators. The standard template system comes with only 00050 a few functions and no operators, it is meant for these functions and operators 00051 to be specified by the users of the template system. But for simplicity a few 00052 help classes is available which can be easily enabled. 00053 00054 The classes are: 00055 - eZTemplateDelimitFunction - Inserts the left and right delimiter which are normally parsed. 00056 - eZTemplateSectionFunction - Allows for conditional blocks and loops. 00057 - eZTemplateIncludeFunction - Includes external templates 00058 - eZTemplateSequenceFunction - Creates sequences arrays 00059 - eZTemplateSwitchFunction - Conditional output of template 00060 00061 - eZTemplatePHPOperator - Allows for easy redirection of operator names to PHP functions. 00062 - eZTemplateLocaleOperator - Allows for locale conversions. 00063 - eZTemplateArrayOperator - Creates arrays 00064 - eZTemplateAttributeOperator - Displays contents of template variables, useful for debugging 00065 - eZTemplateImageOperator - Converts text to image 00066 - eZTemplateLogicOperator - Various logical operators for boolean handling 00067 - eZTemplateUnitOperator - Unit conversion and display 00068 00069 To enable these functions and operator use registerFunction and registerOperator. 00070 00071 In keeping with the spirit of being simple the template system does not know how 00072 to get the template files itself. Instead it relies on resource handlers, these 00073 handlers fetches the template files using different kind of transport mechanism. 00074 For simplicity a default resource class is available, eZTemplateFileResource fetches 00075 templates from the filesystem. 00076 00077 The parser process consists of three passes, each pass adds a new level of complexity. 00078 The first pass strips text from template blocks which starts with a left delimiter and 00079 ends with a right delimiter (default is { and } ), and places them in an array. 00080 The second pass iterates the text and block elements and removes newlines from 00081 text before function blocks and text after function blocks. 00082 The third pass builds the tree according the function rules. 00083 00084 Processing is done by iterating over the root of the tree, if a text block is found 00085 the text is appended to the result text. If a variable or contant is it's data is extracted 00086 and any operators found are run on it before fetching the result and appending it to 00087 the result text. If a function is found the function is called with the parameters 00088 and it's up to the function handle children if any. 00089 00090 Constants and template variables will usually be called variables since there's little 00091 difference. A template variable expression will start with a $ and consists of a 00092 namespace (optional) a name and attribues(optional). The variable expression 00093 \verbatim $root:var.attr1 \endverbatim exists in the "root" namespace, has the name "var" and uses the 00094 attribute "attr1". Some functions will create variables on demand, to avoid name conflicts 00095 namespaces were introduced, each function will place the new variables in a namespace 00096 specified in the template file. Attribues are used for fetching parts of the variable, 00097 for instance an element in an array or data in an object. Since the syntax is the 00098 same for arrays and objects the PHP code can use simple arrays when speed is required, 00099 the template code will not care. 00100 A different syntax is also available when you want to access an attribute using a variable. 00101 For instance \verbatim $root:var[$attr_var] \endverbatim, if the variable $attr_var contains "attr1" it would 00102 access the same attribute as in the first example. 00103 00104 The syntax for operators is a | and a name, optionally parameters can be specified with 00105 ( and ) delimited with ,. Valid operators are \verbatim |upcase, |l10n(date) \endverbatim. 00106 00107 Functions look a lot like HTML/XML tags. The function consists of a name and parameters 00108 which are assigned using the param=value syntax. Some parameters may be required while 00109 others may be optionally, the exact behaviour is specified by each function. 00110 Valid functions are \verbatim "section name=abc loop=4" \endverbatim 00111 00112 Example of usage: 00113 \code 00114 // Init template 00115 $tpl = eZTemplate::instance(); 00116 00117 $tpl->registerOperators( new eZTemplatePHPOperator( array( "upcase" => "strtoupper", 00118 "reverse" => "strrev" ) ) ); 00119 $tpl->registerOperators( new eZTemplateLocaleOperator() ); 00120 $tpl->registerFunction( "section", new eZTemplateSectionFunction( "section" ) ); 00121 $tpl->registerFunctions( new eZTemplateDelimitFunction() ); 00122 00123 $tpl->setVariable( "my_var", "{this value set by variable}", "test" ); 00124 $tpl->setVariable( "my_arr", array( "1st", "2nd", "third", "fjerde" ) ); 00125 $tpl->setVariable( "multidim", array( array( "a", "b" ), 00126 array( "c", "d" ), 00127 array( "e", "f" ), 00128 array( "g", "h" ) ) ); 00129 00130 class mytest 00131 { 00132 function mytest( $n, $s ) 00133 { 00134 $this->n = $n; 00135 $this->s = $s; 00136 } 00137 00138 function hasAttribute( $attr ) 00139 { 00140 return ( $attr == "name" || $attr == "size" ); 00141 } 00142 00143 function attribute( $attr ) 00144 { 00145 switch ( $attr ) 00146 { 00147 case "name"; 00148 return $this->n; 00149 case "size"; 00150 return $this->s; 00151 default: 00152 $retAttr = null; 00153 return $retAttr; 00154 } 00155 } 00156 00157 }; 00158 00159 $tpl->setVariable( "multidim_obj", array( new mytest( "jan", 200 ), 00160 new mytest( "feb", 200 ), 00161 new mytest( "john", 200 ), 00162 new mytest( "doe", 50 ) ) ); 00163 $tpl->setVariable( "curdate", time() ); 00164 00165 $tpl->display( "lib/eztemplate/example/test.tpl" ); 00166 00167 // test.tpl 00168 00169 {section name=outer loop=4} 00170 123 00171 {delimit}::{/delimit} 00172 {/section} 00173 00174 {literal test=1} This is some {blah arg1="" arg2="abc" /} {/literal} 00175 00176 <title>This is a test</title> 00177 <table border="1"> 00178 <tr><th>{$test:my_var} 00179 {"some text!!!"|upcase|reverse}</th></tr> 00180 {section name=abc loop=$my_arr} 00181 <tr><td>{$abc:item}</td></tr> 00182 {/section} 00183 </table> 00184 00185 <table border="1"> 00186 {section name=outer loop=$multidim} 00187 <tr> 00188 {section name=inner loop=$outer:item} 00189 <td>{$inner:item}</td> 00190 {/section} 00191 </tr> 00192 {/section} 00193 </table> 00194 00195 <table border="1"> 00196 {section name=outer loop=$multidim_obj} 00197 <tr> 00198 <td>{$outer:item.name}</td> 00199 <td>{$outer:item.size}</td> 00200 </tr> 00201 {/section} 00202 </table> 00203 00204 {section name=outer loop=$nonexistingvar} 00205 <b><i>Dette skal ikke vises</b></i> 00206 {section-else} 00207 <b><i>This is shown when the {ldelim}$loop{rdelim} variable is non-existant</b></i> 00208 {/section} 00209 00210 00211 Denne koster {1.4|l10n(currency)}<br> 00212 {-123456789|l10n(number)}<br> 00213 {$curdate|l10n(date)}<br> 00214 {$curdate|l10n(shortdate)}<br> 00215 {$curdate|l10n(time)}<br> 00216 {$curdate|l10n(shorttime)}<br> 00217 {include file="test2.tpl"/} 00218 00219 \endcode 00220 */ 00221 00222 require_once( "lib/ezutils/classes/ezdebug.php" ); 00223 00224 //include_once( "lib/eztemplate/classes/eztemplatefileresource.php" ); 00225 00226 //include_once( "lib/eztemplate/classes/eztemplateroot.php" ); 00227 //include_once( "lib/eztemplate/classes/eztemplatetextelement.php" ); 00228 //include_once( "lib/eztemplate/classes/eztemplatevariableelement.php" ); 00229 //include_once( "lib/eztemplate/classes/eztemplateoperatorelement.php" ); 00230 //include_once( "lib/eztemplate/classes/eztemplatefunctionelement.php" ); 00231 00232 class eZTemplate 00233 { 00234 const RESOURCE_FETCH = 1; 00235 const RESOURCE_QUERY = 2; 00236 00237 const ELEMENT_TEXT = 1; 00238 const ELEMENT_SINGLE_TAG = 2; 00239 const ELEMENT_NORMAL_TAG = 3; 00240 const ELEMENT_END_TAG = 4; 00241 const ELEMENT_VARIABLE = 5; 00242 const ELEMENT_COMMENT = 6; 00243 00244 const NODE_ROOT = 1; 00245 const NODE_TEXT = 2; 00246 const NODE_VARIABLE = 3; 00247 const NODE_FUNCTION = 4; 00248 const NODE_OPERATOR = 5; 00249 00250 00251 const NODE_INTERNAL = 100; 00252 const NODE_INTERNAL_CODE_PIECE = 101; 00253 00254 const NODE_INTERNAL_VARIABLE_SET = 105; 00255 const NODE_INTERNAL_VARIABLE_UNSET = 102; 00256 00257 const NODE_INTERNAL_NAMESPACE_CHANGE = 103; 00258 const NODE_INTERNAL_NAMESPACE_RESTORE = 104; 00259 00260 const NODE_INTERNAL_WARNING = 120; 00261 const NODE_INTERNAL_ERROR = 121; 00262 00263 const NODE_INTERNAL_RESOURCE_ACQUISITION = 140; 00264 const NODE_OPTIMIZED_RESOURCE_ACQUISITION = 141; 00265 00266 const NODE_INTERNAL_OUTPUT_ASSIGN = 150; 00267 const NODE_INTERNAL_OUTPUT_READ = 151; 00268 const NODE_INTERNAL_OUTPUT_INCREASE = 152; 00269 const NODE_INTERNAL_OUTPUT_DECREASE = 153; 00270 00271 const NODE_INTERNAL_OUTPUT_SPACING_INCREASE = 160; 00272 const NODE_INTERNAL_SPACING_DECREASE = 161; 00273 00274 const NODE_OPTIMIZED_INIT = 201; 00275 00276 00277 const NODE_USER_CUSTOM = 1000; 00278 00279 00280 const TYPE_VOID = 0; 00281 const TYPE_STRING = 1; 00282 const TYPE_NUMERIC = 2; 00283 const TYPE_IDENTIFIER = 3; 00284 const TYPE_VARIABLE = 4; 00285 const TYPE_ATTRIBUTE = 5; 00286 const TYPE_OPERATOR = 6; 00287 const TYPE_BOOLEAN = 7; 00288 const TYPE_ARRAY = 8; 00289 const TYPE_DYNAMIC_ARRAY = 9; 00290 00291 const TYPE_INTERNAL = 100; 00292 const TYPE_INTERNAL_CODE_PIECE = 101; 00293 const TYPE_PHP_VARIABLE = 102; 00294 00295 const TYPE_OPTIMIZED_NODE = 201; 00296 const TYPE_OPTIMIZED_ARRAY_LOOKUP = 202; 00297 const TYPE_OPTIMIZED_CONTENT_CALL = 203; 00298 const TYPE_OPTIMIZED_ATTRIBUTE_LOOKUP = 204; 00299 00300 const TYPE_INTERNAL_STOP = 999; 00301 00302 00303 const TYPE_STRING_BIT = 1; 00304 const TYPE_NUMERIC_BIT = 2; 00305 const TYPE_IDENTIFIER_BIT = 4; 00306 const TYPE_VARIABLE_BIT = 8; 00307 const TYPE_ATTRIBUTE_BIT = 16; 00308 const TYPE_OPERATOR_BIT = 32; 00309 00310 const TYPE_NONE = 0; 00311 00312 const TYPE_ALL = 63; 00313 00314 const TYPE_BASIC = 47; 00315 00316 const TYPE_MODIFIER_MASK = 48; 00317 00318 const NAMESPACE_SCOPE_GLOBAL = 1; 00319 const NAMESPACE_SCOPE_LOCAL = 2; 00320 const NAMESPACE_SCOPE_RELATIVE = 3; 00321 00322 const DEBUG_INTERNALS = false; 00323 00324 const FILE_ERRORS = 1; 00325 00326 /*! 00327 Intializes the template with left and right delimiters being { and }, 00328 and a file resource. The literal tag "literal" is also registered. 00329 */ 00330 function eZTemplate() 00331 { 00332 $this->Tree = array( eZTemplate::NODE_ROOT, false ); 00333 $this->LDelim = "{"; 00334 $this->RDelim = "}"; 00335 00336 $this->IncludeText = array(); 00337 $this->IncludeOutput = array(); 00338 00339 $this->registerLiteral( "literal" ); 00340 00341 $res = new eZTemplateFileResource(); 00342 $this->DefaultResource = $res; 00343 $this->registerResource( $res ); 00344 00345 $this->Resources = array(); 00346 $this->Text = null; 00347 00348 $this->IsCachingAllowed = true; 00349 00350 $this->resetErrorLog(); 00351 00352 $this->AutoloadPathList = array( 'lib/eztemplate/classes/' ); 00353 $this->Variables = array(); 00354 $this->LocalVariablesNamesStack = array(); 00355 $this->CurrentLocalVariablesNames = null; 00356 $this->Functions = array(); 00357 $this->FunctionAttributes = array(); 00358 00359 $this->TestCompile = false; 00360 00361 $ini = eZINI::instance( 'template.ini' ); 00362 if ( $ini->hasVariable( 'ControlSettings', 'MaxLevel' ) ) 00363 $this->MaxLevel = $ini->variable( 'ControlSettings', 'MaxLevel' ); 00364 require_once('kernel/common/i18n.php'); 00365 $this->MaxLevelWarning = ezi18n( 'lib/template', 00366 'The maximum nesting level of %max has been reached. The execution is stopped to avoid infinite recursion.', 00367 '', 00368 array( '%max' => $this->MaxLevel ) ); 00369 eZDebug::createAccumulatorGroup( 'template_total', 'Template Total' ); 00370 00371 $this->TemplatesUsageStatistics = array(); 00372 // Array of templates which are used in a single fetch() 00373 $this->TemplateFetchList = array(); 00374 00375 $this->ForeachCounter = 0; 00376 $this->ForCounter = 0; 00377 $this->WhileCounter = 0; 00378 $this->DoCounter = 0; 00379 $this->ElseifCounter = 0; 00380 } 00381 00382 /*! 00383 Returns the left delimiter being used. 00384 */ 00385 function leftDelimiter() 00386 { 00387 return $this->LDelim; 00388 } 00389 00390 /*! 00391 Returns the right delimiter being used. 00392 */ 00393 function rightDelimiter() 00394 { 00395 return $this->RDelim; 00396 } 00397 00398 /*! 00399 Sets the left delimiter. 00400 */ 00401 function setLeftDelimiter( $delim ) 00402 { 00403 $this->LDelim = $delim; 00404 } 00405 00406 /*! 00407 Sets the right delimiter. 00408 */ 00409 function setRightDelimiter( $delim ) 00410 { 00411 $this->RDelim = $delim; 00412 } 00413 00414 /*! 00415 Fetches the result of the template file and displays it. 00416 If $template is supplied it will load this template file first. 00417 */ 00418 function display( $template = false, $extraParameters = false ) 00419 { 00420 $output = $this->fetch( $template, $extraParameters ); 00421 if ( $this->ShowDetails ) 00422 { 00423 echo '<h1>Result:</h1>' . "\n"; 00424 echo '<hr/>' . "\n"; 00425 } 00426 echo "$output"; 00427 if ( $this->ShowDetails ) 00428 { 00429 echo '<hr/>' . "\n"; 00430 } 00431 if ( $this->ShowDetails ) 00432 { 00433 echo "<h1>Template data:</h1>"; 00434 echo "<p class=\"filename\">" . $template . "</p>"; 00435 echo "<pre class=\"example\">" . htmlspecialchars( $this->Text ) . "</pre>"; 00436 reset( $this->IncludeText ); 00437 while ( ( $key = key( $this->IncludeText ) ) !== null ) 00438 { 00439 $item = $this->IncludeText[$key]; 00440 echo "<p class=\"filename\">" . $key . "</p>"; 00441 echo "<pre class=\"example\">" . htmlspecialchars( $item ) . "</pre>"; 00442 next( $this->IncludeText ); 00443 } 00444 echo "<h1>Result text:</h1>"; 00445 echo "<p class=\"filename\">" . $template . "</p>"; 00446 echo "<pre class=\"example\">" . htmlspecialchars( $output ) . "</pre>"; 00447 reset( $this->IncludeOutput ); 00448 while ( ( $key = key( $this->IncludeOutput ) ) !== null ) 00449 { 00450 $item = $this->IncludeOutput[$key]; 00451 echo "<p class=\"filename\">" . $key . "</p>"; 00452 echo "<pre class=\"example\">" . htmlspecialchars( $item ) . "</pre>"; 00453 next( $this->IncludeOutput ); 00454 } 00455 } 00456 } 00457 00458 /*! 00459 * Initialize list of local variables for the current template. 00460 * The list contains only names of variables. 00461 */ 00462 function createLocalVariablesList() 00463 { 00464 $this->LocalVariablesNamesStack[] = array(); 00465 $this->CurrentLocalVariablesNames =& $this->LocalVariablesNamesStack[ count( $this->LocalVariablesNamesStack ) - 1]; 00466 } 00467 00468 /*! 00469 * Check if the given local variable exists. 00470 */ 00471 function hasLocalVariable( $varName, $rootNamespace ) 00472 { 00473 return ( array_key_exists( $rootNamespace, $this->CurrentLocalVariablesNames ) && 00474 array_key_exists( $varName, $this->CurrentLocalVariablesNames[$rootNamespace] ) ); 00475 } 00476 00477 /*! 00478 * Create a local variable. 00479 */ 00480 function setLocalVariable( $varName, $varValue, $rootNamespace ) 00481 { 00482 $this->CurrentLocalVariablesNames[$rootNamespace][$varName] = 1; 00483 $this->setVariable( $varName, $varValue, $rootNamespace ); 00484 } 00485 00486 /*! 00487 * Destroy a local variable. 00488 */ 00489 function unsetLocalVariable( $varName, $rootNamespace ) 00490 { 00491 if ( !$this->hasLocalVariable( $varName, $rootNamespace ) ) 00492 return; 00493 00494 $this->unsetVariable( $varName, $rootNamespace ); 00495 unset( $this->CurrentLocalVariablesNames[$rootNamespace][$varName] ); 00496 } 00497 00498 /*! 00499 * Destroy all local variables defined in the current template. 00500 */ 00501 function unsetLocalVariables() 00502 { 00503 foreach ( $this->CurrentLocalVariablesNames as $ns => $vars ) 00504 { 00505 foreach ( $vars as $var => $val ) 00506 $this->unsetLocalVariable( $var, $ns ); 00507 } 00508 } 00509 00510 /*! 00511 * Destroy list of local variables defined in the current (innermost) template. 00512 */ 00513 function destroyLocalVariablesList() 00514 { 00515 array_pop( $this->LocalVariablesNamesStack ); 00516 00517 if ( $this->LocalVariablesNamesStack ) 00518 $this->CurrentLocalVariablesNames =& $this->LocalVariablesNamesStack[ count( $this->LocalVariablesNamesStack ) - 1]; 00519 else 00520 unset( $this->CurrentLocalVariablesNames ); 00521 } 00522 00523 /*! 00524 Tries to fetch the result of the template file and returns it. 00525 If $template is supplied it will load this template file first. 00526 */ 00527 function fetch( $template = false, $extraParameters = false, $returnResourceData = false ) 00528 { 00529 $this->resetErrorLog(); 00530 // Reset fetch list when a new fetch is started 00531 $this->TemplateFetchList = array(); 00532 00533 eZDebug::accumulatorStart( 'template_total' ); 00534 eZDebug::accumulatorStart( 'template_load', 'template_total', 'Template load' ); 00535 $root = null; 00536 if ( is_string( $template ) ) 00537 { 00538 $resourceData = $this->loadURIRoot( $template, true, $extraParameters ); 00539 if ( $resourceData and 00540 $resourceData['root-node'] !== null ) 00541 $root =& $resourceData['root-node']; 00542 } 00543 eZDebug::accumulatorStop( 'template_load' ); 00544 if ( $resourceData['locales'] && count( $resourceData['locales'] ) ) 00545 { 00546 $savedLocale = setlocale( LC_CTYPE, null ); 00547 setlocale( LC_CTYPE, $resourceData['locales'] ); 00548 } 00549 00550 $text = ""; 00551 00552 if ( $root !== null or 00553 $resourceData['compiled-template'] ) 00554 { 00555 if ( $this->ShowDetails ) 00556 eZDebug::addTimingPoint( "Process" ); 00557 eZDebug::accumulatorStart( 'template_processing', 'template_total', 'Template processing' ); 00558 00559 $templateCompilationUsed = false; 00560 if ( $resourceData['compiled-template'] ) 00561 { 00562 $textElements = array(); 00563 if ( $this->executeCompiledTemplate( $resourceData, $textElements, "", "", $extraParameters ) ) 00564 { 00565 $text = implode( '', $textElements ); 00566 $templateCompilationUsed = true; 00567 } 00568 } 00569 if ( !$templateCompilationUsed ) 00570 { 00571 if ( eZTemplate::isDebugEnabled() ) 00572 { 00573 $fname = $resourceData['template-filename']; 00574 eZDebug::writeDebug( "FETCH START URI: $template, $fname" ); 00575 } 00576 $this->process( $root, $text, "", "" ); 00577 if ( eZTemplate::isDebugEnabled() ) 00578 eZDebug::writeDebug( "FETCH END URI: $template, $fname" ); 00579 } 00580 00581 eZDebug::accumulatorStop( 'template_processing' ); 00582 if ( $this->ShowDetails ) 00583 eZDebug::addTimingPoint( "Process done" ); 00584 } 00585 00586 eZDebug::accumulatorStop( 'template_total' ); 00587 00588 if ( $resourceData['locales'] && count( $resourceData['locales'] ) ) 00589 { 00590 setlocale( LC_CTYPE, $savedLocale ); 00591 } 00592 00593 if ( $returnResourceData ) 00594 { 00595 $resourceData['result_text'] = $text; 00596 return $resourceData; 00597 } 00598 return $text; 00599 } 00600 00601 function process( $root, &$text, $rootNamespace, $currentNamespace ) 00602 { 00603 $this->createLocalVariablesList(); 00604 00605 $textElements = array(); 00606 $this->processNode( $root, $textElements, $rootNamespace, $currentNamespace ); 00607 if ( is_array( $textElements ) ) 00608 $text = implode( '', $textElements ); 00609 else 00610 $text = $textElements; 00611 00612 $this->unsetLocalVariables(); 00613 $this->destroyLocalVariablesList(); 00614 } 00615 00616 function processNode( $node, &$textElements, $rootNamespace, $currentNamespace ) 00617 { 00618 $rslt = null; 00619 $nodeType = $node[0]; 00620 if ( $nodeType == eZTemplate::NODE_ROOT ) 00621 { 00622 $children = $node[1]; 00623 if ( $children ) 00624 { 00625 foreach ( $children as $child ) 00626 { 00627 $this->processNode( $child, $textElements, $rootNamespace, $currentNamespace ); 00628 if ( !is_array( $textElements ) ) 00629 eZDebug::writeError( "Textelements is no longer array: '$textElements'", 00630 'eztemplate::processNode::root' ); 00631 } 00632 } 00633 } 00634 else if ( $nodeType == eZTemplate::NODE_TEXT ) 00635 { 00636 $textElements[] = $node[2]; 00637 } 00638 else if ( $nodeType == eZTemplate::NODE_VARIABLE ) 00639 { 00640 $variableData = $node[2]; 00641 $variablePlacement = $node[3]; 00642 $rslt = $this->processVariable( $textElements, $variableData, $variablePlacement, $rootNamespace, $currentNamespace ); 00643 if ( !is_array( $textElements ) ) 00644 eZDebug::writeError( "Textelements is no longer array: '$textElements'", 00645 'eztemplate::processNode::variable' ); 00646 } 00647 else if ( $nodeType == eZTemplate::NODE_FUNCTION ) 00648 { 00649 $functionChildren = $node[1]; 00650 $functionName = $node[2]; 00651 $functionParameters = $node[3]; 00652 $functionPlacement = $node[4]; 00653 $rslt = $this->processFunction( $functionName, $textElements, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace ); 00654 if ( !is_array( $textElements ) ) 00655 eZDebug::writeError( "Textelements is no longer array: '$textElements'", 00656 "eztemplate::processNode::function( '$functionName' )" ); 00657 } 00658 00659 return $rslt; 00660 } 00661 00662 function processVariable( &$textElements, $variableData, $variablePlacement, $rootNamespace, $currentNamespace ) 00663 { 00664 $value = $this->elementValue( $variableData, $rootNamespace, $currentNamespace, $variablePlacement ); 00665 $this->appendElementText( $textElements, $value, $rootNamespace, $currentNamespace ); 00666 } 00667 00668 function processFunction( $functionName, &$textElements, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace ) 00669 { 00670 // Note: This code piece is replicated in the eZTemplateCompiler, 00671 // if this code is changed the replicated code must be updated as well. 00672 $func = $this->Functions[$functionName]; 00673 if ( is_array( $func ) ) 00674 { 00675 $this->loadAndRegisterFunctions( $this->Functions[$functionName] ); 00676 $func = $this->Functions[$functionName]; 00677 } 00678 if ( isset( $func ) and 00679 is_object( $func ) ) 00680 { 00681 if ( eZTemplate::isMethodDebugEnabled() ) 00682 eZDebug::writeDebug( "START FUNCTION: $functionName" ); 00683 $value = $func->process( $this, $textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace ); 00684 if ( eZTemplate::isMethodDebugEnabled() ) 00685 eZDebug::writeDebug( "END FUNCTION: $functionName" ); 00686 return $value; 00687 } 00688 else 00689 { 00690 $this->warning( "", "Function \"$functionName\" is not registered" ); 00691 } 00692 } 00693 00694 function fetchFunctionObject( $functionName ) 00695 { 00696 $func = $this->Functions[$functionName]; 00697 if ( is_array( $func ) ) 00698 { 00699 $this->loadAndRegisterFunctions( $this->Functions[$functionName] ); 00700 $func = $this->Functions[$functionName]; 00701 } 00702 return $func; 00703 } 00704 00705 /*! 00706 Loads the template using the URI $uri and parses it. 00707 \return The root node of the tree if \a $returnResourceData is false, 00708 if \c true the entire resource data structure. 00709 */ 00710 function load( $uri, $extraParameters = false, $returnResourceData = false ) 00711 { 00712 $resourceData = $this->loadURIRoot( $uri, true, $extraParameters ); 00713 if ( !$resourceData or 00714 $resourceData['root-node'] === null ) 00715 { 00716 $retValue = null; 00717 return $retValue; 00718 } 00719 else 00720 return $resourceData['root-node']; 00721 } 00722 00723 function parse( $sourceText, &$rootElement, $rootNamespace, &$resourceData ) 00724 { 00725 //include_once( 'lib/eztemplate/classes/eztemplatemultipassparser.php' ); 00726 $parser = eZTemplateMultiPassParser::instance(); 00727 $parser->parse( $this, $sourceText, $rootElement, $rootNamespace, $resourceData ); 00728 } 00729 00730 function loadURIData( $resourceObject, $uri, $resourceName, $template, &$extraParameters, $displayErrors = true ) 00731 { 00732 $resourceData = $this->resourceData( $resourceObject, $uri, $resourceName, $template ); 00733 00734 $resourceData['text'] = null; 00735 $resourceData['root-node'] = null; 00736 $resourceData['compiled-template'] = false; 00737 $resourceData['time-stamp'] = null; 00738 $resourceData['key-data'] = null; 00739 $resourceData['locales'] = null; 00740 00741 if ( !$resourceObject->handleResource( $this, $resourceData, eZTemplate::RESOURCE_FETCH, $extraParameters ) ) 00742 { 00743 $resourceData = null; 00744 if ( $displayErrors ) 00745 $this->warning( "", "No template could be loaded for \"$template\" using resource \"$resourceName\"" ); 00746 } 00747 return $resourceData; 00748 } 00749 00750 /*! 00751 \static 00752 Creates a resource data structure of the parameters and returns it. 00753 This structure is passed to various parts of the template system. 00754 00755 \note If you only have the URI you should call resourceFor() first to 00756 figure out the resource handler. 00757 */ 00758 function resourceData( $resourceObject, $uri, $resourceName, $templateName ) 00759 { 00760 $resourceData = array(); 00761 $resourceData['uri'] = $uri; 00762 $resourceData['resource'] = $resourceName; 00763 $resourceData['template-name'] = $templateName; 00764 $resourceData['template-filename'] = $templateName; 00765 $resourceData['handler'] = $resourceObject; 00766 $resourceData['test-compile'] = $this->TestCompile; 00767 return $resourceData; 00768 } 00769 00770 /*! 00771 Loads the template using the URI $uri and returns a structure with the text and timestamp, 00772 false otherwise. 00773 The structure keys are: 00774 - "text", the text. 00775 - "time-stamp", the timestamp. 00776 */ 00777 function loadURIRoot( $uri, $displayErrors = true, &$extraParameters ) 00778 { 00779 $res = ""; 00780 $template = ""; 00781 $resobj = $this->resourceFor( $uri, $res, $template ); 00782 00783 if ( !is_object( $resobj ) ) 00784 { 00785 if ( $displayErrors ) 00786 $this->warning( "", "No resource handler for \"$res\" and no default resource handler, aborting." ); 00787 return null; 00788 } 00789 00790 $canCache = true; 00791 if ( !$resobj->servesStaticData() ) 00792 $canCache = false; 00793 if ( !$this->isCachingAllowed() ) 00794 $canCache = false; 00795 00796 $resourceData = $this->loadURIData( $resobj, $uri, $res, $template, $extraParameters, $displayErrors ); 00797 00798 if ( $resourceData ) 00799 { 00800 $root = null; 00801 eZTemplate::appendTemplateToStatisticsIfNeeded( $resourceData['template-name'], $resourceData['template-filename'] ); 00802 $this->appendTemplateFetch( $resourceData['template-filename'] ); 00803 00804 if ( !$resourceData['compiled-template'] and 00805 $resourceData['root-node'] === null ) 00806 { 00807 $resourceData['root-node'] = array( eZTemplate::NODE_ROOT, false ); 00808 $templateText = $resourceData["text"]; 00809 $keyData = $resourceData['key-data']; 00810 $this->setIncludeText( $uri, $templateText ); 00811 $rootNamespace = ''; 00812 $this->parse( $templateText, $resourceData['root-node'], $rootNamespace, $resourceData ); 00813 00814 if ( eZTemplate::isDebugEnabled() ) 00815 { 00816 $this->appendDebugNodes( $resourceData['root-node'], $resourceData ); 00817 } 00818 00819 if ( $canCache ) 00820 $resobj->setCachedTemplateTree( $keyData, $uri, $res, $template, $extraParameters, $resourceData['root-node'] ); 00821 } 00822 if ( !$resourceData['compiled-template'] and 00823 $canCache and 00824 $this->canCompileTemplate( $resourceData, $extraParameters ) ) 00825 { 00826 $generateStatus = $this->compileTemplate( $resourceData, $extraParameters ); 00827 if ( $generateStatus ) 00828 $resourceData['compiled-template'] = true; 00829 } 00830 } 00831 00832 return $resourceData; 00833 } 00834 00835 function processURI( $uri, $displayErrors = true, &$extraParameters, 00836 &$textElements, $rootNamespace, $currentNamespace ) 00837 { 00838 $this->Level++; 00839 if ( $this->Level > $this->MaxLevel ) 00840 { 00841 eZDebug::writeError( $this->MaxLevelWarning, "eZTemplate:processURI Level: $this->Level @ $uri" ); 00842 $textElements[] = $this->MaxLevelWarning; 00843 $this->Level--; 00844 return; 00845 } 00846 $resourceData = $this->loadURIRoot( $uri, $displayErrors, $extraParameters ); 00847 if ( !$resourceData or 00848 ( !$resourceData['compiled-template'] and 00849 $resourceData['root-node'] === null ) ) 00850 { 00851 $this->Level--; 00852 return; 00853 } 00854 00855 $templateCompilationUsed = false; 00856 00857 if ( $resourceData['locales'] && count( $resourceData['locales'] ) ) 00858 { 00859 $savedLocale = setlocale( LC_CTYPE, null ); 00860 setlocale( LC_CTYPE, $resourceData['locales'] ); 00861 } 00862 00863 if ( $resourceData['compiled-template'] ) 00864 { 00865 if ( $this->executeCompiledTemplate( $resourceData, $textElements, $rootNamespace, $currentNamespace, $extraParameters ) ) 00866 $templateCompilationUsed = true; 00867 } 00868 if ( !$templateCompilationUsed ) 00869 { 00870 $text = null; 00871 if ( eZTemplate::isDebugEnabled() ) 00872 { 00873 $fname = $resourceData['template-filename']; 00874 eZDebug::writeDebug( "START URI: $uri, $fname" ); 00875 } 00876 $this->process( $resourceData['root-node'], $text, $rootNamespace, $currentNamespace ); 00877 if ( eZTemplate::isDebugEnabled() ) 00878 eZDebug::writeDebug( "END URI: $uri, $fname" ); 00879 $this->setIncludeOutput( $uri, $text ); 00880 $textElements[] = $text; 00881 } 00882 00883 if ( $resourceData['locales'] && count( $resourceData['locales'] ) ) 00884 { 00885 setlocale( LC_CTYPE, $savedLocale ); 00886 } 00887 $this->Level--; 00888 00889 } 00890 00891 function canCompileTemplate( $resourceData, &$extraParameters ) 00892 { 00893 $resourceObject = $resourceData['handler']; 00894 if ( !$resourceObject ) 00895 return false; 00896 $canGenerate = $resourceObject->canCompileTemplate( $this, $resourceData, $extraParameters ); 00897 return $canGenerate; 00898 } 00899 00900 /*! 00901 Validates the template file \a $file and returns \c true if the file has correct syntax. 00902 \param $returnResourceData If \c true then the returned value will be the resourcedata structure 00903 \sa compileTemplateFile(), fetch() 00904 */ 00905 function validateTemplateFile( $file, $returnResourceData = false ) 00906 { 00907 $this->resetErrorLog(); 00908 00909 if ( !file_exists( $file ) ) 00910 return false; 00911 $resourceHandler = $this->resourceFor( $file, $resourceName, $templateName ); 00912 if ( !$resourceHandler ) 00913 return false; 00914 $resourceData = $this->resourceData( $resourceHandler, $file, $resourceName, $templateName ); 00915 $resourceData['key-data'] = "file:" . $file; 00916 $key = md5( $resourceData['key-data'] ); 00917 $extraParameters = array(); 00918 00919 // Disable caching/compiling while fetchin the resource 00920 // It will be restored afterwards 00921 $isCachingAllowed = $this->IsCachingAllowed; 00922 $this->IsCachingAllowed = false; 00923 00924 $resourceHandler->handleResource( $this, $resourceData, eZTemplate::RESOURCE_FETCH, $extraParameters ); 00925 00926 // Restore previous caching flag 00927 $this->IsCachingAllowed = $isCachingAllowed; 00928 00929 $root =& $resourceData['root-node']; 00930 $root = array( eZTemplate::NODE_ROOT, false ); 00931 $templateText = $resourceData["text"]; 00932 $rootNamespace = ''; 00933 $this->parse( $templateText, $root, $rootNamespace, $resourceData ); 00934 if ( eZTemplate::isDebugEnabled() ) 00935 { 00936 $this->appendDebugNodes( $root, $resourceData ); 00937 } 00938 00939 $result = !$this->hasErrors() and !$this->hasWarnings(); 00940 if ( $returnResourceData ) 00941 { 00942 $resourceData['result'] = $result; 00943 return $resourceData; 00944 } 00945 return $result; 00946 } 00947 00948 /*! 00949 Compiles the template file \a $file and returns \c true if the compilation was OK. 00950 \param $returnResourceData If \c true then the returned value will be the resourcedata structure 00951 \sa validateTemplateFile(), fetch() 00952 */ 00953 function compileTemplateFile( $file, $returnResourceData = false ) 00954 { 00955 $this->resetErrorLog(); 00956 00957 if ( !file_exists( $file ) ) 00958 return false; 00959 $resourceHandler = $this->resourceFor( $file, $resourceName, $templateName ); 00960 if ( !$resourceHandler ) 00961 return false; 00962 $resourceData = $this->resourceData( $resourceHandler, $file, $resourceName, $templateName ); 00963 $resourceData['key-data'] = "file:" . $file; 00964 $key = md5( $resourceData['key-data'] ); 00965 $extraParameters = array(); 00966 $resourceHandler->handleResource( $this, $resourceData, eZTemplate::RESOURCE_FETCH, $extraParameters ); 00967 00968 $isCompiled = false; 00969 if ( isset( $resourceData['compiled-template'] ) ) 00970 $isCompiled = $resourceData['compiled-template']; 00971 00972 if ( !$isCompiled ) 00973 { 00974 $root =& $resourceData['root-node']; 00975 $root = array( eZTemplate::NODE_ROOT, false ); 00976 $templateText = $resourceData["text"]; 00977 $rootNamespace = ''; 00978 $this->parse( $templateText, $root, $rootNamespace, $resourceData ); 00979 if ( eZTemplate::isDebugEnabled() ) 00980 { 00981 $this->appendDebugNodes( $root, $resourceData ); 00982 } 00983 00984 $result = eZTemplateCompiler::compileTemplate( $this, $key, $resourceData ); 00985 } 00986 else 00987 { 00988 $result = true; 00989 } 00990 00991 if ( $returnResourceData ) 00992 { 00993 $resourceData['result'] = $result; 00994 return $resourceData; 00995 } 00996 return $result; 00997 } 00998 00999 function compileTemplate( &$resourceData, &$extraParameters ) 01000 { 01001 $resourceObject = $resourceData['handler']; 01002 if ( !$resourceObject ) 01003 return false; 01004 $keyData = $resourceData['key-data']; 01005 $uri = $resourceData['uri']; 01006 $resourceName = $resourceData['resource']; 01007 $templatePath = $resourceData['template-name']; 01008 return $resourceObject->compileTemplate( $this, $keyData, $uri, $resourceName, $templatePath, $extraParameters, $resourceData ); 01009 } 01010 01011 function executeCompiledTemplate( &$resourceData, &$textElements, $rootNamespace, $currentNamespace, &$extraParameters ) 01012 { 01013 $resourceObject = $resourceData['handler']; 01014 if ( !$resourceObject ) 01015 return false; 01016 $keyData = $resourceData['key-data']; 01017 $uri = $resourceData['uri']; 01018 $resourceName = $resourceData['resource']; 01019 $templatePath = $resourceData['template-name']; 01020 $timestamp = $resourceData['time-stamp']; 01021 return $resourceObject->executeCompiledTemplate( $this, $textElements, 01022 $keyData, $uri, $resourceData, $templatePath, 01023 $extraParameters, $timestamp, 01024 $rootNamespace, $currentNamespace ); 01025 } 01026 01027 /*! 01028 Returns the resource object for URI $uri. If a resource type is specified 01029 in the URI it is extracted and set in $res. The template name is set in $template 01030 without any resource specifier. To specify a resource the name and a ":" is 01031 prepended to the URI, for instance file:my.tpl. 01032 If no resource type is found the URI the default resource handler is used. 01033 */ 01034 function resourceFor( $uri, &$res, &$template ) 01035 { 01036 $args = explode( ":", $uri ); 01037 if ( count( $args ) > 1 ) 01038 { 01039 $res = $args[0]; 01040 $template = $args[1]; 01041 } 01042 else 01043 $template = $uri; 01044 if ( eZTemplate::isDebugEnabled() ) 01045 { 01046 eZDebug::writeNotice( "eZTemplate: Loading template \"$template\" with resource \"$res\"" ); 01047 } 01048 if ( isset( $this->Resources[$res] ) and is_object( $this->Resources[$res] ) ) 01049 { 01050 return $this->Resources[$res]; 01051 } 01052 return $this->DefaultResource; 01053 } 01054 01055 /*! 01056 \return The resource handler object for resource name \a $resourceName. 01057 \sa resourceFor 01058 */ 01059 function resourceHandler( $resourceName ) 01060 { 01061 if ( isset( $this->Resources[$resourceName] ) && 01062 is_object( $this->Resources[$resourceName] ) ) 01063 { 01064 return $this->Resources[$resourceName]; 01065 } 01066 return $this->DefaultResource; 01067 } 01068 01069 function hasChildren( &$function, $functionName ) 01070 { 01071 $hasChildren = $function->hasChildren(); 01072 if ( is_array( $hasChildren ) ) 01073 return $hasChildren[$functionName]; 01074 else 01075 return $hasChildren; 01076 } 01077 01078 /*! 01079 Returns the empty variable type. 01080 */ 01081 function emptyVariable() 01082 { 01083 return array( "type" => "null" ); 01084 } 01085 01086 /*! 01087 \static 01088 */ 01089 function mergeNamespace( $rootNamespace, $additionalNamespace ) 01090 { 01091 $namespace = $rootNamespace; 01092 if ( $namespace == '' ) 01093 $namespace = $additionalNamespace; 01094 else if ( $additionalNamespace != '' ) 01095 $namespace = "$namespace:$additionalNamespace"; 01096 return $namespace; 01097 } 01098 01099 /*! 01100 Returns the actual value of a template type or null if an unknown type. 01101 */ 01102 function elementValue( &$dataElements, $rootNamespace, $currentNamespace, $placement = false, 01103 $checkExistance = false, $checkForProxy = false ) 01104 { 01105 /* 01106 * We use a small dirty hack in this function... 01107 * To help the caller to determine if the value was a proxy object, 01108 * we store boolean true to $dataElements['proxy-object-found'] in this case. 01109 * (it's up to caller to remove this garbage from $dataElements...) 01110 * This behaviour is enabled by $checkForProxy parameter. 01111 */ 01112 01113 $value = null; 01114 if ( !is_array( $dataElements ) ) 01115 { 01116 $this->error( "elementValue", 01117 "Missing array data structure, got " . gettype( $dataElements ) ); 01118 return null; 01119 } 01120 foreach ( $dataElements as $dataElement ) 01121 { 01122 if ( is_null( $dataElement ) ) 01123 { 01124 return null; 01125 } 01126 $dataType = $dataElement[0]; 01127 switch ( $dataType ) 01128 { 01129 case eZTemplate::TYPE_VOID: 01130 { 01131 if ( !$checkExistance ) 01132 $this->warning( 'elementValue', 01133 'Found void datatype, should not be used' ); 01134 else 01135 { 01136 return null; 01137 } 01138 } break; 01139 case eZTemplate::TYPE_STRING: 01140 case eZTemplate::TYPE_NUMERIC: 01141 case eZTemplate::TYPE_IDENTIFIER: 01142 case eZTemplate::TYPE_BOOLEAN: 01143 case eZTemplate::TYPE_ARRAY: 01144 { 01145 $value = $dataElement[1]; 01146 } break; 01147 case eZTemplate::TYPE_VARIABLE: 01148 { 01149 $variableData = $dataElement[1]; 01150 $variableNamespace = $variableData[0]; 01151 $variableNamespaceScope = $variableData[1]; 01152 $variableName = $variableData[2]; 01153 if ( $variableNamespaceScope == eZTemplate::NAMESPACE_SCOPE_GLOBAL ) 01154 $namespace = $variableNamespace; 01155 else if ( $variableNamespaceScope == eZTemplate::NAMESPACE_SCOPE_LOCAL ) 01156 $namespace = $this->mergeNamespace( $rootNamespace, $variableNamespace ); 01157 else if ( $variableNamespaceScope == eZTemplate::NAMESPACE_SCOPE_RELATIVE ) 01158 $namespace = $this->mergeNamespace( $currentNamespace, $variableNamespace ); 01159 else 01160 $namespace = false; 01161 if ( $this->hasVariable( $variableName, $namespace ) ) 01162 { 01163 $value = $this->variable( $variableName, $namespace ); 01164 } 01165 else 01166 { 01167 if ( !$checkExistance ) 01168 $this->error( '', "Unknown template variable '$variableName' in namespace '$namespace'", $placement ); 01169 { 01170 return null; 01171 } 01172 } 01173 } break; 01174 case eZTemplate::TYPE_ATTRIBUTE: 01175 { 01176 $attributeData = $dataElement[1]; 01177 $attributeValue = $this->elementValue( $attributeData, $rootNamespace, $currentNamespace, false, $checkExistance ); 01178 01179 if ( !is_null( $attributeValue ) ) 01180 { 01181 if ( !is_numeric( $attributeValue ) and 01182 !is_string( $attributeValue ) and 01183 !is_bool( $attributeValue ) ) 01184 { 01185 if ( !$checkExistance ) 01186 $this->error( "", 01187 "Cannot use type " . gettype( $attributeValue ) . " for attribute lookup", $placement ); 01188 { 01189 return null; 01190 } 01191 } 01192 if ( is_array( $value ) ) 01193 { 01194 if ( array_key_exists( $attributeValue, $value ) ) 01195 { 01196 $value = $value[$attributeValue]; 01197 } 01198 else 01199 { 01200 if ( !$checkExistance ) 01201 { 01202 $arrayAttributeList = array_keys( $value ); 01203 $arrayCount = count( $arrayAttributeList ); 01204 $errorMessage = "No such attribute for array($arrayCount): $attributeValue"; 01205 $chooseText = "Choose one of following: "; 01206 $errorMessage .= "\n$chooseText"; 01207 $errorMessage .= $this->expandAttributes( $arrayAttributeList, $chooseText, 25 ); 01208 $this->error( "", 01209 $errorMessage, $placement ); 01210 } 01211 return null; 01212 } 01213 } 01214 else if ( is_object( $value ) ) 01215 { 01216 if ( method_exists( $value, "attribute" ) and 01217 method_exists( $value, "hasattribute" ) ) 01218 { 01219 if ( $value->hasAttribute( $attributeValue ) ) 01220 { 01221 $value = $value->attribute( $attributeValue ); 01222 } 01223 else 01224 { 01225 if ( !$checkExistance ) 01226 { 01227 $objectAttributeList = array(); 01228 if ( method_exists( $value, 'attributes' ) ) 01229 $objectAttributeList = $value->attributes(); 01230 $objectClass= get_class( $value ); 01231 $errorMessage = "No such attribute for object($objectClass): $attributeValue"; 01232 $chooseText = "Choose one of following: "; 01233 $errorMessage .= "\n$chooseText"; 01234 $errorMessage .= $this->expandAttributes( $objectAttributeList, $chooseText, 25 ); 01235 $this->error( "", 01236 $errorMessage, $placement ); 01237 } 01238 return null; 01239 } 01240 } 01241 else 01242 { 01243 if ( !$checkExistance ) 01244 $this->error( "", 01245 "Cannot retrieve attribute of object(" . get_class( $value ) . 01246 "), no attribute functions available", 01247 $placement ); 01248 return null; 01249 } 01250 } 01251 else 01252 { 01253 if ( !$checkExistance ) 01254 $this->error( "", 01255 "Cannot retrieve attribute of a " . gettype( $value ), 01256 $placement ); 01257 return null; 01258 } 01259 } 01260 else 01261 { 01262 if ( !$checkExistance ) 01263 $this->error( '', 01264 'Attribute value was null, cannot get attribute', 01265 $placement ); 01266 return null; 01267 } 01268 } break; 01269 case eZTemplate::TYPE_OPERATOR: 01270 { 01271 $operatorParameters = $dataElement[1]; 01272 $operatorName = $operatorParameters[0]; 01273 $operatorParameters = array_splice( $operatorParameters, 1 ); 01274 if ( is_object( $value ) and 01275 method_exists( $value, 'templateValue' ) ) 01276 { 01277 if ( $checkForProxy ) 01278 $dataElements['proxy-object-found'] = true; 01279 $value = $value->templateValue(); 01280 } 01281 $valueData = array( 'value' => $value ); 01282 $this->processOperator( $operatorName, $operatorParameters, $rootNamespace, $currentNamespace, 01283 $valueData, $placement, $checkExistance ); 01284 $value = $valueData['value']; 01285 } break; 01286 default: 01287 { 01288 if ( !$checkExistance ) 01289 $this->error( "elementValue", 01290 "Unknown data type: '$dataType'" ); 01291 return null; 01292 } 01293 } 01294 } 01295 if ( is_object( $value ) and 01296 method_exists( $value, 'templateValue' ) ) 01297 { 01298 if ( $checkForProxy ) 01299 $dataElements['proxy-object-found'] = true; 01300 return $value->templateValue(); 01301 } 01302 return $value; 01303 } 01304 01305 function expandAttributes( $attributeList, $chooseText, $maxThreshold, $minThreshold = 1 ) 01306 { 01307 $errorMessage = ''; 01308 $attributeCount = count( $attributeList ); 01309 if ( $attributeCount < $minThreshold ) 01310 return $errorMessage; 01311 if ( $attributeCount < $maxThreshold ) 01312 { 01313 $chooseLength = strlen( $chooseText ); 01314 $attributeText = ''; 01315 $i = 0; 01316 foreach ( $attributeList as $attributeName ) 01317 { 01318 if ( $i > 0 ) 01319 $attributeText .= ","; 01320 if ( strlen( $attributeText ) > 40 ) 01321 { 01322 $attributeText .= "\n"; 01323 $errorMessage .= $attributeText; 01324 $errorMessage .= str_repeat( ' ', $chooseLength ); 01325 $attributeText = ''; 01326 } 01327 else if ( $i > 0 ) 01328 $attributeText .= " "; 01329 $attributeText .= $attributeName; 01330 ++$i; 01331 } 01332 $errorMessage .= $attributeText; 01333 } 01334 return $errorMessage; 01335 } 01336 01337 function processOperator( $operatorName, $operatorParameters, $rootNamespace, $currentNamespace, 01338 &$valueData, $placement = false, $checkExistance = false ) 01339 { 01340 $namedParameters = array(); 01341 $operatorParameterDefinition = $this->operatorParameterList( $operatorName ); 01342 $i = 0; 01343 foreach ( $operatorParameterDefinition as $parameterName => $parameterType ) 01344 { 01345 if ( !isset( $operatorParameters[$i] ) or 01346 !isset( $operatorParameters[$i][0] ) or 01347 $operatorParameters[$i][0] == eZTemplate::TYPE_VOID ) 01348 { 01349 if ( $parameterType["required"] ) 01350 { 01351 if ( !$checkExistance ) 01352 $this->warning( "eZTemplateOperatorElement", "Parameter '$parameterName' ($i) missing", 01353 $placement ); 01354 $namedParameters[$parameterName] = $parameterType["default"]; 01355 } 01356 else 01357 { 01358 $namedParameters[$parameterName] = $parameterType["default"]; 01359 } 01360 } 01361 else 01362 { 01363 $parameterData = $operatorParameters[$i]; 01364 $namedParameters[$parameterName] = $this->elementValue( $parameterData, $rootNamespace, $currentNamespace, false, $checkExistance ); 01365 } 01366 ++$i; 01367 } 01368 01369 if ( isset( $this->Operators[$operatorName] ) ) 01370 { 01371 if ( is_array( $this->Operators[$operatorName] ) ) 01372 { 01373 $this->loadAndRegisterOperators( $this->Operators[$operatorName] ); 01374 } 01375 01376 $op = $this->Operators[$operatorName]; 01377 01378 if ( is_object( $op ) and method_exists( $op, 'modify' ) ) 01379 { 01380 $value = $valueData['value']; 01381 if ( eZTemplate::isMethodDebugEnabled() ) 01382 eZDebug::writeDebug( "START OPERATOR: $operatorName" ); 01383 $op->modify( $this, $operatorName, $operatorParameters, $rootNamespace, $currentNamespace, $value, $namedParameters, 01384 $placement ); 01385 if ( eZTemplate::isMethodDebugEnabled() ) 01386 eZDebug::writeDebug( "END OPERATOR: $operatorName" ); 01387 $valueData['value'] = $value; 01388 } 01389 else 01390 $this->error( '', "Object problem with operator '$operatorName' ", 01391 $placement ); 01392 } 01393 else if ( !$checkExistance ) 01394 $this->warning( "", "Operator '$operatorName' is not registered", 01395 $placement ); 01396 } 01397 01398 /*! 01399 Return the identifier used for attribute lookup. 01400 */ 01401 function attributeValue( &$data, $nspace ) 01402 { 01403 switch ( $data["type"] ) 01404 { 01405 case "map": 01406 { 01407 return $data["content"]; 01408 } break; 01409 case "index": 01410 { 01411 return $data["content"]; 01412 } break; 01413 case "variable": 01414 { 01415 return $this->elementValue( $data["content"], $nspace ); 01416 } break; 01417 default: 01418 { 01419 $this->error( "attributeValue()", "Unknown attribute type: " . $data["type"] ); 01420 return null; 01421 } 01422 } 01423 } 01424 01425 /*! 01426 Helper function for creating a displayable text for a variable. 01427 */ 01428 function variableText( $var, $namespace = "", $attrs = array() ) 01429 { 01430 $txt = "$"; 01431 if ( $namespace != "" ) 01432 $txt .= "$namespace:"; 01433 $txt .= $var; 01434 if ( count( $attrs ) > 0 ) 01435 $txt .= "." . implode( ".", $attrs ); 01436 return $txt; 01437 } 01438 01439 /*! 01440 Returns the named parameter list for the operator $name. 01441 */ 01442 function operatorParameterList( $name ) 01443 { 01444 $param_list = array(); 01445 if ( !isset( $this->Operators[$name] ) ) 01446 { 01447 return $param_list; 01448 } 01449 01450 if ( is_array( $this->Operators[$name] ) ) 01451 { 01452 $this->loadAndRegisterOperators( $this->Operators[$name] ); 01453 } 01454 01455 $op = $this->Operators[$name]; 01456 if ( isset( $op ) and 01457 method_exists( $op, "namedparameterlist" ) ) 01458 { 01459 $param_list = $op->namedParameterList(); 01460 if ( method_exists( $op, "namedparameterperoperator" ) and 01461 $op->namedParameterPerOperator() ) 01462 { 01463 if ( !isset( $param_list[$name] ) ) 01464 return array(); 01465 $param_list = $param_list[$name]; 01466 } 01467 } 01468 return $param_list; 01469 } 01470 01471 /*! 01472 Tries to run the operator $operatorName with parameters $operatorParameters 01473 on the value $value. 01474 */ 01475 function doOperator( $element, &$namespace, &$current_nspace, &$value, $operatorName, $operatorParameters, &$named_params ) 01476 { 01477 if ( is_array( $this->Operators[$operatorName] ) ) 01478 { 01479 $this->loadAndRegisterOperators( $this->Operators[$operatorName] ); 01480 } 01481 $op = $this->Operators[$operatorName]; 01482 if ( isset( $op ) ) 01483 { 01484 $op->modify( $element, $this, $operatorName, $operatorParameters, $namespace, $current_nspace, $value, $named_params ); 01485 } 01486 else 01487 $this->warning( "", "Operator \"$operatorName\" is not registered" ); 01488 } 01489 01490 /*! 01491 Tries to run the function object $func_obj 01492 */ 01493 function doFunction( $name, $func_obj, $nspace, $current_nspace ) 01494 { 01495 $func = $this->Functions[$name]; 01496 if ( is_array( $func ) ) 01497 { 01498 $this->loadAndRegisterFunctions( $this->Functions[$name] ); 01499 $func = $this->Functions[$name]; 01500 } 01501 if ( isset( $func ) and 01502 is_object( $func ) ) 01503 { 01504 return $func->process( $this, $name, $func_obj, $nspace, $current_nspace ); 01505 } 01506 else 01507 { 01508 $this->warning( "", "Function \"$name\" is not registered" ); 01509 return false; 01510 } 01511 } 01512 01513 /*! 01514 Sets the template variable $var to the value $val. 01515 \sa setVariableRef 01516 */ 01517 function setVariable( $var, $val, $namespace = "" ) 01518 { 01519 if ( array_key_exists( $namespace, $this->Variables ) and 01520 array_key_exists( $var, $this->Variables[$namespace] ) ) 01521 unset( $this->Variables[$namespace][$var] ); 01522 $this->Variables[$namespace][$var] = $val; 01523 } 01524 01525 /*! 01526 Sets the template variable $var to the value $val. 01527 \note This sets the variable using reference 01528 \sa setVariable 01529 */ 01530 function setVariableRef( $var, $val, $namespace = "" ) 01531 { 01532 if ( array_key_exists( $namespace, $this->Variables ) and 01533 array_key_exists( $var, $this->Variables[$namespace] ) ) 01534 unset( $this->Variables[$namespace][$var] ); 01535 $this->Variables[$namespace][$var] = $val; 01536 } 01537 01538 /*! 01539 Removes the template variable $var. If the variable does not exists an error is output. 01540 */ 01541 function unsetVariable( $var, $namespace = "" ) 01542 { 01543 if ( array_key_exists( $namespace, $this->Variables ) and 01544 array_key_exists( $var, $this->Variables[$namespace] ) ) 01545 unset( $this->Variables[$namespace][$var] ); 01546 else 01547 $this->warning( "unsetVariable()", "Undefined Variable: \$$namespace:$var, cannot unset" ); 01548 } 01549 01550 /*! 01551 Returns true if the variable $var is set in namespace $namespace, 01552 if $attrs is supplied alle attributes must exist for the function to return true. 01553 */ 01554 function hasVariable( $var, $namespace = "", $attrs = array() ) 01555 { 01556 $exists = ( array_key_exists( $namespace, $this->Variables ) and 01557 array_key_exists( $var, $this->Variables[$namespace] ) ); 01558 if ( $exists and count( $attrs ) > 0 ) 01559 { 01560 $ptr =& $this->Variables[$namespace][$var]; 01561 foreach( $attrs as $attr ) 01562 { 01563 unset( $tmp ); 01564 if ( is_object( $ptr ) ) 01565 { 01566 if ( $ptr->hasAttribute( $attr ) ) 01567 $tmp = $ptr->attribute( $attr ); 01568 else 01569 return false; 01570 } 01571 else if ( is_array( $ptr ) ) 01572 { 01573 if ( array_key_exists( $attr, $ptr ) ) 01574 $tmp =& $ptr[$attr]; 01575 else 01576 return false; 01577 } 01578 else 01579 { 01580 return false; 01581 } 01582 unset( $ptr ); 01583 $ptr =& $tmp; 01584 } 01585 } 01586 return $exists; 01587 } 01588 01589 /*! 01590 Returns the content of the variable $var using namespace $namespace, 01591 if $attrs is supplied the result of the attributes is returned. 01592 */ 01593 function variable( $var, $namespace = "", $attrs = array() ) 01594 { 01595 $val = null; 01596 $exists = ( array_key_exists( $namespace, $this->Variables ) and 01597 array_key_exists( $var, $this->Variables[$namespace] ) ); 01598 if ( $exists ) 01599 { 01600 if ( count( $attrs ) > 0 ) 01601 { 01602 $element = $this->Variables[$namespace][$var]; 01603 foreach( $attrs as $attr ) 01604 { 01605 if ( is_object( $element ) ) 01606 { 01607 if ( $element->hasAttribute( $attr ) ) 01608 { 01609 $element = $element->attribute( $attr ); 01610 } 01611 else 01612 { 01613 return $val; 01614 } 01615 } 01616 else if ( is_array( $element ) ) 01617 { 01618 if ( array_key_exists( $attr, $element ) ) 01619 { 01620 $val = $element[$attr]; 01621 } 01622 else 01623 { 01624 return $val; 01625 } 01626 } 01627 else 01628 { 01629 return $val; 01630 } 01631 $val = $element; 01632 } 01633 } 01634 else 01635 { 01636 $val = $this->Variables[$namespace][$var]; 01637 } 01638 } 01639 return $val; 01640 } 01641 01642 /*! 01643 Returns the attribute(s) of the template variable $var, 01644 $attrs is an array of attribute names to use iteratively for each new variable returned. 01645 */ 01646 function variableAttribute( $var, $attrs ) 01647 { 01648 foreach( $attrs as $attr ) 01649 { 01650 if ( is_object( $var ) ) 01651 { 01652 if ( $var->hasAttribute( $attr ) ) 01653 { 01654 $var = $var->attribute( $attr ); 01655 } 01656 else 01657 { 01658 return null; 01659 } 01660 } 01661 else if ( is_array( $var ) ) 01662 { 01663 if ( isset( $var[$attr] ) ) 01664 { 01665 $var = $var[$attr]; 01666 } 01667 else 01668 { 01669 return null; 01670 } 01671 } 01672 else 01673 { 01674 return null; 01675 } 01676 } 01677 if ( isset( $var ) ) 01678 { 01679 return $var; 01680 } 01681 01682 return null; 01683 } 01684 01685 /*! 01686 */ 01687 function appendElement( &$text, $item, $nspace, $name ) 01688 { 01689 $this->appendElementText( $textElements, $item, $nspace, $name ); 01690 $text .= implode( '', $textElements ); 01691 } 01692 01693 /*! 01694 */ 01695 function appendElementText( &$textElements, $item, $nspace, $name ) 01696 { 01697 if ( !is_array( $textElements ) ) 01698 $textElements = array(); 01699 if ( is_object( $item ) and 01700 method_exists( $item, 'templateValue' ) ) 01701 { 01702 $item = $item->templateValue(); 01703 $textElements[] = "$item"; 01704 } 01705 else if ( is_object( $item ) ) 01706 { 01707 $hasTemplateData = false; 01708 if ( method_exists( $item, 'templateData' ) ) 01709 { 01710 $templateData = $item->templateData(); 01711 if ( is_array( $templateData ) and 01712 isset( $templateData['type'] ) ) 01713 { 01714 if ( $templateData['type'] == 'template' and 01715 isset( $templateData['uri'] ) and 01716 isset( $templateData['template_variable_name'] ) ) 01717 { 01718 $templateURI =& $templateData['uri']; 01719 $templateVariableName =& $templateData['template_variable_name']; 01720 $templateText = ''; 01721 //include_once( 'lib/eztemplate/classes/eztemplateincludefunction.php' ); 01722 $this->setVariableRef( $templateVariableName, $item, $name ); 01723 eZTemplateIncludeFunction::handleInclude( $textElements, $templateURI, $this, $nspace, $name ); 01724 $hasTemplateData = true; 01725 } 01726 } 01727 } 01728 if ( !$hasTemplateData ) 01729 $textElements[] = method_exists( $item, '__toString' ) ? (string)$item : 'Object(' . get_class( $item ) . ')'; 01730 } 01731 else 01732 $textElements[] = "$item"; 01733 return $textElements; 01734 } 01735 01736 /*! 01737 Creates some text nodes before and after the children of \a $root. 01738 It will extract the current filename and uri and create some XHTML 01739 comments and inline text. 01740 \sa isXHTMLCodeIncluded 01741 */ 01742 function appendDebugNodes( &$root, &$resourceData ) 01743 { 01744 $path = $resourceData['template-filename']; 01745 $uri = $resourceData['uri']; 01746 $preText = "\n<!-- START: including template: $path ($uri) -->\n"; 01747 if ( eZTemplate::isXHTMLCodeIncluded() ) 01748 $preText .= "<p class=\"small\">$path</p><br/>\n"; 01749 $postText = "\n<!-- STOP: including template: $path ($uri) -->\n"; 01750 //include_once( 'lib/eztemplate/classes/eztemplatenodetool.php' ); 01751 $root[1] = array_merge( array( eZTemplateNodeTool::createTextNode( $preText ) ), $root[1] ); 01752 $root[1][] = eZTemplateNodeTool::createTextNode( $postText ); 01753 } 01754 01755 /*! 01756 Registers the functions supplied by the object $functionObject. 01757 The object must have a function called functionList() 01758 which returns an array of functions this object handles. 01759 If the object has a function called attributeList() 01760 it is used for registering function attributes. 01761 The function returns an associative array with each key being 01762 the name of the function and the value being a boolean. 01763 If the boolean is true the function will have children. 01764 */ 01765 function registerFunctions( &$functionObject ) 01766 { 01767 $this->registerFunctionsInternal( $functionObject ); 01768 } 01769 01770 /*! 01771 */ 01772 function registerAutoloadFunctions( $functionDefinition ) 01773 { 01774 if ( ( ( isset( $functionDefinition['function'] ) or 01775 ( isset( $functionDefinition['script'] ) and 01776 isset( $functionDefinition['class'] ) ) ) and 01777 ( isset( $functionDefinition['function_names_function'] ) or 01778 isset( $functionDefinition['function_names'] ) ) ) ) 01779 { 01780 if ( isset( $functionDefinition['function_names_function'] ) ) 01781 { 01782 $functionNamesFunction = $functionDefinition['function_names_function']; 01783 if ( !function_exists( $functionNamesFunction ) ) 01784 { 01785 $this->error( 'registerFunctions', "Cannot register function definition, missing function names function '$functionNamesFunction'" ); 01786 return; 01787 } 01788 $functionNames = $functionNamesFunction(); 01789 } 01790 else 01791 $functionNames = $functionDefinition['function_names']; 01792 foreach ( $functionNames as $functionName ) 01793 { 01794 $this->Functions[$functionName] = $functionDefinition; 01795 } 01796 if ( isset( $functionDefinition['function_attributes'] ) ) 01797 { 01798 foreach ( $functionDefinition['function_attributes'] as $functionAttributeName ) 01799 { 01800 $this->FunctionAttributes[$functionAttributeName] = $functionDefinition; 01801 } 01802 } 01803 } 01804 else 01805 $this->error( 'registerFunctions', 'Cannot register function definition, missing data' ); 01806 } 01807 01808 function loadAndRegisterFunctions( $functionDefinition ) 01809 { 01810 eZDebug::accumulatorStart( 'template_register_function', 'template_total', 'Template load and register function' ); 01811 $functionObject = null; 01812 if ( isset( $functionDefinition['function'] ) ) 01813 { 01814 $function = $functionDefinition['function']; 01815 // print( "loadAndRegisterFunction: $function<br/>" ); 01816 if ( function_exists( $function ) ) 01817 $functionObject = $function(); 01818 } 01819 else if ( isset( $functionDefinition['script'] ) ) 01820 { 01821 $script = $functionDefinition['script']; 01822 $class = $functionDefinition['class']; 01823 // print( "loadAndRegisterFunction: $script<br/>" ); 01824 include_once( $script ); 01825 if ( class_exists( $class ) ) 01826 $functionObject = new $class(); 01827 } 01828 eZDebug::accumulatorStop( 'template_register_function' ); 01829 if ( is_object( $functionObject ) ) 01830 { 01831 $this->registerFunctionsInternal( $functionObject, true ); 01832 return true; 01833 } 01834 return false; 01835 } 01836 01837 /*! 01838 \private 01839 */ 01840 function registerFunctionsInternal( $functionObject, $debug = false ) 01841 { 01842 if ( !is_object( $functionObject ) or 01843 !method_exists( $functionObject, 'functionList' ) ) 01844 return false; 01845 foreach ( $functionObject->functionList() as $functionName ) 01846 { 01847 $this->Functions[$functionName] = $functionObject; 01848 } 01849 if ( method_exists( $functionObject, "attributeList" ) ) 01850 { 01851 $functionAttributes = $functionObject->attributeList(); 01852 foreach ( $functionAttributes as $attributeName => $hasChildren ) 01853 { 01854 $this->FunctionAttributes[$attributeName] = $hasChildren; 01855 } 01856 } 01857 return true; 01858 } 01859 01860 /*! 01861 Registers the function $func_name to be bound to object $func_obj. 01862 If the object has a function called attributeList() 01863 it is used for registering function attributes. 01864 The function returns an associative array with each key being 01865 the name of the function and the value being a boolean. 01866 If the boolean is true the function will have children. 01867 */ 01868 function registerFunction( $func_name, $func_obj ) 01869 { 01870 $this->Functions[$func_name] = $func_obj; 01871 if ( method_exists( $func_obj, "attributeList" ) ) 01872 { 01873 $attrs = $func_obj->attributeList(); 01874 while ( list( $attr_name, $has_children ) = each( $attrs ) ) 01875 { 01876 $this->FunctionAttributes[$attr_name] = $has_children; 01877 } 01878 } 01879 } 01880 01881 /*! 01882 Registers a new literal tag in which the tag will be transformed into 01883 a text element. 01884 */ 01885 function registerLiteral( $func_name ) 01886 { 01887 $this->Literals[$func_name] = true; 01888 } 01889 01890 /*! 01891 Removes the literal tag $func_name. 01892 */ 01893 function unregisterLiteral( $func_name ) 01894 { 01895 unset( $this->Literals[$func_name] ); 01896 } 01897 01898 /*! 01899 */ 01900 function registerAutoloadOperators( $operatorDefinition ) 01901 { 01902 if ( ( ( isset( $operatorDefinition['function'] ) or 01903 ( isset( $operatorDefinition['script'] ) and 01904 isset( $operatorDefinition['class'] ) ) ) and 01905 ( isset( $operatorDefinition['operator_names_function'] ) or 01906 isset( $operatorDefinition['operator_names'] ) ) ) ) 01907 { 01908 if ( isset( $operatorDefinition['operator_names_function'] ) ) 01909 { 01910 $operatorNamesFunction = $operatorDefinition['operator_names_function']; 01911 if ( !function_exists( $operatorNamesFunction ) ) 01912 { 01913 $this->error( 'registerOperators', "Cannot register operator definition, missing operator names function '$operatorNamesFunction'" ); 01914 return; 01915 } 01916 $operatorNames = $operatorNamesFunction(); 01917 } 01918 else 01919 $operatorNames = $operatorDefinition['operator_names']; 01920 foreach ( $operatorNames as $operatorName ) 01921 { 01922 $this->Operators[$operatorName] = $operatorDefinition; 01923 } 01924 } 01925 else 01926 $this->error( 'registerOperators', 'Cannot register operator definition, missing data' ); 01927 } 01928 01929 function loadAndRegisterOperators( $operatorDefinition ) 01930 { 01931 $operatorObject = null; 01932 if ( isset( $operatorDefinition['function'] ) ) 01933 { 01934 $function = $operatorDefinition['function']; 01935 // print( "loadAndRegisterOperator: $function<br/>" ); 01936 if ( function_exists( $function ) ) 01937 $operatorObject = $function(); 01938 } 01939 else if ( isset( $operatorDefinition['script'] ) ) 01940 { 01941 $script = $operatorDefinition['script']; 01942 $class = $operatorDefinition['class']; 01943 // print( "loadAndRegisterOperator: $script<br/>" ); 01944 include_once( $script ); 01945 if ( class_exists( $class ) ) 01946 { 01947 if ( isset( $operatorDefinition['class_parameter'] ) ) 01948 $operatorObject = new $class( $operatorDefinition['class_parameter'] ); 01949 else 01950 $operatorObject = new $class(); 01951 } 01952 } 01953 if ( is_object( $operatorObject ) ) 01954 { 01955 $this->registerOperatorsInternal( $operatorObject, true ); 01956 return true; 01957 } 01958 return false; 01959 } 01960 01961 /*! 01962 Registers the operators supplied by the object $operatorObject. 01963 The function operatorList() must return an array of operator names. 01964 */ 01965 function registerOperators( &$operatorObject ) 01966 { 01967 $this->registerOperatorsInternal( $operatorObject ); 01968 } 01969 01970 /*! 01971 */ 01972 function registerOperatorsInternal( $operatorObject, $debug = false ) 01973 { 01974 if ( !is_object( $operatorObject ) or 01975 !method_exists( $operatorObject, 'operatorList' ) ) 01976 return false; 01977 foreach( $operatorObject->operatorList() as $operatorName ) 01978 { 01979 $this->Operators[$operatorName] = $operatorObject; 01980 } 01981 } 01982 01983 /*! 01984 Registers the operator $op_name to use the object $op_obj. 01985 */ 01986 function registerOperator( $op_name, $op_obj ) 01987 { 01988 $this->Operators[$op_name] = $op_obj; 01989 } 01990 01991 /*! 01992 Unregisters the operator $op_name. 01993 */ 01994 function unregisterOperator( $op_name ) 01995 { 01996 if ( is_array( $op_name ) ) 01997 { 01998 foreach ( $op_name as $op ) 01999 { 02000 $this->unregisterOperator( $op_name ); 02001 } 02002 } 02003 else if ( isset( $this->Operators ) ) 02004 unset( $this->Operators[$op_name] ); 02005 else 02006 $this->warning( "unregisterOpearator()", "Operator $op_name is not registered, cannot unregister" ); 02007 } 02008 02009 /*! 02010 Not implemented yet. 02011 */ 02012 function registerFilter() 02013 { 02014 } 02015 02016 /*! 02017 Registers a new resource object $res. 02018 The resource object take care of fetching templates using an URI. 02019 */ 02020 function registerResource( $res ) 02021 { 02022 if ( is_object( $res ) ) 02023 $this->Resources[$res->resourceName()] =& $res; 02024 else 02025 $this->warning( "registerResource()", "Supplied argument is not a resource object" ); 02026 } 02027 02028 /*! 02029 Unregisters the resource $res_name. 02030 */ 02031 function unregisterResource( $res_name ) 02032 { 02033 if ( is_array( $res_name ) ) 02034 { 02035 foreach ( $res_name as $res ) 02036 { 02037 $this->unregisterResource( $res ); 02038 } 02039 } 02040 else if ( isset( $this->Resources[$res_name] ) ) 02041 unset( $this->Resources[$res_name] ); 02042 else 02043 $this->warning( "unregisterResource()", "Resource $res_name is not registered, cannot unregister" ); 02044 } 02045 02046 /*! 02047 Sets whether detail output is used or not. 02048 Detail output is useful for debug output where you want to examine the template 02049 and the output text. 02050 */ 02051 function setShowDetails( $show ) 02052 { 02053 $this->ShowDetails = $show; 02054 } 02055 02056 /*! 02057 Outputs a warning about the parameter $param missing for function/operator $name. 02058 */ 02059 function missingParameter( $name, $param ) 02060 { 02061 $this->warning( $name, "Missing parameter $param" ); 02062 } 02063 02064 /*! 02065 Outputs a warning about the parameter count being to high for function/operator $name. 02066 */ 02067 function extraParameters( $name, $count, $maxCount ) 02068 { 02069 $this->warning( $name, "Passed $count parameters but correct count is $maxCount" ); 02070 } 02071 02072 /*! 02073 Outputs a warning about the variable $var being undefined. 02074 */ 02075 function undefinedVariable( $name, $var ) 02076 { 02077 $this->warning( $name, "Undefined variable: $var" ); 02078 } 02079 02080 /*! 02081 Outputs an error about the template function $func_name being undefined. 02082 */ 02083 function undefinedFunction( $func_name ) 02084 { 02085 $this->error( "", "Undefined function: $func_name" ); 02086 } 02087 02088 /*! 02089 Creates a string for the placement information and returns it. 02090 \note The placement information can either be in indexed or associative 02091 */ 02092 function placementText( $placement = false ) 02093 { 02094 $placementText = false; 02095 if ( $placement !== false ) 02096 { 02097 if ( isset( $placement['start'] ) and 02098 isset( $placement['stop'] ) and 02099 isset( $placement['templatefile'] ) ) 02100 { 02101 $line = $placement['start']['line']; 02102 $column = $placement['start']['column']; 02103 $templateFile = $placement['templatefile']; 02104 } 02105 else 02106 { 02107 $line = $placement[0][0]; 02108 $column = $placement[0][1]; 02109 $templateFile = $placement[2]; 02110 } 02111 02112 $placementText = " @ $templateFile:$line" . "[$column]"; 02113 } 02114 return $placementText; 02115 } 02116 02117 /*! 02118 Displays a warning for the function/operator $name and text $txt. 02119 */ 02120 function warning( $name, $txt, $placement = false ) 02121 { 02122 $this->WarningLog[] = array( 'name' => $name, 02123 'text' => $txt, 02124 'placement' => $placement ); 02125 02126 if ( !is_string( $placement ) ) 02127 $placementText = $this->placementText( $placement ); 02128 else 02129 $placementText = $placement; 02130 $placementText = $this->placementText( $placement ); 02131 if ( $name != "" ) 02132 eZDebug::writeWarning( $txt, "eZTemplate:$name" . $placementText ); 02133 else 02134 eZDebug::writeWarning( $txt, "eZTemplate" . $placementText ); 02135 } 02136 02137 /*! 02138 Displays an error for the function/operator $name and text $txt. 02139 */ 02140 function error( $name, $txt, $placement = false ) 02141 { 02142 $this->ErrorLog[] = array( 'name' => $name, 02143 'text' => $txt, 02144 'placement' => $placement ); 02145 02146 if ( !is_string( $placement ) ) 02147 $placementText = $this->placementText( $placement ); 02148 else 02149 $placementText = $placement; 02150 if ( $name != "" ) 02151 $nameText = "eZTemplate:$name"; 02152 else 02153 $nameText = "eZTemplate"; 02154 eZDebug::writeError( $txt, $nameText . $placementText ); 02155 $hasAppendWarning =& $GLOBALS['eZTemplateHasAppendWarning']; 02156 $ini = $this->ini(); 02157 if ( $ini->variable( 'ControlSettings', 'DisplayWarnings' ) == 'enabled' ) 02158 { 02159 if ( !isset( $hasAppendWarning ) or 02160 !$hasAppendWarning ) 02161 { 02162 if ( function_exists( 'eZAppendWarningItem' ) ) 02163 { 02164 eZAppendWarningItem( array( 'error' => array( 'type' => 'template', 02165 'number' => eZTemplate::FILE_ERRORS ), 02166 'text' => ezi18n( 'lib/eztemplate', 'Some template errors occurred, see debug for more information.' ) ) ); 02167 $hasAppendWarning = true; 02168 } 02169 } 02170 } 02171 } 02172 02173 02174 function operatorInputSupported( $operatorName ) 02175 { 02176 } 02177 02178 /*! 02179 Sets the original text for uri $uri to $text. 02180 */ 02181 function setIncludeText( $uri, $text ) 02182 { 02183 $this->IncludeText[$uri] = $text; 02184 } 02185 02186 /*! 02187 Sets the output for uri $uri to $output. 02188 */ 02189 function setIncludeOutput( $uri, $output ) 02190 { 02191 $this->IncludeOutput[$uri] = $output; 02192 } 02193 02194 /*! 02195 \return the path list which is used for autoloading functions and operators. 02196 */ 02197 function autoloadPathList() 02198 { 02199 return $this->AutoloadPathList; 02200 } 02201 02202 /*! 02203 Sets the path list for autoloading. 02204 */ 02205 function setAutoloadPathList( $pathList ) 02206 { 02207 $this->AutoloadPathList = $pathList; 02208 } 02209 02210 /*! 02211 Looks trough the pathes specified in autoloadPathList() and fetches autoload 02212 definition files used for autoloading functions and operators. 02213 */ 02214 function autoload() 02215 { 02216 $pathList = $this->autoloadPathList(); 02217 foreach ( $pathList as $path ) 02218 { 02219 $autoloadFile = $path . '/eztemplateautoload.php'; 02220 if ( file_exists( $autoloadFile ) ) 02221 { 02222 unset( $eZTemplateOperatorArray ); 02223 unset( $eZTemplateFunctionArray ); 02224 include( $autoloadFile ); 02225 if ( isset( $eZTemplateOperatorArray ) and 02226 is_array( $eZTemplateOperatorArray ) ) 02227 { 02228 foreach ( $eZTemplateOperatorArray as $operatorDefinition ) 02229 { 02230 $this->registerAutoloadOperators( $operatorDefinition ); 02231 } 02232 } 02233 if ( isset( $eZTemplateFunctionArray ) and 02234 is_array( $eZTemplateFunctionArray ) ) 02235 { 02236 foreach ( $eZTemplateFunctionArray as $functionDefinition ) 02237 { 02238 $this->registerAutoloadFunctions( $functionDefinition ); 02239 } 02240 } 02241 } 02242 } 02243 } 02244 02245 /*! 02246 Resets all template variables. 02247 */ 02248 function resetVariables() 02249 { 02250 $this->Variables = array(); 02251 } 02252 02253 /*! 02254 Resets all template functions and operators by calling the resetFunction and resetOperator 02255 on all elements that supports it. 02256 */ 02257 function resetElements() 02258 { 02259 foreach ( $this->Functions as $functionName => $functionObject ) 02260 { 02261 if ( is_object( $functionObject ) and 02262 method_exists( $functionObject, 'resetFunction' ) ) 02263 { 02264 $functionObject->resetFunction( $functionName ); 02265 } 02266 } 02267 02268 foreach ( $this->Operators as $operatorName => $operatorObject ) 02269 { 02270 if ( is_object( $operatorObject ) and 02271 method_exists( $operatorObject, 'resetOperator' ) ) 02272 { 02273 $operatorObject->resetOperator( $operatorName ); 02274 } 02275 } 02276 } 02277 02278 /*! 02279 Resets all template variables, functions, operators and error counts. 02280 */ 02281 function reset() 02282 { 02283 $this->resetVariables(); 02284 $this->resetElements(); 02285 $this->IsCachingAllowed = true; 02286 02287 $this->resetErrorLog(); 02288 02289 $this->TemplatesUsageStatistics = array(); 02290 $this->TemplateFetchList = array(); 02291 } 02292 02293 /*! 02294 \return The number of errors that occured with the last fetch 02295 \sa hasErrors() 02296 */ 02297 function errorCount() 02298 { 02299 return count( $this->ErrorLog ); 02300 } 02301 02302 /*! 02303 \return \ true if errors occured with the last fetch. 02304 \sa errorCount() 02305 */ 02306 function hasErrors() 02307 { 02308 return $this->errorCount() > 0; 02309 } 02310 02311 /*! 02312 \return error log. 02313 \sa errorCount() 02314 */ 02315 function errorLog() 02316 { 02317 return $this->ErrorLog; 02318 } 02319 02320 /*! 02321 \return The number of warnings that occured with the last fetch 02322 \sa hasWarnings() 02323 */ 02324 function warningCount() 02325 { 02326 return count( $this->WarningLog ); 02327 } 02328 02329 /*! 02330 \return \ true if warnings occured with the last fetch. 02331 \sa warningCount() 02332 */ 02333 function hasWarnings() 02334 { 02335 return $this->warningCount() > 0; 02336 } 02337 02338 /*! 02339 \return waring log. 02340 \sa warningCount() 02341 */ 02342 function warningLog() 02343 { 02344 return $this->WarningLog; 02345 } 02346 02347 /*! 02348 Returns the globale template instance, creating it if it does not exist. 02349 */ 02350 static function instance() 02351 { 02352 if ( !isset( $GLOBALS['eZTemplateInstance'] ) ) 02353 { 02354 $GLOBALS['eZTemplateInstance'] = new eZTemplate(); 02355 } 02356 02357 return $GLOBALS['eZTemplateInstance']; 02358 } 02359 02360 /*! 02361 Returns the INI object for the template.ini file. 02362 */ 02363 function ini() 02364 { 02365 //include_once( "lib/ezutils/classes/ezini.php" ); 02366 return eZINI::instance( "template.ini" ); 02367 } 02368 02369 /*! 02370 \static 02371 \return true if special XHTML code should be included before the included template file. 02372 This code will display the template filename in the browser but will eventually 02373 break the design. 02374 */ 02375 static function isXHTMLCodeIncluded() 02376 { 02377 if ( !isset( $GLOBALS['eZTemplateDebugXHTMLCodeEnabled'] ) ) 02378 { 02379 $ini = eZINI::instance(); 02380 $GLOBALS['eZTemplateDebugXHTMLCodeEnabled'] = $ini->variable( 'TemplateSettings', 'ShowXHTMLCode' ) == 'enabled'; 02381 } 02382 return $GLOBALS['eZTemplateDebugXHTMLCodeEnabled']; 02383 } 02384 02385 /*! 02386 \static 02387 \return \c true if debug output of template functions and operators should be enabled. 02388 */ 02389 static function isMethodDebugEnabled() 02390 { 02391 if ( !isset( $GLOBALS['eZTemplateDebugMethodEnabled'] ) ) 02392 { 02393 $ini = eZINI::instance(); 02394 $GLOBALS['eZTemplateDebugMethodEnabled'] = $ini->variable( 'TemplateSettings', 'ShowMethodDebug' ) == 'enabled'; 02395 } 02396 return $GLOBALS['eZTemplateDebugMethodEnabled']; 02397 } 02398 02399 /*! 02400 \static 02401 \return true if debugging of internals is enabled, this will display 02402 which files are loaded and when cache files are created. 02403 Set the option with setIsDebugEnabled(). 02404 */ 02405 static function isDebugEnabled() 02406 { 02407 if ( !isset( $GLOBALS['eZTemplateDebugInternalsEnabled'] ) ) 02408 $GLOBALS['eZTemplateDebugInternalsEnabled'] = eZTemplate::DEBUG_INTERNALS; 02409 return $GLOBALS['eZTemplateDebugInternalsEnabled']; 02410 } 02411 02412 /*! 02413 \static 02414 Sets whether internal debugging is enabled or not. 02415 */ 02416 static function setIsDebugEnabled( $debug ) 02417 { 02418 $GLOBALS['eZTemplateDebugInternalsEnabled'] = $debug; 02419 } 02420 02421 /*! 02422 \return \c true if caching is allowed (default) or \c false otherwise. 02423 This also affects template compiling. 02424 \sa setIsCachingAllowed 02425 */ 02426 function isCachingAllowed() 02427 { 02428 return $this->IsCachingAllowed; 02429 } 02430 02431 /*! 02432 Sets whether caching/compiling is allowed or not. This is useful 02433 if you need to make sure templates are parsed and processed 02434 without any caching mechanisms. 02435 \note The default is to allow caching. 02436 \sa isCachingAllowed 02437 */ 02438 function setIsCachingAllowed( $allowed ) 02439 { 02440 $this->IsCachingAllowed = $allowed; 02441 } 02442 02443 /*! 02444 \static 02445 \return \c true if templates usage statistics should be enabled. 02446 */ 02447 static function isTemplatesUsageStatisticsEnabled() 02448 { 02449 if ( !isset( $GLOBALS['eZTemplateDebugTemplatesUsageStatisticsEnabled'] ) ) 02450 { 02451 $ini = eZINI::instance(); 02452 $GLOBALS['eZTemplateDebugTemplatesUsageStatisticsEnabled'] = $ini->variable( 'TemplateSettings', 'ShowUsedTemplates' ) == 'enabled'; 02453 } 02454 return ( $GLOBALS['eZTemplateDebugTemplatesUsageStatisticsEnabled'] ); 02455 } 02456 02457 /*! 02458 \static 02459 Sets whether templates usage statistics enabled or not. 02460 \return \c true if templates usage statistics was enabled, otherwise \c false. 02461 */ 02462 function setIsTemplatesUsageStatisticsEnabled( $enabled ) 02463 { 02464 $wasEnabled = false; 02465 if( isset( $GLOBALS['eZTemplateDebugTemplatesUsageStatisticsEnabled'] ) ) 02466 $wasEnabled = $GLOBALS['eZTemplateDebugTemplatesUsageStatisticsEnabled']; 02467 02468 $GLOBALS['eZTemplateDebugTemplatesUsageStatisticsEnabled'] = $enabled; 02469 return $wasEnabled; 02470 } 02471 02472 /*! 02473 \static 02474 Checks settings and if 'ShowUsedTemplates' is enabled appends template info to stats. 02475 */ 02476 function appendTemplateToStatisticsIfNeeded( &$templateName, &$templateFileName ) 02477 { 02478 if ( eZTemplate::isTemplatesUsageStatisticsEnabled() ) 02479 eZTemplate::appendTemplateToStatistics( $templateName, $templateFileName ); 02480 } 02481 02482 /*! 02483 \static 02484 Appends template info to stats. 02485 */ 02486 function appendTemplateToStatistics( $templateName, $templateFileName ) 02487 { 02488 $actualTemplateName = preg_replace( "#^[\w/]+templates/#", '', $templateFileName ); 02489 $requestedTemplateName = preg_replace( "#^[\w/]+templates/#", '', $templateName ); 02490 02491 $tpl = eZTemplate::instance(); 02492 $needToAppend = true; 02493 02494 // don't add template info if it is a duplicate of previous. 02495 $statsSize = count( $tpl->TemplatesUsageStatistics ); 02496 if ( $statsSize > 0 ) 02497 { 02498 $lastTemplateInfo = $tpl->TemplatesUsageStatistics[$statsSize-1]; 02499 if ( $lastTemplateInfo['actual-template-name'] === $actualTemplateName && 02500 $lastTemplateInfo['requested-template-name'] === $requestedTemplateName && 02501 $lastTemplateInfo['template-filename'] === $templateFileName ) 02502 { 02503 $needToAppend = false; 02504 } 02505 } 02506 02507 if ( $needToAppend ) 02508 { 02509 $templateInfo = array( 'actual-template-name' => $actualTemplateName, 02510 'requested-template-name' => $requestedTemplateName, 02511 'template-filename' => $templateFileName ); 02512 02513 $tpl->TemplatesUsageStatistics[] = $templateInfo; 02514 } 02515 } 02516 02517 /*! 02518 Appends template info for current fetch. 02519 */ 02520 function appendTemplateFetch( $actualTemplateName ) 02521 { 02522 $this->TemplateFetchList[] = $actualTemplateName; 02523 $this->TemplateFetchList = array_unique( $this->TemplateFetchList ); 02524 } 02525 02526 /*! 02527 Reset error and warning logs 02528 */ 02529 function resetErrorLog() 02530 { 02531 $this->ErrorLog = array(); 02532 $this->WarningLog = array(); 02533 } 02534 02535 /*! 02536 \static 02537 Returns template usage statistics 02538 */ 02539 static function templatesUsageStatistics() 02540 { 02541 $tpl = eZTemplate::instance(); 02542 return $tpl->TemplatesUsageStatistics; 02543 } 02544 02545 /*! 02546 Returns template list for the last fetch. 02547 */ 02548 function templateFetchList() 02549 { 02550 return $this->TemplateFetchList; 02551 } 02552 02553 /*! 02554 Set template compilation test mode. 02555 02556 \param true, will set template compilation in test mode ( no disc writes ). 02557 false, will compile templates to disc 02558 */ 02559 function setCompileTest( $val ) 02560 { 02561 $this->TestCompile = $val; 02562 } 02563 02564 /*! 02565 Get if template session is test compile 02566 */ 02567 function testCompile() 02568 { 02569 return $this->TestCompile; 02570 } 02571 02572 /// \privatesection 02573 /// Associative array of resource objects 02574 public $Resources; 02575 /// Reference to the default resource object 02576 public $DefaultResource; 02577 /// The original template text 02578 public $Text; 02579 /// Included texts, usually performed by custom functions 02580 public $IncludeText; 02581 /// Included outputs, usually performed by custom functions 02582 public $IncludeOutput; 02583 /// The timestamp of the template when it was last modified 02584 public $TimeStamp; 02585 /// The left delimiter used for parsing 02586 public $LDelim; 02587 /// The right delimiter used for parsing 02588 public $RDelim; 02589 02590 /// The resulting object tree of the template 02591 public $Tree; 02592 /// An associative array of template variables 02593 public $Variables; 02594 /*! 02595 Last element of this stack contains names of 02596 all variables created in the innermost template, for them 02597 to be destroyed after the template execution finishes. 02598 */ 02599 public $LocalVariablesNamesStack; 02600 // Reference to the last element of $LocalVariablesNamesStack. 02601 public $CurrentLocalVariablesNames; 02602 /// An associative array of operators 02603 public $Operators; 02604 /// An associative array of functions 02605 public $Functions; 02606 /// An associative array of function attributes 02607 public $FunctionAttributes; 02608 /// An associative array of literal tags 02609 public $Literals; 02610 /// True if output details is to be shown 02611 public $ShowDetails = false; 02612 /// \c true if caching is allowed 02613 public $IsCachingAllowed; 02614 02615 /// Array containing all errors occured during a fetch 02616 public $ErrorLog; 02617 /// Array containing all warnings occured during a fetch 02618 public $WarningLog; 02619 02620 public $AutoloadPathList; 02621 /// include level 02622 public $Level = 0; 02623 public $MaxLevel = 40; 02624 02625 /// A list of templates used by a rendered page 02626 public $TemplatesUsageStatistics; 02627 02628 // counter to make unique names for {foreach} loop variables in com 02629 public $ForeachCounter; 02630 public $ForCounter; 02631 public $WhileCounter; 02632 public $DoCounter; 02633 public $ElseifCounter; 02634 02635 // Flag for setting compilation in test mode 02636 public $TestCompile; 02637 02638 // public $CurrentRelatedResource; 02639 // public $CurrentRelatedTemplateName; 02640 } 02641 02642 ?>