eZ Publish  [trunk]
eztemplatecompiler.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZTemplateCompiler class.
00004  *
00005  * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
00006  * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
00007  * @version //autogentag//
00008  * @package lib
00009  */
00010 
00011 /*!
00012   \class eZTemplateCompiler eztemplatecompiler.php
00013   \brief Creates compiled PHP code from templates to speed up template usage.
00014 
00015    Various optimizations that can be done are:
00016 
00017     Data:
00018     - Is constant, generate static data
00019     - Is variable, generate direct variable extraction
00020     - Has operators
00021     - Has attributes
00022 
00023     Attributes:
00024     - Is constant, generate static data
00025 
00026     Operators:
00027     - Supports input
00028     - Supports output
00029     - Supports parameters
00030     - Generates static data (true, false)
00031     - Custom PHP code
00032     - Modifies template variables, if possible name which ones. Allows
00033       for caching of variables in the script.
00034 
00035     Functions:
00036     - Supports parameters
00037     - Supports children (set? no, section? yes)
00038     - Generates static data (ldelim,rdelim)
00039     - Children usage, no result(set-block) | copy(let,default) | dynamic(conditional, repeated etc.)
00040     - Children tree, requires original tree | allows custom processing
00041     - Custom PHP code
00042     - Deflate/transform tree, create new non-nested tree (let, default)
00043     - Modifies template variables, if possible name which ones. Allows
00044       for caching of variables in the script.
00045 */
00046 
00047 class eZTemplateCompiler
00048 {
00049     const CODE_DATE = 1074699607;
00050 
00051     /*!
00052      \static
00053      Returns the prefix for file names
00054     */
00055     static function TemplatePrefix()
00056     {
00057         $templatePrefix = '';
00058         $ini = eZINI::instance();
00059         if ( $ini->variable( 'TemplateSettings', 'TemplateCompression' ) == 'enabled' )
00060         {
00061             $templatePrefix = 'compress.zlib://';
00062         }
00063         return $templatePrefix;
00064     }
00065     /*!
00066      \static
00067      Sets/unsets various compiler settings. To set a setting add a key in the \a $settingsMap
00068      with the wanted value, to unset it use \c null as the value.
00069 
00070      The following values can be set.
00071      - compile - boolean, whether to compile templates or not
00072      - comments - boolean, whether to include comments in templates
00073      - accumulators - boolean, whether to include debug accumulators in templates
00074      - timingpoints - boolean, whether to include debug timingpoints in templates
00075      - fallbackresource - boolean, whether to include the fallback resource code
00076      - nodeplacement - boolean, whether to include information on placement of all nodes
00077      - execution - boolean, whether to execute the compiled templates or not
00078      - generate - boolean, whether to always generate the compiled files, or only when template is changed
00079      - compilation-directory - string, where to place compiled files, the path will be relative from the
00080                                eZ Publish directory and not the var/cache directory.
00081     */
00082     static function setSettings( $settingsMap )
00083     {
00084         $existingMap = array();
00085         if ( isset( $GLOBALS['eZTemplateCompilerSettings'] ) )
00086         {
00087             $existingMap = $GLOBALS['eZTemplateCompilerSettings'];
00088         }
00089         $GLOBALS['eZTemplateCompilerSettings'] = array_merge( $existingMap, $settingsMap );
00090     }
00091 
00092     /*!
00093      \static
00094      \return true if template compiling is enabled.
00095      \note To change this setting edit settings/site.ini and locate the group TemplateSettings and the entry TemplateCompile.
00096     */
00097     static function isCompilationEnabled()
00098     {
00099         if ( isset( $GLOBALS['eZSiteBasics'] ) )
00100         {
00101             $siteBasics = $GLOBALS['eZSiteBasics'];
00102             if ( isset( $siteBasics['no-cache-adviced'] ) and
00103                  $siteBasics['no-cache-adviced'] )
00104             {
00105                 return false;
00106             }
00107         }
00108 
00109         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['compile'] ) and
00110              $GLOBALS['eZTemplateCompilerSettings']['compile'] !== null )
00111         {
00112             return $GLOBALS['eZTemplateCompilerSettings']['compile'];
00113         }
00114 
00115         $ini = eZINI::instance();
00116         $compilationEnabled = $ini->variable( 'TemplateSettings', 'TemplateCompile' ) == 'enabled';
00117         return $compilationEnabled;
00118     }
00119 
00120     /*!
00121      \static
00122      \return true if template compilation should include comments.
00123     */
00124     static function isCommentsEnabled()
00125     {
00126         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['comments'] ) and
00127              $GLOBALS['eZTemplateCompilerSettings']['comments'] !== null )
00128         {
00129             return $GLOBALS['eZTemplateCompilerSettings']['comments'];
00130         }
00131 
00132         $ini = eZINI::instance();
00133         $commentsEnabled = $ini->variable( 'TemplateSettings', 'CompileComments' ) == 'enabled';
00134         return $commentsEnabled;
00135     }
00136 
00137     /*!
00138      \static
00139      \return true if template compilation should run in development mode.
00140 
00141      When in development mode the system will perform additional checks, e.g. for
00142      modification time of compiled file vs original source file.
00143      This mode is quite useful for development since it requires less
00144      clear-cache calls but has additional file checks and should be turned off
00145      for live sites.
00146     */
00147     static function isDevelopmentModeEnabled()
00148     {
00149         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['development_mode'] ) and
00150              $GLOBALS['eZTemplateCompilerSettings']['development_mode'] !== null )
00151         {
00152             return $GLOBALS['eZTemplateCompilerSettings']['development_mode'];
00153         }
00154 
00155         $ini = eZINI::instance();
00156         $developmentModeEnabled = $ini->variable( 'TemplateSettings', 'DevelopmentMode' ) == 'enabled';
00157         return $developmentModeEnabled;
00158     }
00159 
00160     /*!
00161      \static
00162      \return true if template compilation should include debug accumulators.
00163     */
00164     static function isAccumulatorsEnabled()
00165     {
00166         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['accumulators'] ) and
00167              $GLOBALS['eZTemplateCompilerSettings']['accumulators'] !== null )
00168         {
00169             return $GLOBALS['eZTemplateCompilerSettings']['accumulators'];
00170         }
00171 
00172         $ini = eZINI::instance();
00173         $enabled = $ini->variable( 'TemplateSettings', 'CompileAccumulators' ) == 'enabled';
00174         return $enabled;
00175     }
00176 
00177     /*!
00178      \static
00179      \return true if template compilation should include debug timing points.
00180     */
00181     static function isTimingPointsEnabled()
00182     {
00183         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['timingpoints'] ) and
00184              $GLOBALS['eZTemplateCompilerSettings']['timingpoints'] !== null )
00185         {
00186             return $GLOBALS['eZTemplateCompilerSettings']['timingpoints'];
00187         }
00188 
00189         $ini = eZINI::instance();
00190         $enabled = $ini->variable( 'TemplateSettings', 'CompileTimingPoints' ) == 'enabled';
00191         return $enabled;
00192     }
00193 
00194     /*!
00195      \static
00196      \return true if resource fallback code should be included.
00197     */
00198     static function isFallbackResourceCodeEnabled()
00199     {
00200         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['fallbackresource'] ) and
00201              $GLOBALS['eZTemplateCompilerSettings']['fallbackresource'] !== null )
00202         {
00203             return $GLOBALS['eZTemplateCompilerSettings']['fallbackresource'];
00204         }
00205 
00206         $ini = eZINI::instance();
00207         $enabled = $ini->variable( 'TemplateSettings', 'CompileResourceFallback' ) == 'enabled';
00208         return $enabled;
00209     }
00210 
00211     /*!
00212      \static
00213      \return true if template compilation should include comments.
00214     */
00215     static function isNodePlacementEnabled()
00216     {
00217         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['nodeplacement'] ) and
00218              $GLOBALS['eZTemplateCompilerSettings']['nodeplacement'] !== null )
00219         {
00220             return $GLOBALS['eZTemplateCompilerSettings']['nodeplacement'];
00221         }
00222 
00223         $ini = eZINI::instance();
00224         $nodePlacementEnabled = $ini->variable( 'TemplateSettings', 'CompileNodePlacements' ) == 'enabled';
00225         return $nodePlacementEnabled;
00226     }
00227 
00228     /*!
00229      \static
00230      \return true if the compiled template execution is enabled.
00231     */
00232     static function isExecutionEnabled()
00233     {
00234         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['execution'] ) and
00235              $GLOBALS['eZTemplateCompilerSettings']['execution'] !== null )
00236         {
00237             return $GLOBALS['eZTemplateCompilerSettings']['execution'];
00238         }
00239 
00240         $ini = eZINI::instance();
00241         $execution = $ini->variable( 'TemplateSettings', 'CompileExecution' ) == 'enabled';
00242         return $execution;
00243     }
00244 
00245     /*!
00246      \static
00247      \return true if template compilation should always be run even if a sufficient compilation already exists.
00248     */
00249     static function alwaysGenerate()
00250     {
00251         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['generate'] ) and
00252              $GLOBALS['eZTemplateCompilerSettings']['generate'] !== null )
00253         {
00254             return $GLOBALS['eZTemplateCompilerSettings']['generate'];
00255         }
00256 
00257         $ini = eZINI::instance();
00258         $alwaysGenerate = $ini->variable( 'TemplateSettings', 'CompileAlwaysGenerate' ) == 'enabled';
00259         return $alwaysGenerate;
00260     }
00261 
00262     /*!
00263      \static
00264      \return true if template node tree named \a $treeName should be included the compiled template.
00265     */
00266     static function isTreeEnabled( $treeName )
00267     {
00268         $ini = eZINI::instance();
00269         $treeList = $ini->variable( 'TemplateSettings', 'CompileIncludeNodeTree' );
00270         return in_array( $treeName, $treeList );
00271     }
00272 
00273     /*!
00274      \static
00275      \return the directory for compiled templates.
00276     */
00277     static function compilationDirectory()
00278     {
00279         if ( isset( $GLOBALS['eZTemplateCompilerSettings']['compilation-directory'] ) and
00280              $GLOBALS['eZTemplateCompilerSettings']['compilation-directory'] !== null )
00281         {
00282             return $GLOBALS['eZTemplateCompilerSettings']['compilation-directory'];
00283         }
00284 
00285         $compilationDirectory =& $GLOBALS['eZTemplateCompilerDirectory'];
00286         if ( !isset( $compilationDirectory ) )
00287         {
00288             $ini = eZINI::instance();
00289             $shareTemplates = $ini->hasVariable( 'TemplateSettings', 'ShareCompiledTemplates' ) ?
00290                                 $ini->variable( 'TemplateSettings', 'ShareCompiledTemplates' ) == 'enabled' :
00291                                 false;
00292             if ( $shareTemplates &&
00293                  $ini->hasVariable( 'TemplateSettings', 'SharedCompiledTemplatesDir' ) &&
00294                  trim( $ini->variable( 'TemplateSettings', 'SharedCompiledTemplatesDir' ) ) != '' )
00295             {
00296                 $compilationDirectory = eZDir::path( array( $ini->variable( 'TemplateSettings', 'SharedCompiledTemplatesDir' ) ) );
00297             }
00298             else
00299             {
00300                 $compilationDirectory = eZDir::path( array( eZSys::cacheDirectory(), 'template/compiled' ) );
00301             }
00302         }
00303         return $compilationDirectory;
00304     }
00305 
00306     /*!
00307      Creates the name for the compiled template and returns it.
00308      The name conists of original filename with the md5 of the key and charset appended.
00309     */
00310     static function compilationFilename( $key, $resourceData )
00311     {
00312         $internalCharset = eZTextCodec::internalCharset();
00313         $templateFilepath = $resourceData['template-filename'];
00314         $extraName = '';
00315         if ( preg_match( "#^.+/(.*)\.tpl$#", $templateFilepath, $matches ) )
00316             $extraName = $matches[1] . '-';
00317         else if ( preg_match( "#^(.*)\.tpl$#", $templateFilepath, $matches ) )
00318             $extraName = $matches[1] . '-';
00319         $accessText = false;
00320         if ( isset( $GLOBALS['eZCurrentAccess']['name'] ) )
00321             $accessText = '-' . $GLOBALS['eZCurrentAccess']['name'];
00322         $locale = eZLocale::instance();
00323         $language = $locale->localeFullCode();
00324         $http = eZHTTPTool::instance();
00325         $useFullUrlText = $http->UseFullUrl ? 'full' : 'relative';
00326 
00327         $pageLayoutVariable = "";
00328         if ( isset( $GLOBALS['eZCustomPageLayout'] ) )
00329             $pageLayoutVariable = $GLOBALS['eZCustomPageLayout'];
00330 
00331         $ini = eZINI::instance();
00332 
00333         $shareTemplates = $ini->hasVariable( 'TemplateSettings', 'ShareCompiledTemplates' ) ?
00334                             $ini->variable( 'TemplateSettings', 'ShareCompiledTemplates' ) == 'enabled' :
00335                             false;
00336 
00337         if ( $shareTemplates )
00338             $cacheFileKey = $key . '-' . $language;
00339         else
00340             $cacheFileKey = $key . '-' . $internalCharset . '-' . $language . '-' . $useFullUrlText . $accessText . "-" . $pageLayoutVariable . '-' . eZSys::indexFile();
00341 
00342         $cacheFileName = $extraName . md5( $cacheFileKey ) . '.php';
00343         return $cacheFileName;
00344     }
00345 
00346     /*!
00347      \static
00348      \return true if the compiled template with the key \a $key exists.
00349              A compiled template is found usable when it exists and has a timestamp
00350              higher or equal to \a $timestamp.
00351     */
00352     static function hasCompiledTemplate( $key, $timestamp, &$resourceData )
00353     {
00354         if ( !eZTemplateCompiler::isCompilationEnabled() )
00355             return false;
00356         if ( eZTemplateCompiler::alwaysGenerate() )
00357             return false;
00358 
00359         $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $resourceData );
00360 
00361         $php = new eZPHPCreator( eZTemplateCompiler::compilationDirectory(), $cacheFileName, eZTemplateCompiler::TemplatePrefix() );
00362         $canRestore = $php->canRestore( $timestamp );
00363         $uri = false;
00364         if ( $canRestore )
00365             eZDebugSetting::writeDebug( 'eztemplate-compile', "Cache hit for uri '$uri' with key '$key'", 'eZTemplateCompiler::hasCompiledTemplate' );
00366         else
00367             eZDebugSetting::writeDebug( 'eztemplate-compile', "Cache miss for uri '$uri' with key '$key'", 'eZTemplateCompiler::hasCompiledTemplate' );
00368         return $canRestore;
00369     }
00370 
00371     /*!
00372      Tries to execute the compiled template and returns \c true if succsesful.
00373      Returns \c false if caching is disabled or the compiled template could not be executed.
00374     */
00375     static function executeCompilation( $tpl, &$textElements, $key, &$resourceData,
00376                                  $rootNamespace, $currentNamespace )
00377      {
00378         if ( !eZTemplateCompiler::isCompilationEnabled() )
00379             return false;
00380         if ( !eZTemplateCompiler::isExecutionEnabled() )
00381             return false;
00382         $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $resourceData );
00383         $resourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
00384 
00385         $directory = eZTemplateCompiler::compilationDirectory();
00386         $phpScript = eZDir::path( array( $directory, $cacheFileName ) );
00387         if ( file_exists( $phpScript ) )
00388         {
00389             $text = false;
00390             $helperStatus = eZTemplateCompiler::executeCompilationHelper( $phpScript, $text,
00391                                                                           $tpl, $key, $resourceData,
00392                                                                           $rootNamespace, $currentNamespace );
00393             if ( $helperStatus )
00394             {
00395                 $textElements[] = $text;
00396                 return true;
00397             }
00398             else
00399                 eZDebug::writeError( "Failed executing compiled template '$phpScript'", __METHOD__ );
00400         }
00401         else
00402             eZDebug::writeError( "Unknown compiled template '$phpScript'", __METHOD__ );
00403         return false;
00404     }
00405 
00406     /*!
00407      Helper function for executeCompilation. Will execute the script \a $phpScript and
00408      set the result text in \a $text.
00409      The parameters \a $tpl, \a $resourceData, \a $rootNamespace and \a $currentNamespace
00410      are passed to the executed template compilation script.
00411      \return true if a text result was created.
00412     */
00413     static function executeCompilationHelper( $phpScript, &$text,
00414                                        $tpl, $key, &$resourceData,
00415                                        $rootNamespace, $currentNamespace )
00416     {
00417         $vars =& $tpl->Variables;
00418 
00419         /* We use $setArray to detect if execution failed, and not $text,
00420          * because an empty template does not return any $text and this is not
00421          * an error. */
00422         $setArray = null;
00423         $namespaceStack = array();
00424 
00425         $tpl->createLocalVariablesList();
00426         include( eZTemplateCompiler::TemplatePrefix() . $phpScript );
00427         $tpl->unsetLocalVariables();
00428         $tpl->destroyLocalVariablesList();
00429 
00430         if ( $setArray !== null )
00431         {
00432             return true;
00433         }
00434         return false;
00435     }
00436 
00437     /*!
00438      \static
00439      Generates the cache which will be used for handling optimized processing using the key \a $key.
00440      \note Each call to this will set the PHP time limit to 30
00441      \return false if the cache does not exist.
00442     */
00443     static function compileTemplate( $tpl, $key, &$resourceData )
00444     {
00445         if ( !eZTemplateCompiler::isCompilationEnabled() )
00446             return false;
00447 
00448         $resourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
00449 
00450         $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $resourceData );
00451         $resourceData['uniqid'] = md5( $resourceData['template-filename']. uniqid( "ezp". getmypid(), true ) );
00452 
00453         // Time limit #1:
00454         // We reset the time limit to 30 seconds to ensure that templates
00455         // have enough time to compile
00456         // However if time limit is unlimited (0) we leave it be
00457         // Time limit will also be reset after subtemplates are compiled
00458         $maxExecutionTime = ini_get( 'max_execution_time' );
00459         if ( $maxExecutionTime != 0 && $maxExecutionTime < 30 )
00460         {
00461             @set_time_limit( 30 );
00462         }
00463 
00464         $rootNode =& $resourceData['root-node'];
00465         if ( !$rootNode )
00466             return false;
00467 
00468         $GLOBALS['eZTemplateCompilerResourceCache'][$resourceData['template-filename']] =& $resourceData;
00469 
00470         $useComments = eZTemplateCompiler::isCommentsEnabled();
00471 
00472         if ( !$resourceData['test-compile'] )
00473         {
00474             eZTemplateCompiler::createCommonCompileTemplate();
00475         }
00476 
00477         /* Check if we need to disable the generation of spacing for the compiled templates */
00478         $ini = eZINI::instance();
00479         $spacing = 'disabled';
00480         if ( $ini->variable( 'TemplateSettings', 'UseFormatting' ) == 'enabled' )
00481         {
00482             $spacing = 'enabled';
00483         }
00484 
00485         $php = new eZPHPCreator( eZTemplateCompiler::compilationDirectory(), $cacheFileName,
00486                                  eZTemplateCompiler::TemplatePrefix(), array( 'spacing' => $spacing ) );
00487         $php->addComment( 'URI:       ' . $resourceData['uri'] );
00488         $php->addComment( 'Filename:  ' . $resourceData['template-filename'] );
00489         $php->addComment( 'Timestamp: ' . $resourceData['time-stamp'] . ' (' . date( 'D M j G:i:s T Y', $resourceData['time-stamp'] ) . ')' );
00490 
00491         $php->addCodePiece("\$oldSetArray_{$resourceData['uniqid']} = isset( \$setArray ) ? \$setArray : array();\n".
00492                            "\$setArray = array();\n");
00493 // Code to decrement include level of the templates
00494         $php->addCodePiece( "\$tpl->Level++;\n" );
00495         $php->addCodePiece( "if ( \$tpl->Level > $tpl->MaxLevel )\n".
00496                             "{\n".
00497                             "\$text = \$tpl->MaxLevelWarning;".
00498                             "\$tpl->Level--;\n".
00499                             "return;\n".
00500                             "}\n" );
00501         if ( $resourceData['locales'] && count( $resourceData['locales'] ) )
00502         {
00503             $php->addComment( 'Locales:   ' . join( ', ', $resourceData['locales'] ) );
00504 
00505             $php->addCodePiece(
00506                 '$locales = array( "'. join( '", "', $resourceData['locales'] ) . "\" );\n".
00507                 '$oldLocale_'. $resourceData['uniqid']. ' = setlocale( LC_CTYPE, null );'. "\n".
00508                 '$currentLocale_'. $resourceData['uniqid']. ' = setlocale( LC_CTYPE, $locales );'. "\n"
00509             );
00510         }
00511 //         $php->addCodePiece( "print( \"" . $resourceData['template-filename'] . " ($cacheFileName)<br/>\n\" );" );
00512         if ( $useComments )
00513         {
00514             $templateFilename = $resourceData['template-filename'];
00515             if ( file_exists( $templateFilename ) )
00516             {
00517                 $fd = fopen( $templateFilename, 'rb' );
00518                 if ( $fd )
00519                 {
00520                     $templateText = fread( $fd, filesize( $templateFilename ) );
00521                     $php->addComment( "Original code:\n" . $templateText );
00522                     fclose( $fd );
00523                 }
00524             }
00525         }
00526         $php->addVariable( 'eZTemplateCompilerCodeDate', eZTemplateCompiler::CODE_DATE );
00527         $php->addCodePiece( "if ( !defined( 'EZ_TEMPLATE_COMPILER_COMMON_CODE' ) )\n" );
00528         $php->addInclude( eZTemplateCompiler::compilationDirectory() . '/common.php', eZPHPCreator::INCLUDE_ONCE_STATEMENT, array( 'spacing' => 4 ) );
00529         $php->addSpace();
00530 
00531         if ( eZTemplateCompiler::isAccumulatorsEnabled() )
00532         {
00533             $php->addCodePiece( "eZDebug::accumulatorStart( 'template_compiled_execution', 'template_total', 'Template compiled execution', true );\n" );
00534         }
00535         if ( eZTemplateCompiler::isTimingPointsEnabled() )
00536         {
00537             $php->addCodePiece( "eZDebug::addTimingPoint( 'Script start $cacheFileName' );\n" );
00538         }
00539 
00540 //         $php->addCodePiece( "if ( !isset( \$vars ) )\n    \$vars =& \$tpl->Variables;\n" );
00541 //         $php->addSpace();
00542 
00543         $parameters = array();
00544         $textName = eZTemplateCompiler::currentTextName( $parameters );
00545 
00546 //         $php->addCodePiece( "if ( !isset( \$$textName ) )\n    \$$textName = '';\n" );
00547 //         $php->addSpace();
00548 
00549         $transformedTree = array();
00550         eZTemplateCompiler::processNodeTransformation( $useComments, $php, $tpl, $rootNode, $resourceData, $transformedTree );
00551 
00552         if ( $ini->variable( 'TemplateSettings', 'TemplateOptimization' ) == 'enabled' )
00553         {
00554             /* Retrieve class information for the attribute lookup table */
00555             if ( isset( $resourceData['handler']->Keys ) and isset( $resourceData['handler']->Keys['class'] ) ) {
00556                 $resourceData['class-info'] = eZTemplateOptimizer::fetchClassDeclaration( $resourceData['handler']->Keys['class'] );
00557             }
00558             /* Run the optimizations */
00559             eZTemplateOptimizer::optimize( $useComments, $php, $tpl, $transformedTree, $resourceData );
00560         }
00561 
00562         $staticTree = array();
00563         eZTemplateCompiler::processStaticOptimizations( $useComments, $php, $tpl, $transformedTree, $resourceData, $staticTree );
00564 
00565         $combinedTree = array();
00566         eZTemplateCompiler::processNodeCombining( $useComments, $php, $tpl, $staticTree, $resourceData, $combinedTree );
00567 
00568         $finalTree = $combinedTree;
00569         if ( !eZTemplateCompiler::isNodePlacementEnabled() )
00570             eZTemplateCompiler::processRemoveNodePlacement( $finalTree );
00571 
00572         eZTemplateCompiler::generatePHPCode( $useComments, $php, $tpl, $finalTree, $resourceData );
00573 
00574         if ( eZTemplateCompiler::isTreeEnabled( 'final' ) )
00575             $php->addVariable( 'finalTree', $finalTree, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
00576         if ( eZTemplateCompiler::isTreeEnabled( 'combined' ) )
00577             $php->addVariable( 'combinedTree', $combinedTree, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
00578         if ( eZTemplateCompiler::isTreeEnabled( 'static' ) )
00579             $php->addVariable( 'staticTree', $staticTree, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
00580         if ( eZTemplateCompiler::isTreeEnabled( 'transformed' ) )
00581             $php->addVariable( 'transformedTree', $transformedTree, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
00582         if ( eZTemplateCompiler::isTreeEnabled( 'original' ) )
00583             $php->addVariable( 'originalTree', $rootNode, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
00584 
00585         if ( eZTemplateCompiler::isTimingPointsEnabled() )
00586             $php->addCodePiece( "eZDebug::addTimingPoint( 'Script end $cacheFileName' );\n" );
00587         if ( eZTemplateCompiler::isAccumulatorsEnabled() )
00588             $php->addCodePiece( "eZDebug::accumulatorStop( 'template_compiled_execution', true );\n" );
00589 
00590         if ( $resourceData['locales'] && count( $resourceData['locales'] ) )
00591         {
00592             $php->addCodePiece(
00593                 'setlocale( LC_CTYPE, $oldLocale_'. $resourceData['uniqid']. ' );'. "\n"
00594             );
00595         }
00596         $php->addCodePiece('$setArray = $oldSetArray_'. $resourceData['uniqid']. ";\n");
00597 
00598 // Code to decrement include level of the templates
00599         $php->addCodePiece("\$tpl->Level--;\n" );
00600 
00601         /*
00602         // dump names of all defined PHP variables
00603         $php->addCodePiece( "echo \"defined vars in $resourceData[uri]:<br/><pre>\\n\";\n" );
00604         $php->addCodePiece( 'foreach ( array_keys( get_defined_vars() ) as $var_name  ) echo "- $var_name\n";' );
00605         // dump tpl vars
00606         $php->addCodePiece( 'echo "\n-----------------------------------------------------------\nvars: ";' );
00607         $php->addCodePiece( 'var_dump( $vars );' );
00608         $php->addCodePiece( 'echo "</pre><hr/>\n";' );
00609         */
00610 
00611         if ( !$resourceData['test-compile'] )
00612         {
00613             $php->store( true );
00614         }
00615 
00616         return true;
00617     }
00618 
00619     /*!
00620      Iterates over the template node tree and tries to combine multiple static siblings
00621      into one element. The original tree is specified in \a $node and the new
00622      combined tree will be present in \a $newNode.
00623      \sa processNodeCombiningChildren
00624     */
00625     static function processNodeCombining( $useComments, $php, $tpl, &$node, &$resourceData, &$newNode )
00626     {
00627         $nodeType = $node[0];
00628         if ( $nodeType == eZTemplate::NODE_ROOT )
00629         {
00630             $children = $node[1];
00631             $newNode[0] = $nodeType;
00632             $newNode[1] = false;
00633             if ( $children )
00634             {
00635                 eZTemplateCompiler::processNodeCombiningChildren( $useComments, $php, $tpl, $children, $resourceData, $newNode );
00636             }
00637         }
00638         else
00639             $tpl->error( 'processNodeCombining', "Unknown root type $nodeType, should be " . eZTemplate::NODE_ROOT );
00640     }
00641 
00642     /*!
00643      Does node combining on the children \a $nodeChildren.
00644      \sa processNodeCombining
00645     */
00646     static function processNodeCombiningChildren( $useComments, $php, $tpl, &$nodeChildren, &$resourceData, &$parentNode )
00647     {
00648         $newNodeChildren = array();
00649         $lastNode = false;
00650         foreach ( $nodeChildren as $node )
00651         {
00652             $newNode = false;
00653             if ( !isset( $node[0] ) )
00654                 continue;
00655             $nodeType = $node[0];
00656             if ( $nodeType == eZTemplate::NODE_ROOT )
00657             {
00658                 $children = $node[1];
00659                 $newNode = array( $nodeType,
00660                                   false );
00661                 if ( $children )
00662                 {
00663                     eZTemplateCompiler::processNodeCombiningChildren( $useComments, $php, $tpl, $children, $resourceData, $newNode );
00664                 }
00665             }
00666             else if ( $nodeType == eZTemplate::NODE_TEXT )
00667             {
00668                 $text = $node[2];
00669                 $placement = $node[3];
00670 
00671                 $newNode = array( $nodeType,
00672                                   false,
00673                                   $text,
00674                                   $placement );
00675                 eZTemplateCompiler::combineStaticNodes( $tpl, $resourceData, $lastNode, $newNode );
00676             }
00677             else if ( $nodeType == eZTemplate::NODE_VARIABLE )
00678             {
00679                 $variableCustom = $node[1];
00680                 $variableData = $node[2];
00681                 $variablePlacement = $node[3];
00682                 $variableParameters = false;
00683                 $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
00684                                                                            $variableData, $variablePlacement,
00685                                                                            $resourceData );
00686                 $newNode = $node;
00687                 $newNode[1] = $variableCustom;
00688                 unset( $dataInspection );
00689                 eZTemplateCompiler::combineStaticNodes( $tpl, $resourceData, $lastNode, $newNode );
00690             }
00691             else if ( $nodeType == eZTemplate::NODE_FUNCTION )
00692             {
00693                 $functionChildren = $node[1];
00694                 $functionName = $node[2];
00695                 $functionParameters = $node[3];
00696                 $functionPlacement = $node[4];
00697 
00698                 $newNode = array( $nodeType,
00699                                   false,
00700                                   $functionName,
00701                                   $functionParameters,
00702                                   $functionPlacement );
00703                 if ( isset( $node[5] ) )
00704                     $newNode[5] = $node[5];
00705 
00706                 if ( is_array( $functionChildren ) )
00707                 {
00708                     eZTemplateCompiler::processNodeCombiningChildren( $useComments, $php, $tpl,
00709                                                                           $functionChildren, $resourceData, $newNode );
00710                 }
00711 
00712             }
00713             else
00714                 $newNode = $node;
00715             if ( $lastNode != false )
00716             {
00717                 $newNodeChildren[] = $lastNode;
00718                 $lastNode = false;
00719             }
00720             if ( $newNode != false )
00721                 $lastNode = $newNode;
00722         }
00723         if ( $lastNode != false )
00724         {
00725             $newNodeChildren[] = $lastNode;
00726             $lastNode = false;
00727         }
00728         $parentNode[1] = $newNodeChildren;
00729     }
00730 
00731     /*!
00732      Tries to combine the node \a $lastNode and the node \a $newNode
00733      into one new text node. If possible the new node is created in \a $newNode
00734      and \a $lastNode will be set to \c false.
00735      Combining nodes only works for text nodes and variable nodes without
00736      variable lookup, attributes and operators.
00737     */
00738     static function combineStaticNodes( $tpl, &$resourceData, &$lastNode, &$newNode )
00739     {
00740         if ( $lastNode == false or
00741              $newNode == false )
00742             return false;
00743         $lastNodeType = $lastNode[0];
00744         $newNodeType = $newNode[0];
00745         if ( !in_array( $lastNodeType, array( eZTemplate::NODE_TEXT,
00746                                               eZTemplate::NODE_VARIABLE ) ) or
00747              !in_array( $newNodeType, array( eZTemplate::NODE_TEXT,
00748                                              eZTemplate::NODE_VARIABLE ) ) )
00749             return false;
00750         if ( $lastNodeType == eZTemplate::NODE_VARIABLE )
00751         {
00752             if ( is_array( $lastNode[1] ) )
00753                 return false;
00754             $lastDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
00755                                                                            $lastNode[2], $lastNode[3],
00756                                                                            $resourceData );
00757             if ( !$lastDataInspection['is-constant'] or
00758                  $lastDataInspection['is-variable'] or
00759                  $lastDataInspection['has-attributes'] or
00760                  $lastDataInspection['has-operators'] )
00761                 return false;
00762             if ( isset( $lastNode[4] ) and
00763                  isset( $lastNode[4]['text-result'] ) and
00764                  !$lastNode[4]['text-result'] )
00765                 return false;
00766         }
00767         if ( $newNodeType == eZTemplate::NODE_VARIABLE )
00768         {
00769             if ( is_array( $newNode[1] ) )
00770                 return false;
00771             $newDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
00772                                                                           $newNode[2], $newNode[3],
00773                                                                           $resourceData );
00774             if ( !$newDataInspection['is-constant'] or
00775                  $newDataInspection['is-variable'] or
00776                  $newDataInspection['has-attributes'] or
00777                  $newDataInspection['has-operators'] )
00778                 return false;
00779             if ( isset( $newNode[4] ) and
00780                  isset( $newNode[4]['text-result'] ) and
00781                  !$newNode[4]['text-result'] )
00782                 return false;
00783             if ( isset( $newNode[1] ) and
00784                  $newNode[1] !== false )
00785                 return false;
00786         }
00787         $textElements = array();
00788         $lastNodeData = eZTemplateCompiler::staticNodeData( $lastNode );
00789         $newNodeData = eZTemplateCompiler::staticNodeData( $newNode );
00790         $tpl->appendElementText( $textElements, $lastNodeData, false, false );
00791         $tpl->appendElementText( $textElements, $newNodeData, false, false );
00792         $newData = implode( '', $textElements );
00793         $newPlacement = $lastNode[3];
00794         if ( !is_array( $newPlacement ) )
00795         {
00796             $newPlacement = $newNode[3];
00797         }
00798         else
00799         {
00800             $newPlacement[1][0] = $newNode[3][1][0]; // Line end
00801             $newPlacement[1][1] = $newNode[3][1][1]; // Column end
00802             $newPlacement[1][2] = $newNode[3][1][2]; // Position end
00803         }
00804         $lastNode = false;
00805         $newNode = array( eZTemplate::NODE_TEXT,
00806                           false,
00807                           $newData,
00808                           $newPlacement );
00809     }
00810 
00811     /*!
00812      \return the static data for the node \a $node or \c false if
00813              no data could be fetched.
00814              Will only return data from text nodes and variables nodes
00815              without variable lookup, attribute lookup or operators.
00816     */
00817     static function staticNodeData( $node )
00818     {
00819         $nodeType = $node[0];
00820         if ( $nodeType == eZTemplate::NODE_TEXT )
00821         {
00822             return $node[2];
00823         }
00824         else if ( $nodeType == eZTemplate::NODE_VARIABLE )
00825         {
00826             $data = $node[2];
00827             if ( is_array( $data ) and
00828                  count( $data ) > 0 )
00829             {
00830                 $dataType = $data[0][0];
00831                 if ( $dataType == eZTemplate::TYPE_STRING or
00832                      $dataType == eZTemplate::TYPE_NUMERIC or
00833                      $dataType == eZTemplate::TYPE_IDENTIFIER or
00834                      $dataType == eZTemplate::TYPE_ARRAY or
00835                      $dataType == eZTemplate::TYPE_BOOLEAN )
00836                 {
00837                     return $data[0][1];
00838                 }
00839             }
00840         }
00841         return null;
00842     }
00843 
00844     /*!
00845      Iterates over the items in the tree \a $node and tries to extract static data
00846      from operators which supports it.
00847     */
00848     static function processStaticOptimizations( $useComments, $php, $tpl, &$node, &$resourceData, &$newNode )
00849     {
00850         $nodeType = $node[0];
00851         if ( $nodeType == eZTemplate::NODE_ROOT )
00852         {
00853             $children = $node[1];
00854             $newNode[0] = $nodeType;
00855             $newNode[1] = false;
00856             if ( $children )
00857             {
00858                 $newNode[1] = array();
00859                 foreach ( $children as $child )
00860                 {
00861                     $newChild = array();
00862                     eZTemplateCompiler::processStaticOptimizations( $useComments, $php, $tpl, $child, $resourceData, $newChild );
00863                     $newNode[1][] = $newChild;
00864                 }
00865             }
00866         }
00867         else if ( $nodeType == eZTemplate::NODE_TEXT )
00868         {
00869             $text = $node[2];
00870             $placement = $node[3];
00871 
00872             $newNode[0] = $nodeType;
00873             $newNode[1] = false;
00874             $newNode[2] = $text;
00875             $newNode[3] = $placement;
00876         }
00877         else if ( $nodeType == eZTemplate::NODE_VARIABLE )
00878         {
00879             $variableCustom = $node[1];
00880             $variableData = $node[2];
00881             $variablePlacement = $node[3];
00882             $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
00883                                                                        $variableData, $variablePlacement,
00884                                                                        $resourceData );
00885             if ( isset( $dataInspection['new-data'] ) )
00886             {
00887                 $variableData = $dataInspection['new-data'];
00888             }
00889             $newNode = $node;
00890             $newNode[1] = $variableCustom;
00891             $newNode[2] = $variableData;
00892             unset( $dataInspection );
00893         }
00894         else if ( $nodeType == eZTemplate::NODE_FUNCTION )
00895         {
00896             $functionChildren = $node[1];
00897             $functionName = $node[2];
00898             $functionParameters = $node[3];
00899             $functionPlacement = $node[4];
00900 
00901             $newFunctionChildren = array();
00902             if ( is_array( $functionChildren ) )
00903             {
00904                 foreach ( $functionChildren as $functionChild )
00905                 {
00906                     $newChild = array();
00907                     eZTemplateCompiler::processStaticOptimizations( $useComments, $php, $tpl,
00908                                                                         $functionChild, $resourceData, $newChild );
00909                     $newFunctionChildren[] = $newChild;
00910                 }
00911                 $functionChildren = $newFunctionChildren;
00912             }
00913 
00914             $newFunctionParameters = array();
00915             if ( $functionParameters )
00916             {
00917                 foreach ( $functionParameters as $functionParameterName => $functionParameterData )
00918                 {
00919                     $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
00920                                                                                    $functionParameterData, false,
00921                                                                                    $resourceData );
00922                     if ( isset( $dataInspection['new-data'] ) )
00923                     {
00924                         $functionParameterData = $dataInspection['new-data'];
00925                     }
00926                     $newFunctionParameters[$functionParameterName] = $functionParameterData;
00927                 }
00928                 $functionParameters = $newFunctionParameters;
00929             }
00930 
00931             $newNode[0] = $nodeType;
00932             $newNode[1] = $functionChildren;
00933             $newNode[2] = $functionName;
00934             $newNode[3] = $functionParameters;
00935             $newNode[4] = $functionPlacement;
00936             if ( isset( $node[5] ) )
00937                 $newNode[5] = $node[5];
00938         }
00939         else
00940             $newNode = $node;
00941     }
00942 
00943     /*!
00944      Iterates over the template node tree \a $node and returns a new transformed
00945      tree in \a $newNode.
00946      \sa processNodeTransformationRoot, processNodeTransformationChild
00947     */
00948     static function processNodeTransformation( $useComments, $php, $tpl, &$node, &$resourceData, &$newNode )
00949     {
00950         $newNode = eZTemplateCompiler::processNodeTransformationRoot( $useComments, $php, $tpl, $node, $resourceData );
00951     }
00952 
00953     /*!
00954      Iterates over the nodes \a $nodes and does transformation on them.
00955      \sa processNodeTransformationChildren
00956      \note This method can be called from operator and functions as long as they have the \a $privateData parameter.
00957     */
00958     static function processNodeTransformationNodes( $tpl, &$node, &$nodes, &$privateData )
00959     {
00960         $useComments = $privateData['use-comments'];
00961         $php =& $privateData['php-creator'];
00962         $resourceData =& $privateData['resource-data'];
00963         return eZTemplateCompiler::processNodeTransformationChildren( $useComments, $php, $tpl, $node, $nodes, $resourceData );
00964     }
00965 
00966     /*!
00967      Iterates over the children \a $children and does transformation on them.
00968      \sa processNodeTransformation, processNodeTransformationChild
00969     */
00970     static function processNodeTransformationChildren( $useComments, $php, $tpl, &$node, &$children, &$resourceData )
00971     {
00972         if ( $children )
00973         {
00974             $newChildren = array();
00975             foreach ( $children as $childNode )
00976             {
00977                 $newChildNode = eZTemplateCompiler::processNodeTransformationChild( $useComments, $php, $tpl, $childNode, $resourceData );
00978                 if ( !$newChildNode )
00979                     $newChildren[] = $childNode;
00980                 else
00981                     $newChildren = array_merge( $newChildren, $newChildNode );
00982             }
00983             if ( count( $newChildren ) > 0 )
00984                 return $newChildren;
00985         }
00986         return $children;
00987     }
00988 
00989     /*!
00990      Iterates over the children of the root node \a $node and does transformation on them.
00991      \sa processNodeTransformation, processNodeTransformationChild
00992     */
00993     static function processNodeTransformationRoot( $useComments, $php, $tpl, &$node, &$resourceData )
00994     {
00995         $nodeType = $node[0];
00996         if ( $nodeType == eZTemplate::NODE_ROOT )
00997         {
00998             $children = $node[1];
00999             $newNode = array( $nodeType,
01000                               false );
01001             if ( $children )
01002             {
01003                 $newChildren = array();
01004                 foreach ( $children as $childNode )
01005                 {
01006                     $newChildNode = eZTemplateCompiler::processNodeTransformationChild( $useComments, $php, $tpl, $childNode, $resourceData );
01007                     if ( !$newChildNode )
01008                         $newChildren[] = $childNode;
01009                     else
01010                         $newChildren = array_merge( $newChildren, $newChildNode );
01011                 }
01012                 if ( count( $newChildren ) > 0 )
01013                     $newNode[1] = $newChildren;
01014             }
01015             return $newNode;
01016         }
01017         else
01018             $tpl->error( 'processNodeTransformation', "Unknown root type $nodeType, should be " . eZTemplate::NODE_ROOT );
01019         return false;
01020     }
01021 
01022     /*!
01023      Iterates over the children of the function node \a $node and transforms the tree.
01024      If the node is not a function it will return \c false.
01025      \sa processNodeTransformationRoot, processNodeTransformationChild
01026     */
01027     static function processNodeTransformationChild( $useComments, $php, $tpl, &$node, &$resourceData )
01028     {
01029         $nodeType = $node[0];
01030         if ( $nodeType == eZTemplate::NODE_FUNCTION )
01031         {
01032             $nodeCopy = $node;
01033             $functionChildren = $node[1];
01034             $functionName = $node[2];
01035             $functionParameters = $node[3];
01036             $functionPlacement = $node[4];
01037             if ( !isset( $tpl->Functions[$functionName] ) )
01038                 return false;
01039 
01040             if ( is_array( $tpl->Functions[$functionName] ) )
01041             {
01042                 $tpl->loadAndRegisterFunctions( $tpl->Functions[$functionName] );
01043             }
01044             $functionObject =& $tpl->Functions[$functionName];
01045             if ( is_object( $functionObject ) )
01046             {
01047                 $hasTransformationSupport = false;
01048                 $transformChildren = true;
01049                 $transformParameters = false;
01050                 if ( method_exists( $functionObject, 'functionTemplateHints' ) )
01051                 {
01052                     $hints = $functionObject->functionTemplateHints();
01053                     if ( isset( $hints[$functionName] ) and
01054                          isset( $hints[$functionName]['tree-transformation'] ) and
01055                          $hints[$functionName]['tree-transformation'] )
01056                         $hasTransformationSupport = true;
01057                     if ( isset( $hints[$functionName] ) and
01058                          isset( $hints[$functionName]['transform-children'] ) )
01059                         $transformChildren = $hints[$functionName]['transform-children'];
01060                     if ( isset( $hints[$functionName] ) and
01061                          isset( $hints[$functionName]['transform-parameters'] ) )
01062                         $transformParameters = $hints[$functionName]['transform-parameters'];
01063                 }
01064                 if ( $hasTransformationSupport and
01065                      method_exists( $functionObject, 'templateNodeTransformation' ) )
01066                 {
01067                     if ( $transformChildren and
01068                          $functionChildren )
01069                     {
01070                         $newChildren = array();
01071                         foreach ( $functionChildren as $childNode )
01072                         {
01073                             $newChildNode = eZTemplateCompiler::processNodeTransformationChild( $useComments, $php, $tpl, $childNode, $resourceData );
01074                             if ( !$newChildNode )
01075                                 $newChildren[] = $childNode;
01076                             else if ( !is_array( $newChildNode ) )
01077                                 $newChildren[] = $newChildNode;
01078                             else
01079                                 $newChildren = array_merge( $newChildren, $newChildNode );
01080                         }
01081                         if ( count( $newChildren ) > 0 )
01082                             $node[1] = $newChildren;
01083                     }
01084 
01085                     if ( $transformParameters and
01086                          $functionParameters )
01087                     {
01088                         $newParameters = array();
01089                         foreach ( $functionParameters as $parameterName => $parameterElementList )
01090                         {
01091                             $elementTree = $parameterElementList;
01092                             $elementList = $elementTree;
01093                             $newParamNode = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
01094                                                                                                    $elementTree, $elementList, $resourceData );
01095                             if ( !$newParamNode || !is_array( $newParamNode ) )
01096                                 $newParameters[$parameterName] = $parameterElementList;
01097                             else
01098                                 $newParameters[$parameterName] = $newParamNode;
01099                         }
01100                         if ( count( $newParameters ) > 0 )
01101                         {
01102                             $node[3] = $newParameters;
01103                             $functionParameters = $newParameters;
01104                         }
01105                     }
01106 
01107                     $privateData = array( 'use-comments' => $useComments,
01108                                           'php-creator' => $php,
01109                                           'resource-data' => &$resourceData );
01110                     $newNodes = $functionObject->templateNodeTransformation( $functionName, $node,
01111                                                                              $tpl, $functionParameters, $privateData );
01112                     unset( $privateData );
01113                     if ( !$newNodes )
01114                     {
01115                         $node = $nodeCopy;
01116                         $node[1] = $functionChildren;
01117                         return false;
01118                         return $node;
01119                     }
01120                     return $newNodes;
01121                 }
01122             }
01123             else if ( $resourceData['test-compile'] )
01124             {
01125                 $tpl->warning( '', "Function '$functionName' is not registered.", $functionPlacement );
01126             }
01127 
01128             return false;
01129         }
01130         else if ( $nodeType == eZTemplate::NODE_VARIABLE )
01131         {
01132             $elementTree = $node[2];
01133             $elementList = $elementTree;
01134 
01135             $newParameterElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
01136                                                                                            $elementTree, $elementList, $resourceData );
01137             if ( $newParameterElements )
01138             {
01139                 $newNode = $node;
01140                 $newNode[2] = $newParameterElements;
01141                 $newNodes = array( $newNode );
01142                 return $newNodes;
01143             }
01144         }
01145         else if ( $nodeType == eZTemplate::NODE_ROOT )
01146         {
01147             return eZTemplateCompiler::processNodeTransformationRoot( $useComments, $php, $tpl, $node, $resourceData );
01148         }
01149         else
01150             return false;
01151     }
01152 
01153     /*!
01154      Iterates over the element list \a $elements and transforms them.
01155      \sa processElementTransformationChild
01156     */
01157     static function processElementTransformationList( $tpl, &$node, $elements, &$privateData )
01158     {
01159         $useComments = $privateData['use-comments'];
01160         $php =& $privateData['php-creator'];
01161         $resourceData =& $privateData['resource-data'];
01162         $elementTree = $elements;
01163         $newElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
01164                                                                               $elementTree, $elements, $resourceData );
01165         if ( $newElements )
01166             return $newElements;
01167         return $elements;
01168     }
01169 
01170     /*!
01171      Iterates over the children of the function node \a $node and transforms the tree.
01172      If the node is not a function it will return \c false.
01173      \sa processNodeTransformationRoot, processNodeTransformationChild
01174     */
01175     static function processElementTransformationChild( $useComments, $php, $tpl, &$node,
01176                                                 $elementTree, $elementList, &$resourceData )
01177     {
01178         $count = count( $elementList );
01179         $lastElement = null;
01180         $newElementList = array();
01181         for ( $i = 0; $i < $count; ++$i )
01182         {
01183             $element =& $elementList[$i];
01184             $elementType = $element[0];
01185             if ( $elementType == eZTemplate::TYPE_OPERATOR )
01186             {
01187                 $operatorName = $element[1][0];
01188                 $operatorParameters = array_slice( $element[1], 1 );
01189                 if ( !isset( $tpl->Operators[$operatorName] ) )
01190                     return false;
01191 
01192                 if ( is_array( $tpl->Operators[$operatorName] ) )
01193                 {
01194                     $tpl->loadAndRegisterOperators( $tpl->Operators[$operatorName] );
01195                 }
01196                 $operatorObject =& $tpl->Operators[$operatorName];
01197                 if ( is_object( $operatorObject ) )
01198                 {
01199                     $hasTransformationSupport = false;
01200                     $transformParameters = false;
01201                     $inputAsParameter = false;
01202                     $knownType = 'static';
01203                     if ( method_exists( $operatorObject, 'operatorTemplateHints' ) )
01204                     {
01205                         $hints = $operatorObject->operatorTemplateHints();
01206                         if ( isset( $hints[$operatorName] ) and
01207                              isset( $hints[$operatorName]['element-transformation'] ) and
01208                              $hints[$operatorName]['element-transformation'] )
01209                         {
01210                             $hasTransformationSupport = true;
01211                         }
01212 
01213                         if ( $hasTransformationSupport  and
01214                              isset( $hints[$operatorName]['element-transformation-func'] ) )
01215                         {
01216                             $transformationMethod = $hints[$operatorName]['element-transformation-func'];
01217                         }
01218                         else
01219                         {
01220                             $transformationMethod = 'templateElementTransformation';
01221                         }
01222 
01223                         if ( isset( $hints[$operatorName] ) and
01224                              isset( $hints[$operatorName]['transform-parameters'] ) )
01225                         {
01226                             $transformParameters = $hints[$operatorName]['transform-parameters'];
01227                         }
01228 
01229                         if ( isset( $hints[$operatorName] ) and
01230                              isset( $hints[$operatorName]['input-as-parameter'] ) )
01231                         {
01232                             $inputAsParameter = $hints[$operatorName]['input-as-parameter'];
01233                         }
01234 
01235                         if ( isset( $hints[$operatorName]['output'] ) and !$hints[$operatorName]['output'] )
01236                         {
01237                             $knownType = 'null';
01238                         }
01239                         else if ( isset( $hints[$operatorName]['output-type'] ) )
01240                         {
01241                             $knownType = $hints[$operatorName]['output-type'];
01242                         }
01243                     }
01244                     if ( $hasTransformationSupport and
01245                          method_exists( $operatorObject, $transformationMethod ) )
01246                     {
01247                         $resetNewElementList = false;
01248                         if ( $transformParameters )
01249                         {
01250                             $newParameters = array();
01251                             if ( $inputAsParameter )
01252                             {
01253                                 $newParameterElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
01254                                                                                                                $elementTree, $newElementList, $resourceData );
01255                                 if ( count( $newParameterElements ) > 0 or
01256                                      $inputAsParameter === 'always' )
01257                                 {
01258                                     $newParameters[] = $newParameterElements;
01259                                     $resetNewElementList = true;
01260                                 }
01261                             }
01262 
01263                             foreach ( $operatorParameters as $operatorParameter )
01264                             {
01265                                 $newParameterElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
01266                                                                                                                $elementTree, $operatorParameter, $resourceData );
01267                                 if ( !$newParameterElements )
01268                                     $newParameters[] = $operatorParameter;
01269                                 else
01270                                     $newParameters[] = $newParameterElements;
01271                             }
01272                             $operatorParameters = $newParameters;
01273                         }
01274 
01275                         $newElements = $operatorObject->$transformationMethod( $operatorName, $node, $tpl, $resourceData,
01276                                                                                $element, $lastElement, $elementList, $elementTree,
01277                                                                                $operatorParameters );
01278                         if ( is_array( $newElements ) )
01279                         {
01280                             if ( $resetNewElementList )
01281                             {
01282                                 $newElementList = $newElements;
01283                             }
01284                             else
01285                             {
01286                                 $newElementList = array_merge( $newElementList, $newElements );
01287                             }
01288                         }
01289                         else
01290                         {
01291                             $newElementList[] = $element;
01292                         }
01293                     }
01294                     else
01295                     {
01296                         $newElementList[] = $element;
01297                     }
01298                 }
01299                 else if ( $resourceData['test-compile'] )
01300                 {
01301                     $tpl->warning( '', "Operator '$operatorName' is not registered." );
01302                 }
01303             }
01304             else
01305             {
01306                 $newElementList[] = $element;
01307             }
01308             $lastElement = $element;
01309         }
01310         return $newElementList;
01311     }
01312 
01313     /*!
01314      Iterates over the node tree and removes all placement information.
01315     */
01316     static function processRemoveNodePlacement( &$node )
01317     {
01318         $nodeType = $node[0];
01319         if ( $nodeType == eZTemplate::NODE_ROOT )
01320         {
01321             $nodeChildren =& $node[1];
01322             for ( $i = 0; $i < count( $nodeChildren ); ++$i )
01323             {
01324                 $nodeChild =& $nodeChildren[$i];
01325                 eZTemplateCompiler::processRemoveNodePlacement( $nodeChild );
01326             }
01327         }
01328         else if ( $nodeType == eZTemplate::NODE_TEXT )
01329         {
01330             $node[3] = false;
01331         }
01332         else if ( $nodeType == eZTemplate::NODE_VARIABLE )
01333         {
01334             $node[3] = false;
01335         }
01336         else if ( $nodeType == eZTemplate::NODE_FUNCTION )
01337         {
01338             $node[4] = false;
01339             $nodeChildren =& $node[1];
01340             if ( $nodeChildren )
01341             {
01342                 for ( $i = 0; $i < count( $nodeChildren ); ++$i )
01343                 {
01344                     $nodeChild =& $nodeChildren[$i];
01345                     eZTemplateCompiler::processRemoveNodePlacement( $nodeChild );
01346                 }
01347             }
01348         }
01349         else if ( $nodeType == eZTemplate::NODE_OPERATOR )
01350         {
01351         }
01352     }
01353 
01354     /*!
01355      Looks over the variable data \a $variableData and returns an array with
01356      information on the structure.
01357      The following entries are generated.
01358      - is-constant - true if the variable data contains constant data like text and numerics
01359      - is-variable - true if the variable data is a variable lookup
01360      - has-operators - true if operators are present
01361      - has-attributes - true if attributes are used
01362     */
01363     static function inspectVariableData( $tpl, $variableData, $variablePlacement, &$resourceData )
01364     {
01365         $dataInspection = array( 'is-constant' => false,
01366                                  'is-variable' => false,
01367                                  'has-operators' => false,
01368                                  'has-attributes' => false );
01369         if ( !is_array( $variableData ) )
01370             return $dataInspection;
01371         $newVariableData = array();
01372         // Static optimizations, the following items are done:
01373         // - Recognize static data
01374         // - Extract static data, if possible, from operators
01375         // - Remove parameters and input which not be used.
01376         foreach ( $variableData as $variableItem )
01377         {
01378             $variableItemType = $variableItem[0];
01379             $variableItemData = $variableItem[1];
01380             $variableItemPlacement = $variableItem[2];
01381             if ( $variableItemType == eZTemplate::TYPE_STRING or
01382                  $variableItemType == eZTemplate::TYPE_IDENTIFIER )
01383             {
01384                 $dataInspection['is-constant'] = true;
01385                 $dataInspection['is-variable'] = false;
01386                 $newVariableData[] = $variableItem;
01387             }
01388             else if ( $variableItemType == eZTemplate::TYPE_NUMERIC )
01389             {
01390                 $dataInspection['is-constant'] = true;
01391                 $dataInspection['is-variable'] = false;
01392                 $newVariableData[] = $variableItem;
01393             }
01394             else if ( $variableItemType == eZTemplate::TYPE_BOOLEAN )
01395             {
01396                 $dataInspection['is-constant'] = true;
01397                 $dataInspection['is-variable'] = false;
01398                 $newVariableData[] = $variableItem;
01399             }
01400             else if ( $variableItemType == eZTemplate::TYPE_DYNAMIC_ARRAY )
01401             {
01402                 $dataInspection['is-constant'] = false;
01403                 $dataInspection['is-variable'] = true;
01404                 $newVariableData[] = $variableItem;
01405             }
01406             else if ( $variableItemType == eZTemplate::TYPE_ARRAY )
01407             {
01408                 $dataInspection['is-constant'] = true;
01409                 $dataInspection['is-variable'] = false;
01410                 $newVariableData[] = $variableItem;
01411             }
01412             else if ( $variableItemType == eZTemplate::TYPE_VARIABLE )
01413             {
01414                 $dataInspection['is-constant'] = false;
01415                 $dataInspection['is-variable'] = true;
01416                 $newVariableData[] = $variableItem;
01417             }
01418             else if ( $variableItemType == eZTemplate::TYPE_ATTRIBUTE )
01419             {
01420                 $dataInspection['has-attributes'] = true;
01421                 $newDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
01422                                                                                   $variableItemData, $variableItemPlacement,
01423                                                                                   $resourceData );
01424                 if ( isset( $newDataInspection['new-data'] ) )
01425                 {
01426                     $variableItemData = $newDataInspection['new-data'];
01427                 }
01428                 $variableItem[1] = $variableItemData;
01429                 unset( $newDataInspection );
01430                 $newVariableData[] = $variableItem;
01431             }
01432             else if ( $variableItemType == eZTemplate::TYPE_OPERATOR )
01433             {
01434                 $dataInspection['has-operators'] = true;
01435                 $operatorName = $variableItemData[0];
01436                 $operatorHint = eZTemplateCompiler::operatorHint( $tpl, $operatorName );
01437                 $newVariableItem = $variableItem;
01438                 if ( $operatorHint and
01439                      isset( $operatorHint['input'] ) and
01440                      isset( $operatorHint['output'] ) and
01441                      isset( $operatorHint['parameters'] ) )
01442                 {
01443                     if ( !$operatorHint['input'] and
01444                          $operatorHint['output'] )
01445                         $newVariableData = array();
01446                     if ( !isset( $operatorHint) or !$operatorHint['parameters'] )
01447                         $newVariableItem[1] = array( $operatorName );
01448                     if ( isset ( $operatorHint['static'] ) and
01449                          $operatorHint['static'] )
01450                     {
01451                         $operatorStaticData = eZTemplateCompiler::operatorStaticData( $tpl, $operatorName );
01452                         $newVariableItem = eZTemplateCompiler::createStaticVariableData( $tpl, $operatorStaticData, $variableItemPlacement );
01453                         $dataInspection['is-constant'] = true;
01454                         $dataInspection['is-variable'] = false;
01455                         $dataInspection['has-operators'] = false;
01456                     }
01457                 }
01458                 if ( $newVariableItem[0] == eZTemplate::TYPE_OPERATOR )
01459                 {
01460                     $tmpVariableItem = $newVariableItem[1];
01461                     $newVariableItem[1] = array( $operatorName );
01462                     for ( $i = 1; $i < count( $tmpVariableItem ); ++$i )
01463                     {
01464                         $operatorParameter = $tmpVariableItem[$i];
01465                         $newDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
01466                                                                                           $operatorParameter, false,
01467                                                                                           $resourceData );
01468                         if ( isset( $newDataInspection['new-data'] ) )
01469                         {
01470                             $operatorParameter = $newDataInspection['new-data'];
01471                         }
01472                         $newVariableItem[1][] = $operatorParameter;
01473                     }
01474                 }
01475                 $newVariableData[] = $newVariableItem;
01476             }
01477             else if ( $variableItemType == eZTemplate::TYPE_VOID )
01478             {
01479                 $tpl->warning( 'TemplateCompiler', "Void datatype should not be used, ignoring it" );
01480             }
01481             else if ( $variableItemType > eZTemplate::TYPE_INTERNAL and
01482                       $variableItemType < eZTemplate::TYPE_INTERNAL_STOP )
01483             {
01484                 $newVariableData[] = $variableItem;
01485             }
01486             else
01487             {
01488                 $tpl->warning( 'TemplateCompiler', "Unknown data type $variableItemType, ignoring it" );
01489             }
01490         }
01491         $dataInspection['new-data'] = $newVariableData;
01492         return $dataInspection;
01493     }
01494 
01495     /*!
01496      \return the operator hint for the operator \a $operatorName, or \c false if
01497              the operator does not exist or has no hints.
01498     */
01499     static function operatorHint( $tpl, $operatorName )
01500     {
01501         if ( isset( $tpl->Operators[$operatorName] ) and
01502              is_array( $tpl->Operators[$operatorName] ) )
01503         {
01504             $tpl->loadAndRegisterOperators( $tpl->Operators[$operatorName] );
01505         }
01506         $operatorObject =& $tpl->Operators[$operatorName];
01507         $operatorHint = false;
01508         if ( is_object( $operatorObject ) )
01509         {
01510             if ( method_exists( $operatorObject, 'operatorTemplateHints' ) )
01511             {
01512                 $operatorHintArray = $operatorObject->operatorTemplateHints();
01513                 if ( isset( $operatorHintArray[$operatorName] ) )
01514                 {
01515                     $operatorHint = $operatorHintArray[$operatorName];
01516                 }
01517             }
01518         }
01519         else if ( $tpl->testCompile() )
01520         {
01521             $tpl->warning( '', "Operator '$operatorName' is not registered." );
01522         }
01523 
01524         return $operatorHint;
01525     }
01526 
01527     /*!
01528      \return static data from operators which support returning static data,
01529              or \c null if no static data could be extracted.
01530              The operator is specified in \a $operatorName.
01531 
01532     */
01533     static function operatorStaticData( $tpl, $operatorName )
01534     {
01535         if ( is_array( $tpl->Operators[$operatorName] ) )
01536         {
01537             $tpl->loadAndRegisterOperators( $tpl->Operators[$operatorName] );
01538         }
01539         $operatorObject =& $tpl->Operators[$operatorName];
01540         $operatorData = null;
01541         if ( is_object( $operatorObject ) )
01542         {
01543             if ( method_exists( $operatorObject, 'operatorCompiledStaticData' ) )
01544             {
01545                 $operatorData = $operatorObject->operatorCompiledStaticData( $operatorName );
01546             }
01547         }
01548         else if ( $tpl->testCompile() )
01549         {
01550             $tpl->warning( '', "Operator '$operatorName' is not registered." );
01551         }
01552 
01553         return $operatorData;
01554     }
01555 
01556     /*!
01557      Creates a variable data element for the data \a $staticData and returns it.
01558      The type of element depends on the type of the data, strings and booleans
01559      are returned as eZTemplate::TYPE_STRING and eZTemplate::TYPE_NUMERIC while other
01560      types are turned into text and returned as eZTemplate::TYPE_STRING.
01561     */
01562     static function createStaticVariableData( $tpl, $staticData, $variableItemPlacement )
01563     {
01564         if ( is_string( $staticData ) )
01565             return array( eZTemplate::TYPE_STRING,
01566                           $staticData,
01567                           $variableItemPlacement );
01568         else if ( is_bool( $staticData ) )
01569             return array( eZTemplate::TYPE_BOOLEAN,
01570                           $staticData,
01571                           $variableItemPlacement );
01572         else if ( is_bool( $staticData ) or is_numeric( $staticData ) )
01573             return array( eZTemplate::TYPE_NUMERIC,
01574                           $staticData,
01575                           $variableItemPlacement );
01576         else if ( is_array( $staticData ) )
01577             return array( eZTemplate::TYPE_ARRAY,
01578                           $staticData,
01579                           $variableItemPlacement );
01580         else
01581             return array( eZTemplate::TYPE_STRING,
01582                           "$staticData",
01583                           $variableItemPlacement );
01584     }
01585 
01586     /*!
01587      Opens the template files specified in \a $placementData
01588      and fetches the text portion defined by the
01589      start and end position. The text is returned or \c null if the
01590      text could not be fetched.
01591     */
01592     static function fetchTemplatePiece( $placementData )
01593     {
01594         if ( !isset( $placementData[0] ) or
01595              !isset( $placementData[1] ) or
01596              !isset( $placementData[2] ) )
01597             return null;
01598         $file = $placementData[2];
01599         $startPosition = $placementData[0][2];
01600         $endPosition = $placementData[1][2];
01601         $length = $endPosition - $startPosition;
01602         if ( file_exists( $file ) )
01603         {
01604             if ( $length > 0 )
01605             {
01606                 $fd = fopen( $file, 'rb' );
01607                 fseek( $fd, $startPosition );
01608                 $text = fread( $fd, $length );
01609                 fclose( $fd );
01610                 return $text;
01611             }
01612             else
01613             {
01614                 return '';
01615             }
01616         }
01617         return null;
01618     }
01619 
01620     /*!
01621      Creates the common.php file which has common functions for compiled templates.
01622      If the file already exists if will not create it.
01623     */
01624     static function createCommonCompileTemplate()
01625     {
01626         $php = new eZPHPCreator( eZTemplateCompiler::compilationDirectory(), 'common.php' );
01627         if ( $php->exists() )
01628             return;
01629 
01630         $php->addComment( "This file contains functions which are common to all compiled templates.\n\n" .
01631                           'NOTE: This file is autogenerated and should not be modified, any changes will be lost!' );
01632         $php->addSpace();
01633         $php->addDefine( 'EZ_TEMPLATE_COMPILER_COMMON_CODE', true );
01634         $php->addSpace();
01635 
01636         $namespaceStack = array();
01637         $php->addCodePiece( "if ( !isset( \$namespaceStack ) )\n" );
01638         $php->addVariable( 'namespaceStack', $namespaceStack, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'spacing' => 4 ) );
01639         $php->addSpace();
01640 
01641         $lbracket = '{';
01642         $rbracket = '}';
01643         $initText = "if ( !function_exists( 'compiledfetchvariable' ) )
01644 $lbracket
01645     function compiledFetchVariable( \$vars, \$namespace, \$name )
01646     $lbracket
01647         \$exists = ( array_key_exists( \$namespace, \$vars ) and
01648                     array_key_exists( \$name, \$vars[\$namespace] ) );
01649         if ( \$exists )
01650         $lbracket
01651             return \$vars[\$namespace][\$name];
01652         $rbracket
01653         return null;
01654     $rbracket
01655 $rbracket
01656 if ( !function_exists( 'compiledfetchtext' ) )
01657 $lbracket
01658     function compiledFetchText( \$tpl, \$rootNamespace, \$currentNamespace, \$namespace, \$var )
01659     $lbracket
01660         \$text = '';
01661         \$tpl->appendElement( \$text, \$var, \$rootNamespace, \$currentNamespace );
01662         return \$text;
01663     $rbracket
01664 $rbracket
01665 if ( !function_exists( 'compiledAcquireResource' ) )
01666 $lbracket
01667     function compiledAcquireResource( \$phpScript, \$key, &\$originalText,
01668                                       \$tpl, \$rootNamespace, \$currentNamespace )
01669     {
01670         include( '" . eZTemplateCompiler::TemplatePrefix() . "' . \$phpScript );
01671         if ( isset( \$text ) )
01672         {
01673             \$originalText .= \$text;
01674             return true;
01675         }
01676         return false;
01677     }
01678 $rbracket
01679 if ( !function_exists( 'compiledfetchattribute' ) )
01680 $lbracket
01681     function compiledFetchAttribute( \$value, \$attributeValue )
01682     $lbracket
01683         if ( is_object( \$value ) )
01684         $lbracket
01685             if ( method_exists( \$value, \"attribute\" ) and
01686                  method_exists( \$value, \"hasAttribute\" ) )
01687             $lbracket
01688                 if ( \$value->hasAttribute( \$attributeValue ) )
01689                 $lbracket
01690                     return \$value->attribute( \$attributeValue );
01691                 $rbracket
01692             $rbracket
01693         $rbracket
01694         else if ( is_array( \$value ) )
01695         $lbracket
01696             if ( isset( \$value[\$attributeValue] ) )
01697             $lbracket
01698                 return \$value[\$attributeValue];
01699             $rbracket
01700         $rbracket
01701         return null;
01702     $rbracket
01703 $rbracket
01704 ";
01705         $php->addCodePiece( $initText );
01706         $php->store( true );
01707     }
01708 
01709     /*!
01710      Figures out the current text name to use in compiled template code and return it.
01711      The names will be text, text1, text2 etc.
01712     */
01713     static function currentTextName( $parameters )
01714     {
01715         $textData = array( 'variable' => 'text',
01716                            'counter' => 0 );
01717         if ( isset( $parameters['text-data'] ) )
01718             $textData = $parameters['text-data'];
01719         $name = $textData['variable'];
01720         if ( $textData['counter'] > 0 )
01721             $name .= $textData['counter'];
01722         return $name;
01723     }
01724 
01725     static function boundVariableName( $variableID, $parameters )
01726     {
01727         $bindMap =& $parameters['variable-bind']['map'][$variableID];
01728         if ( isset( $bindMap ) )
01729             $bindMap = array();
01730     }
01731 
01732     /*!
01733      Generates the PHP code defined in the template node tree \a $node.
01734      The code is generated using the php creator specified in \a $php.
01735     */
01736 
01737     static function generatePHPCode( $useComments, $php, $tpl, &$node, &$resourceData )
01738     {
01739         $parameters = array();
01740         $currentParameters = array( 'spacing' => 0 );
01741         $nodeType = $node[0];
01742         if ( $nodeType == eZTemplate::NODE_ROOT )
01743         {
01744             $children = $node[1];
01745             if ( $children )
01746             {
01747                 eZTemplateCompiler::generatePHPCodeChildren( $useComments, $php, $tpl, $children, $resourceData, $parameters, $currentParameters );
01748             }
01749         }
01750         else
01751             $tpl->error( 'generatePHPCode', "Unknown root type $nodeType, should be " . eZTemplate::NODE_ROOT );
01752         $php->addSpace();
01753     }
01754 
01755     /*!
01756      Generates the PHP code for all node children specified in \a $nodeChildren.
01757      \sa generatePHPCode
01758     */
01759     static function generatePHPCodeChildren( $useComments, $php, $tpl, &$nodeChildren, &$resourceData, &$parameters, $currentParameters )
01760     {
01761         foreach ( $nodeChildren as $node )
01762         {
01763             $newNode = false;
01764             $nodeType = $node[0];
01765             if ( $nodeType > eZTemplate::NODE_USER_CUSTOM )
01766             {
01767                 // Do custom nodes
01768             }
01769             else if ( $nodeType > eZTemplate::NODE_INTERNAL )
01770             {
01771                 // Do custom internal nodes
01772                 if ( $nodeType == eZTemplate::NODE_INTERNAL_CODE_PIECE )
01773                 {
01774                     $codePiece = $node[1];
01775                     $spacing = $currentParameters['spacing'];
01776                     if ( isset( $node[2]['spacing'] ) )
01777                         $spacing += $node[2]['spacing'];
01778                     $php->addCodePiece( $codePiece, array( 'spacing' => $spacing ) );
01779                 }
01780                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_WARNING )
01781                 {
01782                     $warningText = $php->thisVariableText( $node[1], 23, 0, false );
01783                     $warningLabel = false;
01784                     $warningLabelText = '';
01785                     if ( isset( $node[2] ) )
01786                         $warningLabelText = $php->thisVariableText( $node[2], 0, 0, false );
01787                     $spacing = $currentParameters['spacing'];
01788                     if ( isset( $node[3]['spacing'] ) )
01789                         $spacing += $node[3]['spacing'];
01790                     $placementText = 'false';
01791                     if ( isset( $node[4] ) )
01792                         $placementText = $php->thisVariableText( $node[4], 0, 0, false );
01793                     $php->addCodePiece( "\$tpl->warning( " . $warningLabelText . ", " . $warningText . ", " . $placementText . " );", array( 'spacing' => $spacing ) );
01794                 }
01795                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_ERROR )
01796                 {
01797                     $errorText = $php->thisVariableText( $node[1], 21, 0, false );
01798                     $errorLabel = false;
01799                     $errorLabelText = '';
01800                     if ( isset( $node[2] ) )
01801                         $errorLabelText = $php->thisVariableText( $node[2], 0, 0, false );
01802                     $spacing = $currentParameters['spacing'];
01803                     if ( isset( $node[3]['spacing'] ) )
01804                         $spacing += $node[3]['spacing'];
01805                     $placementText = 'false';
01806                     if ( isset( $node[4] ) )
01807                         $placementText = $php->thisVariableText( $node[4], 0, 0, false );
01808                     $php->addCodePiece( "\$tpl->error( " . $errorLabelText . ", " . $errorText . ", " . $placementText . " );", array( 'spacing' => $spacing ) );
01809                 }
01810                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_OUTPUT_READ )
01811                 {
01812                     $variableName = $node[1];
01813                     $spacing = $currentParameters['spacing'];
01814                     if ( isset( $node[2]['spacing'] ) )
01815                         $spacing += $node[2]['spacing'];
01816                     $textName = eZTemplateCompiler::currentTextName( $parameters );
01817                     $assignmentType = $node[3];
01818                     $assignmentText = $php->variableNameText( $variableName, $assignmentType, $node[2] );
01819                     $php->addCodePiece( "$assignmentText\$$textName;", array( 'spacing' => $spacing ) );
01820                 }
01821                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_OUTPUT_ASSIGN )
01822                 {
01823                     $variableName = $node[1];
01824                     $spacing = $currentParameters['spacing'];
01825                     if ( isset( $node[2]['spacing'] ) )
01826                         $spacing += $node[2]['spacing'];
01827                     $textName = eZTemplateCompiler::currentTextName( $parameters );
01828                     $assignmentType = $node[3];
01829                     $assignmentText = $php->variableNameText( $textName, $assignmentType, $node[2] );
01830                     $php->addCodePiece( "$assignmentText\$$variableName;", array( 'spacing' => $spacing ) );
01831                 }
01832                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_OUTPUT_INCREASE )
01833                 {
01834                     $spacing = $currentParameters['spacing'];
01835                     if ( isset( $node[1]['spacing'] ) )
01836                         $spacing += $node[1]['spacing'];
01837                     $textName = eZTemplateCompiler::currentTextName( $parameters );
01838                     $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$textStack ) )\n" .
01839                                         "    \$textStack = array();\n" .
01840                                         "\$textStack[] = \$$textName;\n" .
01841                                         "\$$textName = '';", array( 'spacing' => $spacing ) );
01842                 }
01843                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_OUTPUT_DECREASE )
01844                 {
01845                     $spacing = $currentParameters['spacing'];
01846                     if ( isset( $node[1]['spacing'] ) )
01847                         $spacing += $node[1]['spacing'];
01848                     $textName = eZTemplateCompiler::currentTextName( $parameters );
01849                     $php->addCodePiece( "\$$textName = array_pop( \$textStack );", array( 'spacing' => $spacing ) );
01850                 }
01851                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_OUTPUT_SPACING_INCREASE )
01852                 {
01853                     $spacing = $node[1];
01854                     $currentParameters['spacing'] += $spacing;
01855                     continue;
01856                 }
01857                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_SPACING_DECREASE )
01858                 {
01859                     $spacing = $node[1];
01860                     $currentParameters['spacing'] -= $spacing;
01861                     continue;
01862                 }
01863                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_VARIABLE_SET )
01864                 {
01865                     $variableName = $node[1];
01866                     $variableValue = $node[2];
01867                     $spacing = $currentParameters['spacing'];
01868                     if ( isset( $node[3]['spacing'] ) )
01869                         $spacing += $node[3]['spacing'];
01870                     $php->addVariable( $variableName, $variableValue, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'spacing' => $spacing ) );
01871                 }
01872                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_VARIABLE_UNSET )
01873                 {
01874                     $variableName = $node[1];
01875                     $spacing = $currentParameters['spacing'];
01876                     if ( isset( $node[2]['spacing'] ) )
01877                         $spacing += $node[2]['spacing'];
01878 
01879                     if ( is_array( $variableName ) )
01880                     {
01881                         $namespace = $variableName[0];
01882                         $namespaceScope = $variableName[1];
01883                         $variableName = $variableName[2];
01884                         $namespaceText = eZTemplateCompiler::generateMergeNamespaceCode( $php, $tpl, $namespace, $namespaceScope, array( 'spacing' => $spacing ), true );
01885                         if ( !is_string( $namespaceText ) )
01886                             $namespaceText = "\$namespace";
01887                         $variableNameText = $php->thisVariableText( $variableName, 0, 0, false );
01888                         if ( isset( $node[2]['remember_set'] ) and $node[2]['remember_set'] )
01889                         {
01890                             $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( isset( \$setArray[$namespaceText][$variableNameText] ) )\n".
01891                                                 "{\n" );
01892                             $spacing += 4;
01893                         }
01894                         if ( isset( $node[2]['local-variable'] ) )
01895                         {
01896                             $php->addCodePiece( "\$tpl->unsetLocalVariable( $variableNameText, $namespaceText );\n",
01897                                                 array( 'spacing' => $spacing ) );
01898                         }
01899                         else
01900                         {
01901                             $php->addCodePiece( "unset( \$vars[$namespaceText][$variableNameText] );",
01902                                                 array( 'spacing' => $spacing ) );
01903                         }
01904 
01905                         if ( isset( $node[2]['remember_set'] ) and $node[2]['remember_set'] )
01906                         {
01907                             $php->addCodePiece( "\n}\n" );
01908                             $spacing -= 4;
01909                         }
01910                     }
01911                     else
01912                     {
01913                         $php->addVariableUnset( $variableName, array( 'spacing' => $spacing ) );
01914                     }
01915                 }
01916                 else if ( ( $nodeType == eZTemplate::NODE_INTERNAL_RESOURCE_ACQUISITION ) ||
01917                           ( $nodeType == eZTemplate::NODE_OPTIMIZED_RESOURCE_ACQUISITION ) )
01918                 {
01919                     $resource = $node[1];
01920                     $resourceObject = $tpl->resourceHandler( $resource );
01921                     if ( !$resourceObject )
01922                         continue;
01923 
01924                     $spacing = $currentParameters['spacing'];
01925                     if ( isset( $node[7]['spacing'] ) )
01926                         $spacing += $node[7]['spacing'];
01927                     $newRootNamespace = $node[8];
01928                     $resourceVariableName = $node[9];
01929                     $resourceFilename = isset( $node[10] ) ? $node[10] : false;
01930 
01931                     /* We can only use fallback code if we know upfront which
01932                      * template is included; it does not work if we are using
01933                      * something from the ezobjectforwarder which makes the
01934                      * uriMap an array */
01935                     $useFallbackCode = true;
01936                     $uriMap = $node[2];
01937                     if ( is_string( $uriMap ) )
01938                     {
01939                         $uriMap = array( $uriMap );
01940                     }
01941                     else
01942                     {
01943                         $useFallbackCode = false;
01944                     }
01945 
01946                     $resourceMap = array();
01947                     $hasCompiledCode = false;
01948                     if ( is_array( $uriMap ) )
01949                     {
01950                         foreach ( $uriMap as $uriKey => $originalURI )
01951                         {
01952                             $uri = $originalURI;
01953                             if ( $resource )
01954                                 $uri = $resource . ':' . $uri;
01955                             unset( $tmpResourceData );
01956                             $tmpResourceData = $tpl->resourceData( $resourceObject, $uri, $node[1], $originalURI );
01957                             $uriText = $php->thisVariableText( $uri, 0, 0, false );
01958 
01959                             $resourceCanCache = true;
01960                             if ( !$resourceObject->servesStaticData() )
01961                                 $resourceCanCache = false;
01962                             if ( !$tpl->isCachingAllowed() )
01963                                 $resourceCanCache = false;
01964 
01965                             $tmpResourceData['text'] = null;
01966                             $tmpResourceData['root-node'] = null;
01967                             $tmpResourceData['compiled-template'] = false;
01968                             $tmpResourceData['time-stamp'] = null;
01969                             $tmpResourceData['key-data'] = null;
01970                             $tmpResourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
01971                             $subSpacing = 0;
01972                             $hasResourceData = false;
01973 
01974                             $savedLocale = setlocale( LC_CTYPE, null );
01975                             if ( isset( $GLOBALS['eZTemplateCompilerResourceCache'][$tmpResourceData['template-filename']] ) )
01976                             {
01977                                 $tmpFileName = $tmpResourceData['template-filename'];
01978                                 unset( $tmpResourceData );
01979                                 $tmpResourceData = $GLOBALS['eZTemplateCompilerResourceCache'][$tmpFileName];
01980                                 $tmpResourceData['compiled-template'] = true;
01981                                 $tmpResourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
01982                                 $hasResourceData = true;
01983                                 $hasCompiledCode = true;
01984                             }
01985                             else if ( $useFallbackCode )
01986                             {
01987                                 // If we can use fallback code we don't need to compile the templates in advance
01988                                 // Simply fake that it has been compiled by setting some variables
01989                                 // Note: Yes this is a hack, but rewriting this code is not an easy task
01990                                 if ( $resourceObject->handleResource( $tpl, $tmpResourceData, $node[4], $node[5] ) )
01991                                 {
01992                                     $tmpResourceData['compiled-template'] = true;
01993                                     $hasResourceData = true;
01994                                     $hasCompiledCode = true;
01995                                 }
01996                             }
01997                             else
01998                             {
01999                                 if ( $resourceObject->handleResource( $tpl, $tmpResourceData, $node[4], $node[5] ) )
02000                                 {
02001                                     if ( !$tmpResourceData['compiled-template'] and
02002                                          $tmpResourceData['root-node'] === null )
02003                                     {
02004                                         $root =& $tmpResourceData['root-node'];
02005                                         $root = array( eZTemplate::NODE_ROOT, false );
02006                                         $templateText =& $tmpResourceData["text"];
02007                                         $keyData = $tmpResourceData['key-data'];
02008                                         $rootNamespace = '';
02009                                         $tpl->parse( $templateText, $root, $rootNamespace, $tmpResourceData );
02010                                         $hasResourceData = false;
02011                                     }
02012 
02013                                     /* We always DO need to execute this part if we
02014                                      * don't have any fallback code. If we can
02015                                      * generate the fallback code we make the
02016                                      * included template compile on demand */
02017                                     if ( !$tmpResourceData['compiled-template'] and
02018                                          $resourceCanCache and
02019                                          $tpl->canCompileTemplate( $tmpResourceData, $node[5] ) and
02020                                          !$useFallbackCode )
02021                                     {
02022                                         $generateStatus = $tpl->compileTemplate( $tmpResourceData, $node[5] );
02023 
02024                                         // Time limit #2:
02025                                         /* We reset the time limit to 60 seconds to
02026                                          * ensure that remaining template has
02027                                          * enough time to compile. However if time
02028                                          * limit is unlimited (0) we leave it be */
02029                                         $maxExecutionTime = ini_get( 'max_execution_time' );
02030                                         if ( $maxExecutionTime != 0 && $maxExecutionTime < 60 )
02031                                         {
02032                                             @set_time_limit( 60 );
02033                                         }
02034 
02035                                         if ( $generateStatus )
02036                                             $tmpResourceData['compiled-template'] = true;
02037                                     }
02038                                 }
02039                                 $GLOBALS['eZTemplateCompilerResourceCache'][$tmpResourceData['template-filename']] =& $tmpResourceData;
02040                             }
02041                             setlocale( LC_CTYPE, $savedLocale );
02042                             $textName = eZTemplateCompiler::currentTextName( $parameters );
02043                             if ( $tmpResourceData['compiled-template'] )
02044                             {
02045                                 $hasCompiledCode = true;
02046     //                            if ( !eZTemplateCompiler::isFallbackResourceCodeEnabled() )
02047     //                                $useFallbackCode = false;
02048                                 $keyData = $tmpResourceData['key-data'];
02049                                 $templatePath = $tmpResourceData['template-name'];
02050                                 $key = $resourceObject->cacheKey( $keyData, $tmpResourceData, $templatePath, $node[5] );
02051                                 $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $tmpResourceData );
02052 
02053                                 $directory = eZTemplateCompiler::compilationDirectory();
02054                                 $phpScript = eZDir::path( array( $directory, $cacheFileName ) );
02055                                 $phpScriptText = $php->thisVariableText( $phpScript, 0, 0, false );
02056                                 $resourceMap[$uriKey] = array( 'key' => $uriKey,
02057                                                                'uri' => $uri,
02058                                                                'phpscript' => $phpScript );
02059                             }
02060                         }
02061                     }
02062 
02063                     if ( $useComments )
02064                     {
02065                         $variablePlacement = $node[6];
02066                         if ( $variablePlacement )
02067                         {
02068                             $originalText = eZTemplateCompiler::fetchTemplatePiece( $variablePlacement );
02069                             $php->addComment( "Resource Acquisition:", true, true, array( 'spacing' => $spacing ) );
02070                             $php->addComment( $originalText, true, true, array( 'spacing' => $spacing ) );
02071                         }
02072                     }
02073 
02074                     if ( $hasCompiledCode )
02075                     {
02076                         if ( $resourceVariableName )
02077                         {
02078                             $phpScriptText = '$phpScript';
02079                             $phpScriptArray = array();
02080 
02081                             foreach ( $resourceMap as $resourceMapItem )
02082                             {
02083                                 $phpScriptArray[$resourceMapItem['key']] = $resourceMapItem['phpscript'];
02084                             }
02085 
02086                             if ( !$resourceFilename ) /* Not optimized version */
02087                             {
02088                                 $php->addVariable( "phpScriptArray", $phpScriptArray, eZPHPCreator::VARIABLE_ASSIGNMENT, array( 'spacing' => $spacing ) );
02089                                 $resourceVariableNameText = "\$$resourceVariableName";
02090                                 $php->addCodePiece( "\$phpScript = isset( \$phpScriptArray[$resourceVariableNameText] ) ? \$phpScriptArray[$resourceVariableNameText] : false;\n", array( 'spacing' => $spacing ) );
02091                             }
02092                             else /* Optimised version */
02093                             {
02094                                 $php->addVariable( "phpScript", $phpScriptArray[$node[10]], eZPHPCreator::VARIABLE_ASSIGNMENT, array('spacing' => $spacing ) );
02095                             }
02096 
02097                             // The default is to only check if it exists
02098                             $modificationCheckText = "file_exists( $phpScriptText )";
02099                             if  ( eZTemplateCompiler::isDevelopmentModeEnabled() )
02100                             {
02101                                 $modificationCheckText = "file_exists( $phpScriptText ) && filemtime( $phpScriptText ) > filemtime( $uriText )";
02102                             }
02103                             $php->addCodePiece( "\$resourceFound = false;\nif " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( $phpScriptText !== false and $modificationCheckText )\n{\n", array( 'spacing' => $spacing ) );
02104                         }
02105                         else
02106                         {
02107                             $php->addCodePiece( "\$resourceFound = false;\n", array( 'spacing' => $spacing ) );
02108                             $phpScript = $resourceMap[0]['phpscript'];
02109                             $phpScriptText = $php->thisVariableText( $phpScript, 0, 0, false );
02110                             // Not sure where this should come from
02111 //                         if ( $resourceIndex > 0 )
02112 //                             $php->addCodePiece( "else " );
02113                             // The default is to only check if it exists
02114                             $modificationCheckText = "file_exists( $phpScriptText )";
02115                             if  ( eZTemplateCompiler::isDevelopmentModeEnabled() )
02116                             {
02117                                 $modificationCheckText = "file_exists( $phpScriptText ) && filemtime( $phpScriptText ) > filemtime( $uriText )";
02118                             }
02119                             $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( $modificationCheckText )\n{\n", array( 'spacing' => $spacing ) );
02120 
02121                         }
02122 
02123                         /* Generate code to do a namespace switch and includes the template */
02124                         $code = "\$resourceFound = true;\n\$namespaceStack[] = array( \$rootNamespace, \$currentNamespace );\n";
02125                         if ( $newRootNamespace )
02126                         {
02127                             $newRootNamespaceText = $php->thisVariableText( $newRootNamespace, 0, 0, false );
02128                             $code .= "\$currentNamespace = \$rootNamespace = !\$currentNamespace ? $newRootNamespaceText : ( \$currentNamespace . ':' . $newRootNamespaceText );\n";
02129                         }
02130                         else
02131                         {
02132                             $code .= "\$rootNamespace = \$currentNamespace;\n";
02133                         }
02134 
02135                         $code .=
02136                             "\$tpl->createLocalVariablesList();\n" .
02137                             "\$tpl->appendTemplateFetch( $uriText );\n" . // Make sure the template file is recorded, like in loadURIRoot
02138                             "include( '" . eZTemplateCompiler::TemplatePrefix() . "' . $phpScriptText );\n" .
02139                             "\$tpl->unsetLocalVariables();\n" .
02140                             "\$tpl->destroyLocalVariablesList();\n" .
02141                             "list( \$rootNamespace, \$currentNamespace ) = array_pop( \$namespaceStack );\n";
02142 
02143                         $php->addCodePiece( $code, array( 'spacing' => $spacing + 4 ) );
02144                         if ( $useFallbackCode )
02145                             $php->addCodePiece( "}\nelse\n{\n    \$resourceFound = true;\n", array( 'spacing' => $spacing ) );
02146                         else
02147                             $php->addCodePiece( "}\n", array( 'spacing' => $spacing ) );
02148                         $subSpacing = 4;
02149                     }
02150                     else
02151                     {
02152                         /* Yes, this is a hack, but it is required because
02153                          * sometimes the generated nodes after this one emit an
02154                          * else statement while there is no accompanied if */
02155                         $php->addCodePiece( "\nif " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "(false)\n{\n}\n" );
02156                     }
02157 
02158                     /* The fallback code will be added if we need to process an
02159                      * URI, this will also compile a template then. We need to
02160                      * do the namespace switch manually here otherwise the
02161                      * processed template will be run on the node from which
02162                      * the template was included from. */
02163                     if ( $useFallbackCode )
02164                     {
02165                         $code = "\$resourceFound = true;\n\$namespaceStack[] = array( \$rootNamespace, \$currentNamespace );\n";
02166                         if ( $newRootNamespace )
02167                         {
02168                             $newRootNamespaceText = $php->thisVariableText( $newRootNamespace, 0, 0, false );
02169                             $code .= "\$currentNamespace = \$rootNamespace = !\$currentNamespace ? $newRootNamespaceText : ( \$currentNamespace . ':' . $newRootNamespaceText );\n";
02170                         }
02171                         else
02172                         {
02173                             $code .= "\$rootNamespace = \$currentNamespace;\n";
02174                         }
02175                         $php->addCodePiece( $code );
02176 
02177                         $php->addCodePiece( "\$textElements = array();\n\$extraParameters = array();\n\$tpl->processURI( $uriText, true, \$extraParameters, \$textElements, \$rootNamespace, \$currentNamespace );\n\$$textName .= implode( '', \$textElements );\n", array( 'spacing' => $spacing + $subSpacing ) );
02178                         $php->addCodePiece( "list( \$rootNamespace, \$currentNamespace ) = array_pop( \$namespaceStack );\n" );
02179                     }
02180 
02181                     if ( $hasCompiledCode and $useFallbackCode )
02182                     {
02183                         $php->addCodePiece( "}\n", array( 'spacing' => $spacing ) );
02184                     }
02185                 }
02186                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_NAMESPACE_CHANGE )
02187                 {
02188                     $variableData = $node[1];
02189                     $spacing = $currentParameters['spacing'];
02190                     if ( isset( $node[2]['spacing'] ) )
02191                         $spacing += $node[2]['spacing'];
02192                     $php->addCodePiece( "\$namespaceStack[] = \$currentNamespace;\n", array( 'spacing' => $spacing ) );
02193                     $php->addCodePiece( '$currentNamespace .= ( $currentNamespace ? ":" : "" ) . \''. $variableData[0][1] . '\';' . "\n", array( 'spacing' => $spacing ) );
02194                 }
02195                 else if ( $nodeType == eZTemplate::NODE_INTERNAL_NAMESPACE_RESTORE )
02196                 {
02197                     $spacing = $currentParameters['spacing'];
02198                     if ( isset( $node[1]['spacing'] ) )
02199                         $spacing += $node[1]['spacing'];
02200                     $php->addCodePiece( "\$currentNamespace = array_pop( \$namespaceStack );\n", array( 'spacing' => $spacing ) );
02201                 }
02202                 else if ( $nodeType == eZTemplate::NODE_OPTIMIZED_INIT )
02203                 {
02204                     $code = <<<END
02205 \$node = ( array_key_exists( \$rootNamespace, \$vars ) and array_key_exists( "node", \$vars[\$rootNamespace] ) ) ? \$vars[\$rootNamespace]["node"] : null;
02206 if ( is_object( \$node ) )
02207 \$object = \$node->attribute( 'object' );
02208 if ( isset( \$object ) && is_object( \$object ) )
02209 \$nod_{$resourceData['uniqid']} = \$object->attribute( 'data_map' );
02210 else
02211 \$nod_{$resourceData['uniqid']} = false;
02212 unset( \$node, \$object );
02213 
02214 END;
02215                     $php->addCodePiece($code);
02216                     // Tell the rest of the system that we have create the nod_* variable
02217                     $resourceData['node-object-cached'] = true;
02218                 }
02219                 else
02220                     eZDebug::writeWarning( "Unknown internal template node type $nodeType, ignoring node for code generation",
02221                                            'eZTemplateCompiler:generatePHPCodeChildren' );
02222             }
02223             else if ( $nodeType == eZTemplate::NODE_ROOT )
02224             {
02225                 $children = $node[1];
02226                 if ( $children )
02227                 {
02228                     $newCurrentParameters = $currentParameters;
02229                     $newCurrentParameters['spacing'] += 4;
02230                     eZTemplateCompiler::generatePHPCodeChildren( $useComments, $php, $tpl, $children, $resourceData, $parameters, $newCurrentParameters );
02231                 }
02232                 continue;
02233             }
02234             else if ( $nodeType == eZTemplate::NODE_TEXT )
02235             {
02236                 $text = $node[2];
02237                 if ( $text != '' )
02238                 {
02239                     $variablePlacement = $node[3];
02240                     $originalText = eZTemplateCompiler::fetchTemplatePiece( $variablePlacement );
02241                     if ( $useComments )
02242                     {
02243                         $php->addComment( "Text start:", true, true, array( 'spacing' => $currentParameters['spacing'] ) );
02244                         $php->addComment( $originalText, true, true, array( 'spacing' => $currentParameters['spacing'] ) );
02245                         $php->addComment( "Text end:", true, true, array( 'spacing' => $currentParameters['spacing'] ) );
02246                     }
02247                     $php->addVariable( eZTemplateCompiler::currentTextName( $parameters ),
02248                                        $text, eZPHPCreator::VARIABLE_APPEND_TEXT,
02249                                        array( 'spacing' => $currentParameters['spacing'] ) );
02250                 }
02251                 continue;
02252             }
02253             else if ( $nodeType == eZTemplate::NODE_VARIABLE )
02254             {
02255                 $variableAssignmentName = $node[1];
02256                 $variableData = $node[2];
02257                 $variablePlacement = $node[3];
02258 
02259                 $variableParameters = array();
02260                 if ( isset( $node[4] ) and
02261                      $node[4] )
02262                     $variableParameters = $node[4];
02263                 $variableOnlyExisting = isset( $node[5] ) ? $node[5] : false;
02264                 $variableOverWrite = isset( $node[6] ) ? $node[6] : false;
02265                 $rememberSet = isset( $node[7] ) ? $node[7] : false;
02266 
02267                 $spacing = $currentParameters['spacing'];
02268                 if ( isset( $variableParameters['spacing'] ) )
02269                     $spacing += $variableParameters['spacing'];
02270                 $variableParameters = array_merge( array( 'variable-name' => 'var',
02271                                                           'text-result' => true ),
02272                                                    $variableParameters );
02273                 $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
02274                                                                            $variableData, $variablePlacement,
02275                                                                            $resourceData );
02276                 $newNode = $node;
02277                 $newNode[1] = false;
02278 
02279                 $treatVariableDataAsNonObject = isset( $variableParameters['treat-value-as-non-object'] ) && $variableParameters['treat-value-as-non-object'];
02280 
02281                 if ( $useComments )
02282                 {
02283                     $php->addComment( "Variable data: " .
02284                                       "Is constant: " . ( $dataInspection['is-constant'] ? 'Yes' : 'No' ) .
02285                                       " Is variable: " . ( $dataInspection['is-variable'] ? 'Yes' : 'No' ) .
02286                                       " Has attributes: " . ( $dataInspection['has-attributes'] ? 'Yes' : 'No' ) .
02287                                       " Has operators: " . ( $dataInspection['has-operators'] ? 'Yes' : 'No' ),
02288                                       true, true, array( 'spacing' => $spacing )
02289                                       );
02290                     $originalText = eZTemplateCompiler::fetchTemplatePiece( $variablePlacement );
02291                     $php->addComment( '{' . $originalText . '}', true, true, array( 'spacing' => $spacing ) );
02292                 }
02293                 $generatedVariableName = $variableParameters['variable-name'];
02294                 $assignVariable = false;
02295                 if ( $variableAssignmentName !== false )
02296                 {
02297                     if ( is_array( $variableAssignmentName ) )
02298                     {
02299                         $variableParameters['text-result'] = false;
02300                         $assignVariable = true;
02301                     }
02302                     else
02303                     {
02304                         $generatedVariableName = $variableAssignmentName;
02305                         $variableParameters['text-result'] = false;
02306                     }
02307                 }
02308 
02309                 $isStaticElement = false;
02310                 $nodeElements = $node[2];
02311                 $knownTypes = array();
02312                 if ( eZTemplateNodeTool::isConstantElement( $nodeElements ) and
02313                      !$variableParameters['text-result'] )
02314                 {
02315                     $variableText = $php->thisVariableText( eZTemplateNodeTool::elementConstantValue( $nodeElements ), 0, 0, false );
02316                     $isStaticElement = true;
02317                 }
02318                 else if ( eZTemplateNodeTool::isPHPVariableElement( $nodeElements ) and
02319                           !$variableParameters['text-result'] )
02320                 {
02321                     $variableText = '$' . eZTemplateNodeTool::elementConstantValue( $nodeElements );
02322                     $isStaticElement = true;
02323                 }
02324                 else
02325                 {
02326                     $variableText = "\$$generatedVariableName";
02327                     eZTemplateCompiler::generateVariableCode( $php, $tpl, $node, $knownTypes, $dataInspection,
02328                                                               array( 'spacing' => $spacing,
02329                                                                      'variable' => $generatedVariableName,
02330                                                                      'treat-value-as-non-object' => $treatVariableDataAsNonObject,
02331                                                                      'counter' => 0 ),
02332                                                               $resourceData );
02333                 }
02334 
02335                 if ( $variableParameters['text-result'] )
02336                 {
02337                     $textName = eZTemplateCompiler::currentTextName( $parameters );
02338                     if ( count( $knownTypes ) == 0 or in_array( 'objectproxy', $knownTypes ) )
02339                     {
02340                         $php->addCodePiece( "\$$textName .= ( is_object( \$$generatedVariableName ) ? compiledFetchText( \$tpl, \$rootNamespace, \$currentNamespace, false, \$$generatedVariableName ) : \$$generatedVariableName );" .  ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "\n" .
02341                                             "unset( \$$generatedVariableName );\n", array( 'spacing' => $spacing ) );
02342                     }
02343                     else
02344                     {
02345                         $php->addCodePiece( "\$$textName .= \$$generatedVariableName;\n" .
02346                                             "unset( \$$generatedVariableName );\n", array( 'spacing' => $spacing ) );
02347                     }
02348                 }
02349                 else if ( $assignVariable )
02350                 {
02351                     $namespace = $variableAssignmentName[0];
02352                     $namespaceScope = $variableAssignmentName[1];
02353                     $variableName = $variableAssignmentName[2];
02354                     $namespaceText = eZTemplateCompiler::generateMergeNamespaceCode( $php, $tpl, $namespace, $namespaceScope, array( 'spacing' => $spacing ), true );
02355                     if ( !is_string( $namespaceText ) )
02356                         $namespaceText = "\$namespace";
02357                     $variableNameText = $php->thisVariableText( $variableName, 0, 0, false );
02358                     $unsetVariableText = false;
02359                     if ( $variableOnlyExisting )
02360                     {
02361                         if ( !$isStaticElement )
02362                             $unsetVariableText = "\n    unset( $variableText );";
02363                         $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( array_key_exists( $namespaceText, \$vars ) && array_key_exists( $variableNameText, \$vars[$namespaceText] ) )\n".
02364                                             "{\n".
02365                                             "    \$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText\n".
02366                                             "}",
02367                                             array( 'spacing' => $spacing ) );
02368                     }
02369                     else if ( $variableOverWrite )
02370                     {
02371                         if ( !$isStaticElement )
02372                             $unsetVariableText = "\nunset( $variableText );";
02373                         if ( isset( $variableParameters['local-variable'] ) )
02374                         {
02375                             $php->addCodePiece( "if ( \$tpl->hasVariable( $variableNameText, $namespaceText ) )\n{\n" ); // if the variable already exists
02376                             $php->addCodePiece( "    \$tpl->warning( '" . eZTemplateDefFunction::DEF_FUNCTION_NAME . "', \"Variable '$variableName' is already defined.\", " . $php->thisVariableText( $variablePlacement ) . " );\n" );
02377                             $php->addCodePiece( "    \$tpl->setVariable( $variableNameText, $variableText, $namespaceText );\n}\nelse\n{\n" );
02378                             $php->addCodePiece( "    \$tpl->setLocalVariable( $variableNameText, $variableText, $namespaceText );\n}\n" ,
02379                                                 array( 'spacing' => $spacing ) );
02380                         }
02381                         else
02382                         {
02383                             $php->addCodePiece( "\$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText",
02384                                                 array( 'spacing' => $spacing ) );
02385                         }
02386 
02387                     }
02388                     else if ( $rememberSet )
02389                     {
02390                         if ( !$isStaticElement )
02391                             $unsetVariableText = "\n    unset( $variableText );";
02392                         $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$vars[$namespaceText][$variableNameText] ) )\n".
02393                                             "{\n".
02394                                             "    \$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText\n".
02395                                             "    \$setArray[$namespaceText][$variableNameText] = true;\n".
02396                                             "}\n",
02397                                             array( 'spacing' => $spacing ) );
02398                     }
02399                     else
02400                     {
02401                         if ( !$isStaticElement )
02402                             $unsetVariableText = "\n    unset( $variableText );";
02403                         $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$vars[$namespaceText][$variableNameText] ) )\n{\n    \$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText\n}",
02404                                             array( 'spacing' => $spacing ) );
02405                     }
02406                 }
02407                 else if ( $variableAssignmentName !== false and $isStaticElement )
02408                 {
02409                     $php->addCodePiece( "\$$generatedVariableName = $variableText;", array( 'spacing' => $spacing ) );
02410                 }
02411                 else if ( $variableAssignmentName !== false and !$isStaticElement and !$treatVariableDataAsNonObject )
02412                 {
02413                     // Normal assignment from an expression, no need to anything extra
02414                 }
02415                 unset( $dataInspection );
02416             }
02417             else if ( $nodeType == eZTemplate::NODE_FUNCTION )
02418             {
02419                 $functionChildren = $node[1];
02420                 $functionName = $node[2];
02421                 $functionParameters = $node[3];
02422                 $functionPlacement = $node[4];
02423 
02424                 $newNode = array( $nodeType,
02425                                   false,
02426                                   $functionName,
02427                                   $functionParameters,
02428                                   $functionPlacement );
02429 
02430                 $parameterText = 'No parameters';
02431                 if ( $functionParameters )
02432                 {
02433                     $parameterText = "Parameters: ". implode( ', ', array_keys( $functionParameters ) );
02434                 }
02435                 if ( $useComments )
02436                 {
02437                     $php->addComment( "Function: $functionName, $parameterText", true, true, array( 'spacing' => $currentParameters['spacing'] ) );
02438                     $originalText = eZTemplateCompiler::fetchTemplatePiece( $functionPlacement );
02439                     $php->addComment( '{' . $originalText . '}', true, true, array( 'spacing' => $currentParameters['spacing'] ) );
02440                 }
02441                 if ( isset( $node[5] ) )
02442                 {
02443                     $functionHook = $node[5];
02444                     $functionHookCustomFunction = $functionHook['function'];
02445                     if ( $functionHookCustomFunction )
02446                     {
02447                         $functionHookCustomFunction = array_merge( array( 'add-function-name' => false,
02448                                                                           'add-hook-name' => false,
02449                                                                           'add-template-handler' => true,
02450                                                                           'add-function-hook-data' => false,
02451                                                                           'add-function-parameters' => true,
02452                                                                           'add-function-placement' => false,
02453                                                                           'add-calculated-namespace' => false,
02454                                                                           'add-namespace' => true,
02455                                                                           'add-input' => false,
02456                                                                           'return-value' => false ),
02457                                                                    $functionHookCustomFunction );
02458                         if ( !isset( $parameters['hook-result-variable-counter'][$functionName] ) )
02459                             $parameters['hook-result-variable-counter'][$functionName] = 0;
02460                         if ( $functionHookCustomFunction['return-value'] )
02461                             $parameters['hook-result-variable-counter'][$functionName]++;
02462                         $hookResultName = $functionName . 'Result' . $parameters['hook-result-variable-counter'][$functionName];
02463                         if ( $functionHookCustomFunction['add-input'] )
02464                             $parameters['hook-result-variable-counter'][$functionName]--;
02465                         $functionHookCustomFunctionName = $functionHookCustomFunction['name'];
02466                         $codeText = '';
02467                         if ( $functionHookCustomFunction['return-value'] )
02468                             $codeText = "\$$hookResultName = ";
02469                         if ( $functionHookCustomFunction['static'] )
02470                         {
02471                             $hookClassName = $functionHookCustomFunction['class-name'];
02472                             $codeText .= "$hookClassName::$functionHookCustomFunctionName( ";
02473                         }
02474                         else
02475                             $codeText .= "\$functionObject->$functionHookCustomFunctionName( ";
02476                         $codeTextLength = strlen( $codeText );
02477 
02478                         $functionNameText = $php->thisVariableText( $functionName, 0, 0, false );
02479                         $functionChildrenText = $php->thisVariableText( $functionChildren, $codeTextLength, 0, false );
02480 
02481                         $inputFunctionParameters = $functionParameters;
02482                         if ( $functionHookCustomFunction['add-calculated-namespace'] )
02483                             unset( $inputFunctionParameters['name'] );
02484                         $functionParametersText = $php->thisVariableText( $inputFunctionParameters, $codeTextLength, 0, false );
02485 
02486                         $functionPlacementText = $php->thisVariableText( $functionPlacement, $codeTextLength, 0, false );
02487                         $functionHookText = $php->thisVariableText( $functionHook, $codeTextLength, 0, false );
02488 
02489                         $functionHookName = $functionHook['name'];
02490                         $functionHookNameText = $php->thisVariableText( $functionHookName, 0, 0, false );
02491 
02492                         $codeParameters = array();
02493                         if ( $functionHookCustomFunction['add-function-name'] )
02494                             $codeParameters[] = $functionNameText;
02495                         if ( $functionHookCustomFunction['add-hook-name'] )
02496                             $codeParameters[] = $functionHookNameText;
02497                         if ( $functionHookCustomFunction['add-function-hook-data'] )
02498                             $codeParameters[] = $functionHookText;
02499                         if ( $functionHookCustomFunction['add-template-handler'] )
02500                             $codeParameters[] = "\$tpl";
02501                         if ( $functionHookCustomFunction['add-function-parameters'] )
02502                             $codeParameters[] = $functionParametersText;
02503                         if ( $functionHookCustomFunction['add-function-placement'] )
02504                             $codeParameters[] = $functionPlacementText;
02505                         if ( $functionHookCustomFunction['add-calculated-namespace'] )
02506                         {
02507                             $name = '';
02508                             if ( isset( $functionParameters['name'] ) )
02509                             {
02510                                 $nameParameter = $functionParameters['name'];
02511                                 $nameInspection = eZTemplateCompiler::inspectVariableData( $tpl,
02512                                                                                            $nameParameter, $functionPlacement,
02513                                                                                            $resourceData );
02514                                 if ( $nameInspection['is-constant'] and
02515                                      !$nameInspection['is-variable'] and
02516                                      !$nameInspection['has-attributes'] and
02517                                      !$nameInspection['has-operators'] )
02518                                 {
02519                                     $nameData = $nameParameter[0][1];
02520                                     $nameText = $php->thisVariableText( $nameData, 0, 0, false );
02521                                     $php->addCodePiece( "if ( \$currentNamespace != '' )
02522     \$name = \$currentNamespace . ':' . $nameText;
02523 else
02524     \$name = $nameText;\n", array( 'spacing' => $currentParameters['spacing'] ) );
02525                                     $codeParameters[] = "\$name";
02526                                 }
02527                                 else
02528                                 {
02529                                     $persistence = array();
02530                                     $knownTypes = array();
02531                                     eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $nameParameter, $knownTypes, $nameInspection,
02532                                                                                   $persistence,
02533                                                                                   array( 'variable' => 'name',
02534                                                                                          'counter' => 0 ),
02535                                                                                   $resourceData );
02536                                     $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( \$currentNamespace != '' )
02537 {
02538     if ( \$name != '' )
02539         \$name = \"\$currentNamespace:\$name\";
02540     else
02541         \$name = \$currentNamespace;
02542 }\n", array( 'spacing' => $currentParameters['spacing'] ) );
02543                                     $codeParameters[] = "\$name";
02544                                 }
02545                             }
02546                             else
02547                             {
02548                                 $codeParameters[] = "\$currentNamespace";
02549                             }
02550                         }
02551                         if ( $functionHookCustomFunction['add-namespace'] )
02552                             $codeParameters[] = "\$rootNamespace, \$currentNamespace";
02553                         if ( $functionHookCustomFunction['add-input'] )
02554                             $codeParameters[] = "\$$hookResultName";
02555                         $codeText .= implode( ",\n" . str_repeat( ' ', $codeTextLength ),
02556                                               $codeParameters );
02557                         $codeText .= " );\n";
02558                         if ( $functionHookCustomFunction['static'] )
02559                         {
02560                             $hookFile = $functionHookCustomFunction['php-file'];
02561                             $hookFileText = $php->thisVariableText( $hookFile, 0, 0, false );
02562                             $php->addCodePiece( "include_once( $hookFileText );\n", array( 'spacing' => $currentParameters['spacing'] ) );
02563                         }
02564                         else
02565                             $php->addCodePiece( "\$functionObject = \$tpl->fetchFunctionObject( $functionNameText );\n", array( 'spacing' => $currentParameters['spacing'] ) );
02566                         $php->addCodePiece( $codeText, array( 'spacing' => $currentParameters['spacing'] ) );
02567                     }
02568                     else
02569                     {
02570                         $functionNameText = $php->thisVariableText( $functionName, 0, 0, false );
02571                         $functionChildrenText = $php->thisVariableText( $functionChildren, 52, 0, false );
02572                         $functionParametersText = $php->thisVariableText( $functionParameters, 52, 0, false );
02573                         $functionPlacementText = $php->thisVariableText( $functionPlacement, 52, 0, false );
02574 
02575                         $functionHookText = $php->thisVariableText( $functionHook, 52, 0, false );
02576                         $functionHookName = $functionHook['name'];
02577                         $functionHookNameText = $php->thisVariableText( $functionHookName, 0, 0, false );
02578                         $functionHookParameters = $functionHook['parameters'];
02579                         $php->addCodePiece( "\$functionObject = \$tpl->fetchFunctionObject( $functionNameText );
02580 \$hookResult = \$functionObject->templateHookProcess( $functionNameText, $functionHookNameText,
02581                                                     $functionHookText,
02582                                                     \$tpl,
02583                                                     $functionParametersText,
02584                                                     $functionPlacementText,
02585                                                     \$rootNamespace, \$currentNamespace );
02586 ", array( 'spacing' => $currentParameters['spacing'] ) );
02587                     }
02588                 }
02589                 else
02590                 {
02591                     $textName = eZTemplateCompiler::currentTextName( $parameters );
02592                     $functionNameText = $php->thisVariableText( $functionName, 0, 0, false );
02593                     $functionChildrenText = $php->thisVariableText( $functionChildren, 22, 0, false );
02594                     $functionParametersText = $php->thisVariableText( $functionParameters, 22, 0, false );
02595                     $functionPlacementText = $php->thisVariableText( $functionPlacement, 22, 0, false );
02596                     $php->addCodePiece( "\$textElements = array();
02597 \$tpl->processFunction( $functionNameText, \$textElements,
02598                        $functionChildrenText,
02599                        $functionParametersText,
02600                        $functionPlacementText,
02601                        \$rootNamespace, \$currentNamespace );
02602 \$$textName .= implode( '', \$textElements );\n", array( 'spacing' => $currentParameters['spacing'] ) );
02603                 }
02604             }
02605             $php->addSpace();
02606         }
02607     }
02608 
02609     /*!
02610      Generates PHP code which will do namespace merging.
02611      The namespace to merge with is specified in \a $namespace and
02612      the scope of the merging is defined by \a $namespaceScope.
02613     */
02614     static function generateMergeNamespaceCode( $php, $tpl, $namespace, $namespaceScope, $parameters = array(), $skipSimpleAssignment = false )
02615     {
02616         if ( $namespace != '' )
02617         {
02618             if ( $namespaceScope == eZTemplate::NAMESPACE_SCOPE_GLOBAL )
02619             {
02620                 $php->addVariable( 'namespace', $namespace, eZPHPCreator::VARIABLE_ASSIGNMENT, $parameters );
02621             }
02622             else if ( $namespaceScope == eZTemplate::NAMESPACE_SCOPE_LOCAL )
02623             {
02624                 $php->addCodePiece( "\$namespace = \$rootNamespace;
02625 if ( \$namespace == '' )
02626     \$namespace = \"$namespace\";
02627 else
02628     \$namespace .= ':$namespace';
02629 ", $parameters );
02630             }
02631             else if ( $namespaceScope == eZTemplate::NAMESPACE_SCOPE_RELATIVE )
02632             {
02633                 $php->addCodePiece( "\$namespace = \$currentNamespace;
02634 if ( \$namespace == '' )
02635     \$namespace = \"$namespace\";
02636 else
02637     \$namespace .= ':$namespace';
02638 ", $parameters );
02639             }
02640         }
02641         else
02642         {
02643             if ( $namespaceScope == eZTemplate::NAMESPACE_SCOPE_GLOBAL )
02644             {
02645                 if ( $skipSimpleAssignment )
02646                     return "''";
02647                 $php->addVariable( 'namespace', '', eZPHPCreator::VARIABLE_ASSIGNMENT, $parameters );
02648             }
02649             else if ( $namespaceScope == eZTemplate::NAMESPACE_SCOPE_LOCAL )
02650             {
02651                 if ( $skipSimpleAssignment )
02652                     return "\$rootNamespace";
02653                 $php->addCodePiece( "\$namespace = \$rootNamespace;\n", $parameters );
02654             }
02655             else if ( $namespaceScope == eZTemplate::NAMESPACE_SCOPE_RELATIVE )
02656             {
02657                 if ( $skipSimpleAssignment )
02658                     return "\$currentNamespace";
02659                 $php->addCodePiece( "\$namespace = \$currentNamespace;\n", $parameters );
02660             }
02661         }
02662         return true;
02663     }
02664 
02665     /*!
02666      Generates PHP code for the variable node \a $node.
02667      Use generateVariableDataCode if you want to create code for arbitrary variable data structures.
02668     */
02669     static function generateVariableCode( $php, $tpl, $node, &$knownTypes, $dataInspection, $parameters, &$resourceData )
02670     {
02671         $variableData = $node[2];
02672         $persistence = array();
02673         eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $variableData, $knownTypes, $dataInspection, $persistence, $parameters, $resourceData );
02674     }
02675 
02676     /*!
02677      Generates PHP code for the variable tree structure in \a $variableData.
02678      The code will contain string, numeric and identifier assignment,
02679      variable lookup, attribute lookup and operator execution.
02680      Use generateVariableCode if you want to create code for a variable tree node.
02681     */
02682     static function generateVariableDataCode( $php, $tpl, $variableData, &$knownTypes, $dataInspection, &$persistence, $parameters, &$resourceData )
02683     {
02684         $staticTypeMap = array( eZTemplate::TYPE_STRING => 'string',
02685                                 eZTemplate::TYPE_NUMERIC => 'numeric',
02686                                 eZTemplate::TYPE_IDENTIFIER => 'string',
02687                                 eZTemplate::TYPE_ARRAY => 'array',
02688                                 eZTemplate::TYPE_BOOLEAN => 'boolean' );
02689 
02690         $variableAssignmentName = $parameters['variable'];
02691         $variableAssignmentCounter = $parameters['counter'];
02692         $spacing = 0;
02693         $optimizeNode = false;
02694         if ( isset( $parameters['spacing'] ) )
02695             $spacing = $parameters['spacing'];
02696         if ( $variableAssignmentCounter > 0 )
02697             $variableAssignmentName .= $variableAssignmentCounter;
02698 
02699         // We need to unset the assignment variable before any elements are processed
02700         // This ensures that we don't work on existing variables
02701         $php->addCodePiece( "unset( \$$variableAssignmentName );\n", array( 'spacing' => $spacing ) );
02702 
02703         if ( is_array( $variableData ) )
02704         {
02705         foreach ( $variableData as $index => $variableDataItem )
02706         {
02707             $variableDataType = $variableDataItem[0];
02708             if ( $variableDataType == eZTemplate::TYPE_STRING or
02709                  $variableDataType == eZTemplate::TYPE_NUMERIC or
02710                  $variableDataType == eZTemplate::TYPE_IDENTIFIER or
02711                  $variableDataType == eZTemplate::TYPE_ARRAY or
02712                  $variableDataType == eZTemplate::TYPE_BOOLEAN )
02713             {
02714                 $knownTypes = array_unique( array_merge( $knownTypes, array( $staticTypeMap[$variableDataType] ) ) );
02715                 $dataValue = $variableDataItem[1];
02716                 $dataText = $php->thisVariableText( $dataValue, 0, 0, false );
02717                 $php->addCodePiece( "\$$variableAssignmentName = $dataText;\n", array( 'spacing' => $spacing ) );
02718             }
02719             else if ( $variableDataType == eZTemplate::TYPE_OPTIMIZED_NODE )
02720             {
02721                 $optimizeNode = true;
02722                 if ( !isset( $resourceData['node-object-cached'] ) )
02723                     $tpl->error( "eZTemplateCompiler" . ( $resourceData['use-comments'] ? ( ":" . __LINE__ ) : "" ), "Attribute node-object-cached of variable \$resourceData was not found but variable node eZTemplate::TYPE_OPTIMIZED_NODE is still present. This should not happen" );
02724                 $php->addCodePiece("\$$variableAssignmentName = \$nod_{$resourceData['uniqid']};\n");
02725 
02726                 // If optimized node is not set, use unoptimized code.
02727                 $php->addCodePiece( "if ( !\$$variableAssignmentName )\n{\n" );
02728             }
02729             else if ( $variableDataType == eZTemplate::TYPE_OPTIMIZED_ARRAY_LOOKUP )
02730             {
02731                 $code = ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/\n" ) : "" );
02732 
02733                 // This code is used a lot so we create a variable for it
02734                 $phpVar = "\$$variableAssignmentName";
02735                 $indexName = "'{$variableDataItem[1][0][1]}'";
02736 
02737                 // Add sanity checking
02738                 $code .= ( "if ( !isset( {$phpVar}[{$indexName}] ) )\n" .
02739                            "{\n" .
02740                            "    \$tpl->error( 'eZTemplateCompiler" . ( $resourceData['use-comments'] ? ( ":" . __LINE__ ) : "" ) . "', \"PHP variable \\$phpVar"."[{$indexName}] does not exist, cannot fetch the value.\" );\n" .
02741                            "    $phpVar = null;\n" .
02742                            "}\n" .
02743                            "else\n    " );
02744 
02745                 // Add the actual code
02746                 $code .= "$phpVar = {$phpVar}[{$indexName}];\n";
02747 
02748                 $php->addCodePiece( $code );
02749             }
02750             else if ( $variableDataType == eZTemplate::TYPE_OPTIMIZED_ATTRIBUTE_LOOKUP )
02751             {
02752                 $code = ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/\n" ) : "" );
02753                 $code .= <<<END
02754 if ( !is_object( \${$variableAssignmentName} ) )
02755 {
02756     \${$variableAssignmentName} = null;
02757 }
02758 else if ( \${$variableAssignmentName}->hasAttribute( "{$variableDataItem[1][0][1]}" ) )
02759 {
02760     \${$variableAssignmentName} = \${$variableAssignmentName}->attribute( "{$variableDataItem[1][0][1]}" );
02761 }
02762 
02763 END;
02764                 $php->addCodePiece($code);
02765             }
02766             else if ( $variableDataType == eZTemplate::TYPE_OPTIMIZED_CONTENT_CALL )
02767             {
02768                 // Line number comment
02769                 $code = ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/\n" ) : "" );
02770 
02771                 // This code is used a lot so we create a variable for it
02772                 $phpVar = "\$$variableAssignmentName";
02773 
02774                 // Add sanity checking
02775                 $code .= ( "if ( !is_object( $phpVar ) )\n" .
02776                            "{\n" .
02777                            "    \$tpl->error( 'eZTemplateCompiler" . ( $resourceData['use-comments'] ? ( ":" . __LINE__ ) : "" ) . "', \"PHP variable \\$phpVar is not an object, cannot fetch content()\" );\n" .
02778                            "    $phpVar = null;\n" .
02779                            "}\n" .
02780                            "else\n" .
02781                            "{\n" );
02782 
02783                 // Add the actual code
02784                 $code .= "     {$phpVar}Tmp = {$phpVar}->content();\n" .
02785                          "     unset( $phpVar );\n" .
02786                          "     $phpVar = {$phpVar}Tmp;\n" .
02787                          "     unset( {$phpVar}Tmp );\n}\n";
02788 
02789                 $php->addCodePiece( $code );
02790             }
02791             else if ( $variableDataType == eZTemplate::TYPE_PHP_VARIABLE )
02792             {
02793                 $knownTypes = array();
02794                 $phpVariableName = $variableDataItem[1];
02795                 $php->addCodePiece( "\$$variableAssignmentName = \$$phpVariableName;\n", array( 'spacing' => $spacing ) );
02796             }
02797             else if ( $variableDataType == eZTemplate::TYPE_VARIABLE )
02798             {
02799                 $knownTypes = array();
02800                 $namespace = $variableDataItem[1][0];
02801                 $namespaceScope = $variableDataItem[1][1];
02802                 $variableName = $variableDataItem[1][2];
02803                 $namespaceText = eZTemplateCompiler::generateMergeNamespaceCode( $php, $tpl, $namespace, $namespaceScope, array( 'spacing' => $spacing ), true );
02804                 if ( !is_string( $namespaceText ) )
02805                     $namespaceText = "\$namespace";
02806                 $variableNameText = $php->thisVariableText( $variableName, 0, 0, false );
02807                 $code = "unset( \$$variableAssignmentName );\n";
02808                 $code .= "\$$variableAssignmentName = ( array_key_exists( $namespaceText, \$vars ) and array_key_exists( $variableNameText, \$vars[$namespaceText] ) ) ? \$vars[$namespaceText][$variableNameText] : null;\n";
02809                 $php->addCodePiece( $code,
02810                                     array( 'spacing' => $spacing ) );
02811             }
02812             else if ( $variableDataType == eZTemplate::TYPE_ATTRIBUTE )
02813             {
02814                 $knownTypes = array();
02815                 $newParameters = $parameters;
02816                 $newParameters['counter'] += 1;
02817                 $tmpVariableAssignmentName = $newParameters['variable'];
02818                 $tmpVariableAssignmentCounter = $newParameters['counter'];
02819                 if ( $tmpVariableAssignmentCounter > 0 )
02820                     $tmpVariableAssignmentName .= $tmpVariableAssignmentCounter;
02821                 if ( eZTemplateNodeTool::isConstantElement( $variableDataItem[1] ) )
02822                 {
02823                     $attributeStaticValue = eZTemplateNodeTool::elementConstantValue( $variableDataItem[1] );
02824                     $attributeText = $php->thisVariableText( $attributeStaticValue, 0, 0, false );
02825                 }
02826                 else
02827                 {
02828                     $newParameters['counter'] += 1;
02829                     $tmpKnownTypes = array();
02830                     eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $variableDataItem[1], $tmpKnownTypes, $dataInspection,
02831                                                                   $persistence, $newParameters, $resourceData );
02832                     $newVariableAssignmentName = $newParameters['variable'];
02833                     $newVariableAssignmentCounter = $newParameters['counter'];
02834                     if ( $newVariableAssignmentCounter > 0 )
02835                         $newVariableAssignmentName .= $newVariableAssignmentCounter;
02836                     $attributeText = "\$$newVariableAssignmentName";
02837                 }
02838                 $php->addCodePiece( "\$$tmpVariableAssignmentName = compiledFetchAttribute( \$$variableAssignmentName, $attributeText );\n" .
02839                                     "unset( \$$variableAssignmentName );\n" .
02840                                     "\$$variableAssignmentName = \$$tmpVariableAssignmentName;\n",
02841                                     array( 'spacing' => $spacing ) );
02842 
02843                 // End if optimized node object is null/false. See also eZTemplateOptimizer::optimizeVariable()
02844                 if ( $optimizeNode &&
02845                      $index == 3 )
02846                 {
02847                     $php->addCodePiece( "}\n" );
02848                 }
02849             }
02850             else if ( $variableDataType == eZTemplate::TYPE_OPERATOR )
02851             {
02852                 $knownTypes = array();
02853                 $operatorParameters = $variableDataItem[1];
02854                 $operatorName = $operatorParameters[0];
02855                 $operatorParameters = array_splice( $operatorParameters, 1 );
02856                 $operatorNameText = $php->thisVariableText( $operatorName, 0, 0, false );
02857                 $operatorParametersText = $php->thisVariableText( $operatorParameters, 23, 0, false );
02858 
02859                 $operatorHint = eZTemplateCompiler::operatorHint( $tpl, $operatorName );
02860                 if ( isset( $operatorHint['output'] ) and $operatorHint['output'] )
02861                 {
02862                     if ( isset( $operatorHint['output-type'] ) )
02863                     {
02864                         $knownType = $operatorHint['output-type'];
02865                         if ( is_array( $knownType ) )
02866                             $knownTypes = array_merge( $knownTypes, $knownType );
02867                         else
02868                             $knownTypes[] = $knownType;
02869                         $knownTypes = array_unique( $knownTypes );
02870                     }
02871                     else
02872                         $knownTypes[] = 'static';
02873                 }
02874 
02875                 $php->addCodePiece( "if (! isset( \$$variableAssignmentName ) ) \$$variableAssignmentName = NULL;\n", array ( 'spacing' => $spacing ) );
02876                 $php->addCodePiece( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$variableAssignmentName ) and method_exists( \$$variableAssignmentName, 'templateValue' ) )\n" .
02877                                                   "    \$$variableAssignmentName = \$$variableAssignmentName" . "->templateValue();\n" );
02878                 $php->addCodePiece( "\$" . $variableAssignmentName . "Data = array( 'value' => \$$variableAssignmentName );
02879 \$tpl->processOperator( $operatorNameText,
02880                        $operatorParametersText,
02881                        \$rootNamespace, \$currentNamespace, \$" . $variableAssignmentName . "Data, false, false );
02882 \$$variableAssignmentName = \$" . $variableAssignmentName . "Data['value'];
02883 unset( \$" . $variableAssignmentName . "Data );\n",
02884                                     array( 'spacing' => $spacing ) );
02885             }
02886             else if ( $variableDataType == eZTemplate::TYPE_VOID )
02887             {
02888             }
02889             else if ( $variableDataType == eZTemplate::TYPE_DYNAMIC_ARRAY )
02890             {
02891                 $knownTypes = array_unique( array_merge( $knownTypes, array( 'array' ) ) );
02892                 $code = '%output% = array( ';
02893 
02894                 $matchMap = array( '%input%', '%output%' );
02895                 $replaceMap = array( '$' . $variableAssignmentName, '$' . $variableAssignmentName );
02896                 $unsetList = array();
02897                 $counter = 1;
02898                 $paramCount = 0;
02899 
02900                 $values = $variableDataItem[2];
02901                 $newParameters = $parameters;
02902                 foreach ( $values as $key => $value )
02903                 {
02904                     if ( $paramCount != 0 )
02905                     {
02906                         $code .= ', ';
02907                     }
02908                     ++$paramCount;
02909                     $code .= '\'' . $key . '\' => ';
02910                     if( eZTemplateNodeTool::isConstantElement( $value ) )
02911                     {
02912                         $code .= eZPHPCreator::variableText( eZTemplateNodeTool::elementConstantValue( $value ), 0, 0, false );
02913                         continue;
02914                     }
02915                     $code .= '%' . $counter . '%';
02916                     $newParameters['counter'] += 1;
02917                     $newVariableAssignmentName = $newParameters['variable'];
02918                     $newVariableAssignmentCounter = $newParameters['counter'];
02919                     if ( $newVariableAssignmentCounter > 0 )
02920                         $newVariableAssignmentName .= $newVariableAssignmentCounter;
02921                     $matchMap[] = '%' . $counter . '%';
02922                     $replaceMap[] = '$' . $newVariableAssignmentName;
02923                     $unsetList[] = $newVariableAssignmentName;
02924                     $tmpKnownTypes = array();
02925                     eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $value, $tmpKnownTypes, $dataInspection,
02926                                                                   $persistence, $newParameters, $resourceData );
02927                     ++$counter;
02928                 }
02929 
02930                 $code .= ' );';
02931                 $code = str_replace( $matchMap, $replaceMap, $code );
02932                 $php->addCodePiece( $code, array( 'spacing' => $spacing ) );
02933                 $php->addVariableUnsetList( $unsetList, array( 'spacing' => $spacing ) );
02934             }
02935             else if ( $variableDataType == eZTemplate::TYPE_INTERNAL_CODE_PIECE )
02936             {
02937                 $code = $variableDataItem[1];
02938                 $values = false;
02939                 $matchMap = array( '%input%', '%output%' );
02940                 $replaceMap = array( '$' . $variableAssignmentName, '$' . $variableAssignmentName );
02941                 $unsetList = array();
02942                 $counter = 1;
02943                 if ( isset( $variableDataItem[3] ) && is_array( $variableDataItem[3] ) )
02944                 {
02945                     $newParameters = $parameters;
02946                     $values = $variableDataItem[3];
02947                     foreach ( $values as $value )
02948                     {
02949                         $newParameters['counter'] += 1;
02950                         $newVariableAssignmentName = $newParameters['variable'];
02951                         $newVariableAssignmentCounter = $newParameters['counter'];
02952                         if ( $newVariableAssignmentCounter > 0 )
02953                             $newVariableAssignmentName .= $newVariableAssignmentCounter;
02954                         if ( eZTemplateNodeTool::isConstantElement( $value ) )
02955                         {
02956                             $staticValue = eZTemplateNodeTool::elementConstantValue( $value );
02957                             $staticValueText = $php->thisVariableText( $staticValue, 0, 0, false );
02958                             if ( preg_match( "/%code$counter%/", $code ) )
02959                             {
02960                                 $matchMap[] = '%code' . $counter . '%';
02961                                 $replaceMap[] = '';
02962                             }
02963                             $matchMap[] = '%' . $counter . '%';
02964                             $replaceMap[] = $staticValueText;
02965                         }
02966                         else
02967                         {
02968                             $matchMap[] = '%' . $counter . '%';
02969                             $replaceMap[] = '$' . $newVariableAssignmentName;
02970                             $unsetList[] = $newVariableAssignmentName;
02971                             if ( preg_match( "/%code$counter%/", $code ) )
02972                             {
02973                                 $tmpPHP = new eZPHPCreator( '', '', eZTemplateCompiler::TemplatePrefix() );
02974                                 $tmpKnownTypes = array();
02975                                 eZTemplateCompiler::generateVariableDataCode( $tmpPHP, $tpl, $value, $tmpKnownTypes, $dataInspection,
02976                                                                               $persistence, $newParameters, $resourceData );
02977                                 $newCode = $tmpPHP->fetch( false );
02978                                 if ( count( $tmpKnownTypes ) == 0 or in_array( 'objectproxy', $tmpKnownTypes ) )
02979                                 {
02980                                     $newCode .= ( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$newVariableAssignmentName ) and method_exists( \$$newVariableAssignmentName, 'templateValue' ) )\n" .
02981                                                   "    \$$newVariableAssignmentName = \$$newVariableAssignmentName" . "->templateValue();\n" );
02982                                 }
02983                                 $matchMap[] = '%code' . $counter . '%';
02984                                 $replaceMap[] = $newCode;
02985                             }
02986                             else
02987                             {
02988                                 $tmpKnownTypes = array();
02989                                 eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $value, $tmpKnownTypes, $dataInspection,
02990                                                                               $persistence, $newParameters, $resourceData );
02991                                 if ( !$parameters['treat-value-as-non-object'] and ( count( $tmpKnownTypes ) == 0 or in_array( 'objectproxy', $tmpKnownTypes ) ) )
02992                                 {
02993                                     $php->addCodePiece( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$newVariableAssignmentName ) and method_exists( \$$newVariableAssignmentName, 'templateValue' ) )\n" .
02994                                                         "    \$$newVariableAssignmentName = \$$newVariableAssignmentName" . "->templateValue();\n",
02995                                                         array( 'spacing' => $spacing ) );
02996                                 }
02997                             }
02998                         }
02999                         ++$counter;
03000                     }
03001                 }
03002                 if ( isset( $variableDataItem[4] ) && ( $variableDataItem[4] !== false ) )
03003                 {
03004                     $values = $variableDataItem[4];
03005 
03006                     for ( $i = 0; $i < $values; $i++ )
03007                     {
03008                         $newParameters['counter'] += 1;
03009                         $newVariableAssignmentName = $newParameters['variable'];
03010                         $newVariableAssignmentCounter = $newParameters['counter'];
03011                         if ( $newVariableAssignmentCounter > 0 )
03012                             $newVariableAssignmentName .= $newVariableAssignmentCounter;
03013                         $matchMap[] = '%tmp' . ( $i + 1 ) . '%';
03014                         $replaceMap[] = '$' . $newVariableAssignmentName;
03015                         $unsetList[] = $newVariableAssignmentName;
03016                     }
03017                 }
03018                 if ( isset( $variableDataItem[5] ) and $variableDataItem[5] )
03019                 {
03020                     if ( is_array( $variableDataItem[5] ) )
03021                         $knownTypes = array_unique( array_merge( $knownTypes, $variableDataItem[5] ) );
03022                     else if ( is_string( $variableDataItem[5] ) )
03023                         $knownTypes = array_unique( array_merge( $knownTypes, array( $variableDataItem[5] ) ) );
03024                     else
03025                         $knownTypes = array_unique( array_merge( $knownTypes, array( 'static' ) ) );
03026                 }
03027                 $code = str_replace( $matchMap, $replaceMap, $code );
03028                 $php->addCodePiece( $code, array( 'spacing' => $spacing ) );
03029                 $php->addVariableUnsetList( $unsetList, array( 'spacing' => $spacing ) );
03030             }
03031         }
03032         }
03033         // After the entire expression line is done we try to extract the actual value if proxies are used
03034         $php->addCodePiece( "if (! isset( \$$variableAssignmentName ) ) \$$variableAssignmentName = NULL;\n" );
03035         $php->addCodePiece( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$variableAssignmentName ) and method_exists( \$$variableAssignmentName, 'templateValue' ) )\n" .
03036                             "    \$$variableAssignmentName = \$$variableAssignmentName" . "->templateValue();\n" );
03037     }
03038 }
03039 
03040 ?>