[ Index ]
 

Code source de eZ Publish 3.9.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/eztemplate/classes/ -> eztemplatecompiler.php (source)

   1  <?php
   2  //
   3  // Definition of eZTemplateCompiler class
   4  //
   5  // Created on: <06-Dec-2002 14:17:10 amos>
   6  //
   7  // SOFTWARE NAME: eZ publish
   8  // SOFTWARE RELEASE: 3.9.0
   9  // BUILD VERSION: 17785
  10  // COPYRIGHT NOTICE: Copyright (C) 1999-2006 eZ systems AS
  11  // SOFTWARE LICENSE: GNU General Public License v2.0
  12  // NOTICE: >
  13  //   This program is free software; you can redistribute it and/or
  14  //   modify it under the terms of version 2.0  of the GNU General
  15  //   Public License as published by the Free Software Foundation.
  16  //
  17  //   This program is distributed in the hope that it will be useful,
  18  //   but WITHOUT ANY WARRANTY; without even the implied warranty of
  19  //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20  //   GNU General Public License for more details.
  21  //
  22  //   You should have received a copy of version 2.0 of the GNU General
  23  //   Public License along with this program; if not, write to the Free
  24  //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  25  //   MA 02110-1301, USA.
  26  //
  27  //
  28  
  29  /*! \file eztemplatecompiler.php
  30  */
  31  
  32  /*!
  33    \class eZTemplateCompiler eztemplatecompiler.php
  34    \brief Creates compiled PHP code from templates to speed up template usage.
  35  
  36     Various optimizations that can be done are:
  37  
  38      Data:
  39      - Is constant, generate static data
  40      - Is variable, generate direct variable extraction
  41      - Has operators
  42      - Has attributes
  43  
  44      Attributes:
  45      - Is constant, generate static data
  46  
  47      Operators:
  48      - Supports input
  49      - Supports output
  50      - Supports parameters
  51      - Generates static data (true, false)
  52      - Custom PHP code
  53      - Modifies template variables, if possible name which ones. Allows
  54        for caching of variables in the script.
  55  
  56      Functions:
  57      - Supports parameters
  58      - Supports children (set? no, section? yes)
  59      - Generates static data (ldelim,rdelim)
  60      - Children usage, no result(set-block) | copy(let,default) | dynamic(conditional, repeated etc.)
  61      - Children tree, requires original tree | allows custom processing
  62      - Custom PHP code
  63      - Deflate/transform tree, create new non-nested tree (let, default)
  64      - Modifies template variables, if possible name which ones. Allows
  65        for caching of variables in the script.
  66  */
  67  
  68  include_once ( 'lib/ezutils/classes/ezdebug.php' );
  69  
  70  define( 'EZ_TEMPLATE_COMPILE_CODE_DATE', 1074699607 );
  71  
  72  class eZTemplateCompiler
  73  {
  74      /*!
  75       Constructor
  76      */
  77      function eZTemplateCompiler()
  78      {
  79      }
  80  
  81      /*!
  82       \static
  83       Returns the prefix for file names
  84      */
  85      function TemplatePrefix()
  86      {
  87          $templatePrefix = '';
  88          include_once ( 'lib/ezutils/classes/ezini.php' );
  89          $ini =& eZINI::instance();
  90          if ( $ini->variable( 'TemplateSettings', 'TemplateCompression' ) == 'enabled' )
  91          {
  92              $templatePrefix = 'compress.zlib://';
  93          }
  94          return $templatePrefix;
  95      }
  96      /*!
  97       \static
  98       Sets/unsets various compiler settings. To set a setting add a key in the \a $settingsMap
  99       with the wanted value, to unset it use \c null as the value.
 100  
 101       The following values can be set.
 102       - compile - boolean, whether to compile templates or not
 103       - comments - boolean, whether to include comments in templates
 104       - accumulators - boolean, whether to include debug accumulators in templates
 105       - timingpoints - boolean, whether to include debug timingpoints in templates
 106       - fallbackresource - boolean, whether to include the fallback resource code
 107       - nodeplacement - boolean, whether to include information on placement of all nodes
 108       - execution - boolean, whether to execute the compiled templates or not
 109       - generate - boolean, whether to always generate the compiled files, or only when template is changed
 110       - compilation-directory - string, where to place compiled files, the path will be relative from the
 111                                 eZ publish directory and not the var/cache directory.
 112      */
 113      function setSettings( $settingsMap )
 114      {
 115          $existingMap = array();
 116          if ( isset( $GLOBALS['eZTemplateCompilerSettings'] ) )
 117          {
 118              $existingMap = $GLOBALS['eZTemplateCompilerSettings'];
 119          }
 120          $GLOBALS['eZTemplateCompilerSettings'] = array_merge( $existingMap, $settingsMap );
 121      }
 122  
 123      /*!
 124       \static
 125       \return true if template compiling is enabled.
 126       \note To change this setting edit settings/site.ini and locate the group TemplateSettings and the entry TemplateCompile.
 127      */
 128      function isCompilationEnabled()
 129      {
 130          if ( isset( $GLOBALS['eZSiteBasics'] ) )
 131          {
 132              $siteBasics = $GLOBALS['eZSiteBasics'];
 133              if ( isset( $siteBasics['no-cache-adviced'] ) and
 134                   $siteBasics['no-cache-adviced'] )
 135              {
 136                  return false;
 137              }
 138          }
 139  
 140          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['compile'] ) and
 141               $GLOBALS['eZTemplateCompilerSettings']['compile'] !== null )
 142          {
 143              return $GLOBALS['eZTemplateCompilerSettings']['compile'];
 144          }
 145  
 146          include_once ( 'lib/ezutils/classes/ezini.php' );
 147          $ini =& eZINI::instance();
 148          $compilationEnabled = $ini->variable( 'TemplateSettings', 'TemplateCompile' ) == 'enabled';
 149          return $compilationEnabled;
 150      }
 151  
 152      /*!
 153       \static
 154       \return true if template compilation should include comments.
 155      */
 156      function isCommentsEnabled()
 157      {
 158          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['comments'] ) and
 159               $GLOBALS['eZTemplateCompilerSettings']['comments'] !== null )
 160          {
 161              return $GLOBALS['eZTemplateCompilerSettings']['comments'];
 162          }
 163  
 164          include_once ( 'lib/ezutils/classes/ezini.php' );
 165          $ini =& eZINI::instance();
 166          $commentsEnabled = $ini->variable( 'TemplateSettings', 'CompileComments' ) == 'enabled';
 167          return $commentsEnabled;
 168      }
 169  
 170      /*!
 171       \static
 172       \return true if template compilation should run in development mode.
 173  
 174       When in development mode the system will perform additional checks, e.g. for
 175       modification time of compiled file vs original source file.
 176       This mode is quite useful for development since it requires less
 177       clear-cache calls but has additional file checks and should be turned off
 178       for live sites.
 179      */
 180      function isDevelopmentModeEnabled()
 181      {
 182          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['development_mode'] ) and
 183               $GLOBALS['eZTemplateCompilerSettings']['development_mode'] !== null )
 184          {
 185              return $GLOBALS['eZTemplateCompilerSettings']['development_mode'];
 186          }
 187  
 188          include_once ( 'lib/ezutils/classes/ezini.php' );
 189          $ini =& eZINI::instance();
 190          $developmentModeEnabled = $ini->variable( 'TemplateSettings', 'DevelopmentMode' ) == 'enabled';
 191          return $developmentModeEnabled;
 192      }
 193  
 194      /*!
 195       \static
 196       \return true if template compilation should include debug accumulators.
 197      */
 198      function isAccumulatorsEnabled()
 199      {
 200          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['accumulators'] ) and
 201               $GLOBALS['eZTemplateCompilerSettings']['accumulators'] !== null )
 202          {
 203              return $GLOBALS['eZTemplateCompilerSettings']['accumulators'];
 204          }
 205  
 206          include_once ( 'lib/ezutils/classes/ezini.php' );
 207          $ini =& eZINI::instance();
 208          $enabled = $ini->variable( 'TemplateSettings', 'CompileAccumulators' ) == 'enabled';
 209          return $enabled;
 210      }
 211  
 212      /*!
 213       \static
 214       \return true if template compilation should include debug timing points.
 215      */
 216      function isTimingPointsEnabled()
 217      {
 218          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['timingpoints'] ) and
 219               $GLOBALS['eZTemplateCompilerSettings']['timingpoints'] !== null )
 220          {
 221              return $GLOBALS['eZTemplateCompilerSettings']['timingpoints'];
 222          }
 223  
 224          include_once ( 'lib/ezutils/classes/ezini.php' );
 225          $ini =& eZINI::instance();
 226          $enabled = $ini->variable( 'TemplateSettings', 'CompileTimingPoints' ) == 'enabled';
 227          return $enabled;
 228      }
 229  
 230      /*!
 231       \static
 232       \return true if resource fallback code should be included.
 233      */
 234      function isFallbackResourceCodeEnabled()
 235      {
 236          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['fallbackresource'] ) and
 237               $GLOBALS['eZTemplateCompilerSettings']['fallbackresource'] !== null )
 238          {
 239              return $GLOBALS['eZTemplateCompilerSettings']['fallbackresource'];
 240          }
 241  
 242          include_once ( 'lib/ezutils/classes/ezini.php' );
 243          $ini =& eZINI::instance();
 244          $enabled = $ini->variable( 'TemplateSettings', 'CompileResourceFallback' ) == 'enabled';
 245          return $enabled;
 246      }
 247  
 248      /*!
 249       \static
 250       \return true if template compilation should include comments.
 251      */
 252      function isNodePlacementEnabled()
 253      {
 254          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['nodeplacement'] ) and
 255               $GLOBALS['eZTemplateCompilerSettings']['nodeplacement'] !== null )
 256          {
 257              return $GLOBALS['eZTemplateCompilerSettings']['nodeplacement'];
 258          }
 259  
 260          include_once ( 'lib/ezutils/classes/ezini.php' );
 261          $ini =& eZINI::instance();
 262          $nodePlacementEnabled = $ini->variable( 'TemplateSettings', 'CompileNodePlacements' ) == 'enabled';
 263          return $nodePlacementEnabled;
 264      }
 265  
 266      /*!
 267       \static
 268       \return true if the compiled template execution is enabled.
 269      */
 270      function isExecutionEnabled()
 271      {
 272          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['execution'] ) and
 273               $GLOBALS['eZTemplateCompilerSettings']['execution'] !== null )
 274          {
 275              return $GLOBALS['eZTemplateCompilerSettings']['execution'];
 276          }
 277  
 278          include_once ( 'lib/ezutils/classes/ezini.php' );
 279          $ini =& eZINI::instance();
 280          $execution = $ini->variable( 'TemplateSettings', 'CompileExecution' ) == 'enabled';
 281          return $execution;
 282      }
 283  
 284      /*!
 285       \static
 286       \return true if template compilation should always be run even if a sufficient compilation already exists.
 287      */
 288      function alwaysGenerate()
 289      {
 290          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['generate'] ) and
 291               $GLOBALS['eZTemplateCompilerSettings']['generate'] !== null )
 292          {
 293              return $GLOBALS['eZTemplateCompilerSettings']['generate'];
 294          }
 295  
 296          include_once ( 'lib/ezutils/classes/ezini.php' );
 297          $ini =& eZINI::instance();
 298          $alwaysGenerate = $ini->variable( 'TemplateSettings', 'CompileAlwaysGenerate' ) == 'enabled';
 299          return $alwaysGenerate;
 300      }
 301  
 302      /*!
 303       \static
 304       \return true if template node tree named \a $treeName should be included the compiled template.
 305      */
 306      function isTreeEnabled( $treeName )
 307      {
 308          include_once ( 'lib/ezutils/classes/ezini.php' );
 309          $ini =& eZINI::instance();
 310          $treeList = $ini->variable( 'TemplateSettings', 'CompileIncludeNodeTree' );
 311          return in_array( $treeName, $treeList );
 312      }
 313  
 314      /*!
 315       \static
 316       \return the directory for compiled templates.
 317      */
 318      function compilationDirectory()
 319      {
 320          if ( isset( $GLOBALS['eZTemplateCompilerSettings']['compilation-directory'] ) and
 321               $GLOBALS['eZTemplateCompilerSettings']['compilation-directory'] !== null )
 322          {
 323              return $GLOBALS['eZTemplateCompilerSettings']['compilation-directory'];
 324          }
 325  
 326          $compilationDirectory =& $GLOBALS['eZTemplateCompilerDirectory'];
 327          if ( !isset( $compilationDirectory ) )
 328          {
 329              include_once ( 'lib/ezfile/classes/ezdir.php' );
 330              include_once ( 'lib/ezutils/classes/ezsys.php' );
 331              $compilationDirectory = eZDir::path( array( eZSys::cacheDirectory(), 'template/compiled' ) );
 332          }
 333          return $compilationDirectory;
 334      }
 335  
 336      /*!
 337       Creates the name for the compiled template and returns it.
 338       The name conists of original filename with the md5 of the key and charset appended.
 339      */
 340      function compilationFilename( $key, $resourceData )
 341      {
 342          $internalCharset = eZTextCodec::internalCharset();
 343          $templateFilepath = $resourceData['template-filename'];
 344          $extraName = '';
 345          if ( preg_match( "#^.+/(.*)\.tpl$#", $templateFilepath, $matches ) )
 346              $extraName = $matches[1] . '-';
 347          else if ( preg_match( "#^(.*)\.tpl$#", $templateFilepath, $matches ) )
 348              $extraName = $matches[1] . '-';
 349          $accessText = false;
 350          if ( isset( $GLOBALS['eZCurrentAccess']['name'] ) )
 351              $accessText = '-' . $GLOBALS['eZCurrentAccess']['name'];
 352          include_once ( 'lib/ezlocale/classes/ezlocale.php' );
 353          $locale =& eZLocale::instance();
 354          $language = $locale->translationCode();
 355          include_once ( 'lib/ezutils/classes/ezhttptool.php' );
 356          $http =& eZHTTPTool::instance();
 357          $useFullUrlText = $http->UseFullUrl ? 'full' : 'relative';
 358  
 359          $pageLayoutVariable = "";
 360          if ( isset( $GLOBALS['eZCustomPageLayout'] ) )
 361              $pageLayoutVariable = $GLOBALS['eZCustomPageLayout'];
 362          $cacheFileKey = $key . '-' . $internalCharset . '-' . $language . '-' . $useFullUrlText . $accessText . "-" . $pageLayoutVariable . '-' . eZSys::indexFile();
 363          $cacheFileName = $extraName . md5( $cacheFileKey ) . '.php';
 364          return $cacheFileName;
 365      }
 366  
 367      /*!
 368       \static
 369       \return true if the compiled template with the key \a $key exists.
 370               A compiled template is found usable when it exists and has a timestamp
 371               higher or equal to \a $timestamp.
 372      */
 373      function hasCompiledTemplate( $key, $timestamp, &$resourceData )
 374      {
 375          if ( !eZTemplateCompiler::isCompilationEnabled() )
 376              return false;
 377          if ( eZTemplateCompiler::alwaysGenerate() )
 378              return false;
 379  
 380          $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $resourceData );
 381  
 382          include_once ( 'lib/ezutils/classes/ezphpcreator.php' );
 383  
 384          $php = new eZPHPCreator( eZTemplateCompiler::compilationDirectory(), $cacheFileName, eZTemplateCompiler::TemplatePrefix() );
 385          $canRestore = $php->canRestore( $timestamp );
 386          $uri = false;
 387          if ( $canRestore )
 388              eZDebugSetting::writeDebug( 'eztemplate-compile', "Cache hit for uri '$uri' with key '$key'", 'eZTemplateCompiler::hasCompiledTemplate' );
 389          else
 390              eZDebugSetting::writeDebug( 'eztemplate-compile', "Cache miss for uri '$uri' with key '$key'", 'eZTemplateCompiler::hasCompiledTemplate' );
 391          return $canRestore;
 392      }
 393  
 394      /*!
 395       Tries to execute the compiled template and returns \c true if succsesful.
 396       Returns \c false if caching is disabled or the compiled template could not be executed.
 397      */
 398      function executeCompilation( &$tpl, &$textElements, $key, &$resourceData,
 399                                   $rootNamespace, $currentNamespace )
 400       {
 401          if ( !eZTemplateCompiler::isCompilationEnabled() )
 402              return false;
 403          if ( !eZTemplateCompiler::isExecutionEnabled() )
 404              return false;
 405          $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $resourceData );
 406          $resourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
 407  
 408          $directory = eZTemplateCompiler::compilationDirectory();
 409          $phpScript = eZDir::path( array( $directory, $cacheFileName ) );
 410          if ( file_exists( $phpScript ) )
 411          {
 412              $text = false;
 413              $helperStatus = eZTemplateCompiler::executeCompilationHelper( $phpScript, $text,
 414                                                                            $tpl, $key, $resourceData,
 415                                                                            $rootNamespace, $currentNamespace );
 416              if ( $helperStatus )
 417              {
 418                  $textElements[] = $text;
 419                  return true;
 420              }
 421              else
 422                  eZDebug::writeError( "Failed executing compiled template '$phpScript'", 'eZTemplateCompiler::executeCompilation' );
 423          }
 424          else
 425              eZDebug::writeError( "Unknown compiled template '$phpScript'", 'eZTemplateCompiler::executeCompilation' );
 426          return false;
 427      }
 428  
 429      /*!
 430       Helper function for executeCompilation. Will execute the script \a $phpScript and
 431       set the result text in \a $text.
 432       The parameters \a $tpl, \a $resourceData, \a $rootNamespace and \a $currentNamespace
 433       are passed to the executed template compilation script.
 434       \return true if a text result was created.
 435      */
 436      function executeCompilationHelper( $phpScript, &$text,
 437                                         &$tpl, $key, &$resourceData,
 438                                         $rootNamespace, $currentNamespace )
 439      {
 440          $vars =& $tpl->Variables;
 441  
 442          /* We use $setArray to detect if execution failed, and not $text,
 443           * because an empty template does not return any $text and this is not
 444           * an error. */
 445          $setArray = null;
 446          $namespaceStack = array();
 447  
 448          $tpl->createLocalVariablesList();
 449          include( eZTemplateCompiler::TemplatePrefix() . $phpScript );
 450          $tpl->unsetLocalVariables();
 451          $tpl->destroyLocalVariablesList();
 452  
 453          if ( $setArray !== null )
 454          {
 455              return true;
 456          }
 457          return false;
 458      }
 459  
 460      /*!
 461       \static
 462       Generates the cache which will be used for handling optimized processing using the key \a $key.
 463       \note Each call to this will set the PHP time limit to 30
 464       \return false if the cache does not exist.
 465      */
 466      function compileTemplate( &$tpl, $key, &$resourceData )
 467      {
 468          if ( !eZTemplateCompiler::isCompilationEnabled() )
 469              return false;
 470  
 471          $resourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
 472  
 473          $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $resourceData );
 474          $resourceData['uniqid'] = md5( $resourceData['template-filename']. uniqid( "ezp". getmypid(), true ) );
 475  
 476          // Time limit #1:
 477          // We reset the time limit to 30 seconds to ensure that templates
 478          // have enough time to compile
 479          // However if time limit is unlimited (0) we leave it be
 480          // Time limit will also be reset after subtemplates are compiled
 481          $maxExecutionTime = ini_get( 'max_execution_time' );
 482          if ( $maxExecutionTime != 0 && $maxExecutionTime < 30 )
 483          {
 484              @set_time_limit( 30 );
 485          }
 486  
 487          $rootNode =& $resourceData['root-node'];
 488          if ( !$rootNode )
 489              return false;
 490  
 491          include_once ( 'lib/eztemplate/classes/eztemplatenodetool.php' );
 492          include_once ( 'lib/ezutils/classes/ezphpcreator.php' );
 493  
 494          $GLOBALS['eZTemplateCompilerResourceCache'][$resourceData['template-filename']] =& $resourceData;
 495  
 496          $useComments = eZTemplateCompiler::isCommentsEnabled();
 497  
 498          if ( !$resourceData['test-compile'] )
 499          {
 500              eZTemplateCompiler::createCommonCompileTemplate();
 501          }
 502  
 503          /* Check if we need to disable the generation of spacing for the compiled templates */
 504          $ini =& eZINI::instance();
 505          $spacing = 'disabled';
 506          if ( $ini->variable( 'TemplateSettings', 'UseFormatting' ) == 'enabled' )
 507          {
 508              $spacing = 'enabled';
 509          }
 510  
 511          $php = new eZPHPCreator( eZTemplateCompiler::compilationDirectory(), $cacheFileName,
 512                                   eZTemplateCompiler::TemplatePrefix(), array( 'spacing' => $spacing ) );
 513          $php->addComment( 'URI:       ' . $resourceData['uri'] );
 514          $php->addComment( 'Filename:  ' . $resourceData['template-filename'] );
 515          $php->addComment( 'Timestamp: ' . $resourceData['time-stamp'] . ' (' . date( 'D M j G:i:s T Y', $resourceData['time-stamp'] ) . ')' );
 516  
 517          $php->addCodePiece("\$oldSetArray_{$resourceData['uniqid']} = isset( \$setArray ) ? \$setArray : array();\n".
 518                             "\$setArray = array();\n");
 519  // Code to decrement include level of the templates
 520          $php->addCodePiece( "\$tpl->Level++;\n" );
 521          $php->addCodePiece( "if ( \$tpl->Level > $tpl->MaxLevel )\n".
 522                              "{\n".
 523                              "\$text = \$tpl->MaxLevelWarning;".
 524                              "\$tpl->Level--;\n".
 525                              "return;\n".
 526                              "}\n" );
 527          if ( $resourceData['locales'] && count( $resourceData['locales'] ) )
 528          {
 529              $php->addComment( 'Locales:   ' . join( ', ', $resourceData['locales'] ) );
 530  
 531              $php->addCodePiece(
 532                  '$locales = array( "'. join( '", "', $resourceData['locales'] ) . "\" );\n".
 533                  '$oldLocale_'. $resourceData['uniqid']. ' = setlocale( LC_CTYPE, null );'. "\n".
 534                  '$currentLocale_'. $resourceData['uniqid']. ' = setlocale( LC_CTYPE, $locales );'. "\n"
 535              );
 536          }
 537  //         $php->addCodePiece( "print( \"" . $resourceData['template-filename'] . " ($cacheFileName)<br/>\n\" );" );
 538          if ( $useComments )
 539          {
 540              $templateFilename = $resourceData['template-filename'];
 541              if ( file_exists( $templateFilename ) )
 542              {
 543                  $fd = fopen( $templateFilename, 'rb' );
 544                  if ( $fd )
 545                  {
 546                      $templateText = fread( $fd, filesize( $templateFilename ) );
 547                      $php->addComment( "Original code:\n" . $templateText );
 548                      fclose( $fd );
 549                  }
 550              }
 551          }
 552          $php->addVariable( 'eZTemplateCompilerCodeDate', EZ_TEMPLATE_COMPILE_CODE_DATE );
 553          $php->addCodePiece( "if ( !defined( 'EZ_TEMPLATE_COMPILER_COMMON_CODE' ) )\n" );
 554          $php->addInclude( eZTemplateCompiler::compilationDirectory() . '/common.php', EZ_PHPCREATOR_INCLUDE_ONCE, array( 'spacing' => 4 ) );
 555          $php->addSpace();
 556  
 557          if ( eZTemplateCompiler::isAccumulatorsEnabled() )
 558              $php->addCodePiece( "eZDebug::accumulatorStart( 'template_compiled_execution', 'template_total', 'Template compiled execution', true );\n" );
 559          if ( eZTemplateCompiler::isTimingPointsEnabled() )
 560              $php->addCodePiece( "eZDebug::addTimingPoint( 'Script start $cacheFileName' );\n" );
 561  
 562  //         $php->addCodePiece( "if ( !isset( \$vars ) )\n    \$vars =& \$tpl->Variables;\n" );
 563  //         $php->addSpace();
 564  
 565          $parameters = array();
 566          $textName = eZTemplateCompiler::currentTextName( $parameters );
 567  
 568  //         $php->addCodePiece( "if ( !isset( \$$textName ) )\n    \$$textName = '';\n" );
 569  //         $php->addSpace();
 570  
 571  //         $variableStats = array();
 572  //         eZTemplateCompiler::prepareVariableStatistics( $tpl, $resourceData, $variableStats );
 573  //         eZTemplateCompiler::calculateVariableStatistics( $tpl, $rootNode, $resourceData, $variableStats );
 574  //         print_r( $variableStats );
 575  
 576          $transformedTree = array();
 577          eZTemplateCompiler::processNodeTransformation( $useComments, $php, $tpl, $rootNode, $resourceData, $transformedTree );
 578  
 579          if ( $ini->variable( 'TemplateSettings', 'TemplateOptimization' ) == 'enabled' )
 580          {
 581              require_once  ('lib/eztemplate/classes/eztemplateoptimizer.php');
 582              /* Retrieve class information for the attribute lookup table */
 583              if ( isset( $resourceData['handler']->Keys ) and isset( $resourceData['handler']->Keys['class'] ) ) {
 584                  $resourceData['class-info'] = eZTemplateOptimizer::fetchClassDeclaration( $resourceData['handler']->Keys['class'] );
 585              }
 586              /* Run the optimizations */
 587              eZTemplateOptimizer::optimize( $useComments, $php, $tpl, $transformedTree, $resourceData );
 588          }
 589  
 590          $staticTree = array();
 591          eZTemplateCompiler::processStaticOptimizations( $useComments, $php, $tpl, $transformedTree, $resourceData, $staticTree );
 592  
 593          $combinedTree = array();
 594          eZTemplateCompiler::processNodeCombining( $useComments, $php, $tpl, $staticTree, $resourceData, $combinedTree );
 595  
 596          $finalTree = $combinedTree;
 597          if ( !eZTemplateCompiler::isNodePlacementEnabled() )
 598              eZTemplateCompiler::processRemoveNodePlacement( $finalTree );
 599  
 600          eZTemplateCompiler::generatePHPCode( $useComments, $php, $tpl, $finalTree, $resourceData );
 601  
 602          if ( eZTemplateCompiler::isTreeEnabled( 'final' ) )
 603              $php->addVariable( 'finalTree', $finalTree, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
 604          if ( eZTemplateCompiler::isTreeEnabled( 'combined' ) )
 605              $php->addVariable( 'combinedTree', $combinedTree, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
 606          if ( eZTemplateCompiler::isTreeEnabled( 'static' ) )
 607              $php->addVariable( 'staticTree', $staticTree, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
 608          if ( eZTemplateCompiler::isTreeEnabled( 'transformed' ) )
 609              $php->addVariable( 'transformedTree', $transformedTree, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
 610          if ( eZTemplateCompiler::isTreeEnabled( 'original' ) )
 611              $php->addVariable( 'originalTree', $rootNode, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'full-tree' => true ) );
 612  
 613          if ( eZTemplateCompiler::isTimingPointsEnabled() )
 614              $php->addCodePiece( "eZDebug::addTimingPoint( 'Script end $cacheFileName' );\n" );
 615          if ( eZTemplateCompiler::isAccumulatorsEnabled() )
 616              $php->addCodePiece( "eZDebug::accumulatorStop( 'template_compiled_execution', true );\n" );
 617  
 618          if ( $resourceData['locales'] && count( $resourceData['locales'] ) )
 619          {
 620              $php->addCodePiece(
 621                  'setlocale( LC_CTYPE, $oldLocale_'. $resourceData['uniqid']. ' );'. "\n"
 622              );
 623          }
 624          $php->addCodePiece('$setArray = $oldSetArray_'. $resourceData['uniqid']. ";\n");
 625  
 626  // Code to decrement include level of the templates
 627          $php->addCodePiece("\$tpl->Level--;\n" );
 628  
 629          /*
 630          // dump names of all defined PHP variables
 631          $php->addCodePiece( "echo \"defined vars in $resourceData[uri]:<br/><pre>\\n\";\n" );
 632          $php->addCodePiece( 'foreach ( array_keys( get_defined_vars() ) as $var_name  ) echo "- $var_name\n";' );
 633          // dump tpl vars
 634          $php->addCodePiece( 'echo "\n-----------------------------------------------------------\nvars: ";' );
 635          $php->addCodePiece( 'var_dump( $vars );' );
 636          $php->addCodePiece( 'echo "</pre><hr/>\n";' );
 637          */
 638  
 639          if ( !$resourceData['test-compile'] )
 640          {
 641              $php->store( true );
 642          }
 643  
 644          return true;
 645      }
 646  
 647      function prepareVariableStatistics( &$tpl, &$resourceData, &$stats )
 648      {
 649  //         $path = $resourceData['template-filename'];
 650  //         $info =& $GLOBALS['eZTemplateCompileVariableInfo'][$path];
 651          if ( isset( $resourceData['variable-info'] ) )
 652          {
 653          }
 654      }
 655  
 656      /*!
 657      */
 658      function calculateVariableStatistics( &$tpl, &$node, &$resourceData, &$stats )
 659      {
 660          $nodeType = $node[0];
 661          if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
 662          {
 663              $children = $node[1];
 664              $namespace = '';
 665              if ( $children )
 666              {
 667                  eZTemplateCompiler::calculateVariableStatisticsChildren( $tpl, $children, $resourceData, $namespace, $stats );
 668              }
 669          }
 670          else
 671              $tpl->error( 'calculateVariableStatistics', "Unknown root type $nodeType, should be " . EZ_TEMPLATE_NODE_ROOT );
 672      }
 673  
 674      function calculateVariableStatisticsChildren( &$tpl, &$nodeChildren, &$resourceData, $namespace, &$stats )
 675      {
 676          foreach ( $nodeChildren as $node )
 677          {
 678              if ( !isset( $node[0] ) )
 679                  continue;
 680              $nodeType = $node[0];
 681              if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
 682              {
 683                  $children = $node[1];
 684                  if ( $children )
 685                  {
 686                      eZTemplateCompiler::calculateVariableStatisticsChildren( $tpl, $children, $resourceData, $namespace, $stats );
 687                  }
 688              }
 689              else if ( $nodeType == EZ_TEMPLATE_NODE_TEXT )
 690              {
 691                  $text = $node[2];
 692                  $placement = $node[3];
 693              }
 694              else if ( $nodeType == EZ_TEMPLATE_NODE_VARIABLE )
 695              {
 696                  $variableData = $node[2];
 697                  $variablePlacement = $node[3];
 698                  $variableParameters = false;
 699                  eZTemplateCompiler::calculateVariableNodeStatistics( $tpl, $variableData, $variablePlacement, $resourceData, $namespace, $stats );
 700              }
 701              else if ( $nodeType == EZ_TEMPLATE_NODE_FUNCTION )
 702              {
 703                  $functionChildren = $node[1];
 704                  $functionName = $node[2];
 705                  $functionParameters = $node[3];
 706                  $functionPlacement = $node[4];
 707  
 708                  if ( !isset( $tpl->Functions[$functionName] ) )
 709                      continue;
 710  
 711                  if ( is_array( $tpl->Functions[$functionName] ) )
 712                  {
 713                      $tpl->loadAndRegisterOperators( $tpl->Functions[$functionName] );
 714                  }
 715                  $functionObject =& $tpl->Functions[$functionName];
 716                  if ( is_object( $functionObject ) )
 717                  {
 718                      $hasTransformationSupport = false;
 719                      $transformChildren = true;
 720                      if ( method_exists( $functionObject, 'functionTemplateStatistics' ) )
 721                      {
 722                          $functionObject->functionTemplateStatistics( $functionName, $node, $tpl, $resourceData, $namespace, $stats );
 723                      }
 724                  }
 725                  else if ( $resourceData['test-compile'] )
 726                  {
 727                      $tpl->warning( '', "Operator '$operatorName' is not registered.", $functionPlacement );
 728                  }
 729              }
 730          }
 731      }
 732  
 733      function calculateVariableNodeStatistics( &$tpl, $variableData, $variablePlacement, &$resourceData, $namespace, &$stats )
 734      {
 735          if ( !is_array( $variableData ) )
 736              return false;
 737          foreach ( $variableData as $variableItem )
 738          {
 739              $variableItemType = $variableItem[0];
 740              $variableItemData = $variableItem[1];
 741              $variableItemPlacement = $variableItem[2];
 742              if ( $variableItemType == EZ_TEMPLATE_TYPE_STRING or
 743                   $variableItemType == EZ_TEMPLATE_TYPE_IDENTIFIER )
 744              {
 745              }
 746              else if ( $variableItemType == EZ_TEMPLATE_TYPE_NUMERIC )
 747              {
 748              }
 749              else if ( $variableItemType == EZ_TEMPLATE_TYPE_ARRAY )
 750              {
 751              }
 752              else if ( $variableItemType == EZ_TEMPLATE_TYPE_BOOLEAN )
 753              {
 754              }
 755              else if ( $variableItemType == EZ_TEMPLATE_TYPE_VARIABLE )
 756              {
 757                  $variableNamespace = $variableItemData[0];
 758                  $variableNamespaceScope = $variableItemData[1];
 759                  $variableName = $variableItemData[2];
 760                  if ( $variableNamespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_GLOBAL )
 761                      $newNamespace = $variableNamespace;
 762                  else if ( $variableNamespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_LOCAL )
 763                      $newNamespace = $variableNamespace;
 764                  else if ( $variableNamespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_RELATIVE )
 765                      $newNamespace = $tpl->mergeNamespace( $namespace, $variableNamespace );
 766                  else
 767                      $newNamespace = false;
 768                  eZTemplateCompiler::setVariableStatistics( $stats, $newNamespace, $variableName, array( 'is_accessed' => true ) );
 769              }
 770              else if ( $variableItemType == EZ_TEMPLATE_TYPE_ATTRIBUTE )
 771              {
 772                  eZTemplateCompiler::calculateVariableNodeStatistics( $tpl, $variableItemData, $variableItemPlacement, $resourceData, $namespace, $stats );
 773              }
 774              else if ( $variableItemType == EZ_TEMPLATE_TYPE_OPERATOR )
 775              {
 776                  $operatorName = $variableItemData[0];
 777  
 778                  if ( !isset( $tpl->Operators[$operatorName] ) )
 779                      continue;
 780  
 781                  if ( is_array( $tpl->Operators[$operatorName] ) )
 782                  {
 783                      $tpl->loadAndRegisterOperators( $tpl->Operators[$operatorName] );
 784                  }
 785                  $operator =& $tpl->Operators[$operatorName];
 786  
 787                  if ( is_object( $operator ) )
 788                  {
 789                      $hasStats = false;
 790                      if ( method_exists( $operator, 'operatorTemplateHints' ) )
 791                      {
 792                          $hints = $operator->operatorTemplateHints();
 793                          if ( isset( $hints[$operatorName] ) )
 794                          {
 795                              $operatorHints = $hints[$operatorName];
 796                              $hasParameters = false;
 797                              if ( isset( $operatorHints['parameters'] ) )
 798                                  $hasParameters = $operatorHints['parameters'];
 799                              if ( $hasParameters === true )
 800                              {
 801                                  $parameters = $variableItemData;
 802                                  $count = count( $parameters ) - 1;
 803                                  for ( $i = 0; $i < $count; ++$i )
 804                                  {
 805                                      $parameter =& $parameters[$i + 1];
 806                                      $parameterData = $parameter[1];
 807                                      $parameterPlacement = $parameter[2];
 808                                      eZTemplateCompiler::calculateVariableNodeStatistics( $tpl, $parameter, $parameterPlacement,
 809                                                                                           $resourceData, $namespace, $stats );
 810                                  }
 811                              }
 812                              else if ( is_integer( $hasParameters ) )
 813                              {
 814                                  $parameters = $variableItemData;
 815                                  $count = min( count( $parameters ) - 1, $hasParameters );
 816                                  for ( $i = 0; $i < $count; ++$i )
 817                                  {
 818                                      $parameter =& $parameters[$i + 1];
 819                                      $parameterData = $parameter[1];
 820                                      $parameterPlacement = $parameter[2];
 821                                      eZTemplateCompiler::calculateVariableNodeStatistics( $tpl, $parameter, $parameterPlacement,
 822                                                                                           $resourceData, $namespace, $stats );
 823                                  }
 824                              }
 825                              $hasStats = true;
 826                          }
 827                      }
 828                      if ( !$hasStats and method_exists( $operator, 'operatorTemplateStatistics' ) )
 829                      {
 830                          $hasStats = $operator->operatorTemplateStatistics( $operatorName, $variableItem, $variablePlacement, $tpl, $resourceData, $namespace, $stats );
 831                      }
 832                      if ( !$hasStats and method_exists( $operator, 'namedParameterList' ) )
 833                      {
 834                          $namedParameterList = $operator->namedParameterList();
 835                          if ( method_exists( $operator, 'namedParameterPerOperator' ) and
 836                               $operator->namedParameterPerOperator() )
 837                          {
 838                              $namedParameterList = $namedParameterList[$operatorName];
 839                          }
 840                          $operatorParameters = array_slice( $variableItemData, 1 );
 841                          $count = 0;
 842                          foreach ( $namedParameterList as $parameterName => $parameterDefinition )
 843                          {
 844                              $operatorParameter = $operatorParameters[$count];
 845                              eZTemplateCompiler::calculateVariableNodeStatistics( $tpl, $operatorParameter, $variablePlacement, $resourceData, $namespace, $stats );
 846                              ++$count;
 847                          }
 848                          $hasStats = true;
 849                      }
 850                  }
 851                  else if ( $resourceData['test-compile'] )
 852                  {
 853                      $tpl->warning( '', "Operator '$operatorName' is not registered." );
 854                  }
 855              }
 856              else if ( $variableItemType == EZ_TEMPLATE_TYPE_VOID )
 857              {
 858                  $tpl->warning( 'TemplateCompiler::calculateOperatorStatistics', "Void datatype should not be used, ignoring it" );
 859              }
 860              else
 861              {
 862                  $tpl->warning( 'TemplateCompiler::calculateOperatorStatistics', "Unknown data type $variableItemType, ignoring it" );
 863              }
 864          }
 865          return true;
 866      }
 867  
 868      function setVariableStatistics( &$stats, $namespace, $variableName, $changes )
 869      {
 870          if ( isset( $stats['variables'][$namespace][$variableName] ) )
 871          {
 872              $variableStats =& $stats['variables'][$namespace][$variableName];
 873          }
 874          else
 875          {
 876              $variableStats = array( 'is_accessed' => false,
 877                                      'is_created' => false,
 878                                      'is_modified' => false,
 879                                      'is_removed' => false,
 880                                      'is_local' => false,
 881                                      'is_input' => false,
 882                                      'namespace' => $namespace,
 883                                      'namespace_scope' => false,
 884                                      'type' => false );
 885              $stats['variables'][$namespace][$variableName] =& $variableStats;
 886          }
 887          if ( isset( $changes['invalid_access'] ) and $changes['invalid_access'] !== false )
 888              $variableStats['invalid_access'] = $changes['invalid_access'];
 889          if ( isset( $changes['is_accessed'] ) and $changes['is_accessed'] !== false )
 890              $variableStats['is_accessed'] = $changes['is_accessed'];
 891          if ( isset( $changes['is_created'] ) and $changes['is_created'] !== false )
 892              $variableStats['is_created'] = $changes['is_created'];
 893          if ( isset( $changes['is_modified'] ) and $changes['is_modified'] !== false )
 894              $variableStats['is_modified'] = $changes['is_modified'];
 895          if ( isset( $changes['is_removed'] ) and $changes['is_removed'] !== false )
 896              $variableStats['is_removed'] = $changes['is_removed'];
 897          if ( isset( $changes['is_local'] ) and $changes['is_local'] !== false )
 898              $variableStats['is_local'] = $changes['is_local'];
 899          if ( isset( $changes['is_input'] ) and $changes['is_input'] !== false )
 900              $variableStats['is_input'] = $changes['is_input'];
 901          if ( isset( $changes['namespace'] ) )
 902              $variableStats['namespace'] = $changes['namespace'];
 903          if ( isset( $changes['namespace_scope'] ) )
 904              $variableStats['namespace_scope'] = $changes['namespace_scope'];
 905          if ( isset( $changes['type'] ) )
 906              $variableStats['type'] = $changes['type'];
 907      }
 908  
 909      /*!
 910       Iterates over the template node tree and tries to combine multiple static siblings
 911       into one element. The original tree is specified in \a $node and the new
 912       combined tree will be present in \a $newNode.
 913       \sa processNodeCombiningChildren
 914      */
 915      function processNodeCombining( $useComments, &$php, &$tpl, &$node, &$resourceData, &$newNode )
 916      {
 917          $nodeType = $node[0];
 918          if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
 919          {
 920              $children = $node[1];
 921              $newNode[0] = $nodeType;
 922              $newNode[1] = false;
 923              if ( $children )
 924              {
 925                  eZTemplateCompiler::processNodeCombiningChildren( $useComments, $php, $tpl, $children, $resourceData, $newNode );
 926              }
 927          }
 928          else
 929              $tpl->error( 'processNodeCombining', "Unknown root type $nodeType, should be " . EZ_TEMPLATE_NODE_ROOT );
 930      }
 931  
 932      /*!
 933       Does node combining on the children \a $nodeChildren.
 934       \sa processNodeCombining
 935      */
 936      function processNodeCombiningChildren( $useComments, &$php, &$tpl, &$nodeChildren, &$resourceData, &$parentNode )
 937      {
 938          $newNodeChildren = array();
 939          $lastNode = false;
 940          foreach ( $nodeChildren as $node )
 941          {
 942              $newNode = false;
 943              if ( !isset( $node[0] ) )
 944                  continue;
 945              $nodeType = $node[0];
 946              if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
 947              {
 948                  $children = $node[1];
 949                  $newNode = array( $nodeType,
 950                                    false );
 951                  if ( $children )
 952                  {
 953                      eZTemplateCompiler::processNodeCombiningChildren( $useComments, $php, $tpl, $children, $resourceData, $newNode );
 954                  }
 955              }
 956              else if ( $nodeType == EZ_TEMPLATE_NODE_TEXT )
 957              {
 958                  $text = $node[2];
 959                  $placement = $node[3];
 960  
 961                  $newNode = array( $nodeType,
 962                                    false,
 963                                    $text,
 964                                    $placement );
 965                  eZTemplateCompiler::combineStaticNodes( $tpl, $resourceData, $lastNode, $newNode );
 966              }
 967              else if ( $nodeType == EZ_TEMPLATE_NODE_VARIABLE )
 968              {
 969                  $variableCustom = $node[1];
 970                  $variableData = $node[2];
 971                  $variablePlacement = $node[3];
 972                  $variableParameters = false;
 973                  $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
 974                                                                             $variableData, $variablePlacement,
 975                                                                             $resourceData );
 976                  $newNode = $node;
 977                  $newNode[1] = $variableCustom;
 978                  unset( $dataInspection );
 979                  eZTemplateCompiler::combineStaticNodes( $tpl, $resourceData, $lastNode, $newNode );
 980              }
 981              else if ( $nodeType == EZ_TEMPLATE_NODE_FUNCTION )
 982              {
 983                  $functionChildren = $node[1];
 984                  $functionName = $node[2];
 985                  $functionParameters = $node[3];
 986                  $functionPlacement = $node[4];
 987  
 988                  $newNode = array( $nodeType,
 989                                    false,
 990                                    $functionName,
 991                                    $functionParameters,
 992                                    $functionPlacement );
 993                  if ( isset( $node[5] ) )
 994                      $newNode[5] = $node[5];
 995  
 996                  if ( is_array( $functionChildren ) )
 997                  {
 998                      eZTemplateCompiler::processNodeCombiningChildren( $useComments, $php, $tpl,
 999                                                                            $functionChildren, $resourceData, $newNode );
1000                  }
1001  
1002              }
1003              else
1004                  $newNode = $node;
1005              if ( $lastNode != false )
1006              {
1007                  $newNodeChildren[] = $lastNode;
1008                  $lastNode = false;
1009              }
1010              if ( $newNode != false )
1011                  $lastNode = $newNode;
1012          }
1013          if ( $lastNode != false )
1014          {
1015              $newNodeChildren[] = $lastNode;
1016              $lastNode = false;
1017          }
1018          $parentNode[1] = $newNodeChildren;
1019      }
1020  
1021      /*!
1022       Tries to combine the node \a $lastNode and the node \a $newNode
1023       into one new text node. If possible the new node is created in \a $newNode
1024       and \a $lastNode will be set to \c false.
1025       Combining nodes only works for text nodes and variable nodes without
1026       variable lookup, attributes and operators.
1027      */
1028      function combineStaticNodes( &$tpl, &$resourceData, &$lastNode, &$newNode )
1029      {
1030          if ( $lastNode == false or
1031               $newNode == false )
1032              return false;
1033          $lastNodeType = $lastNode[0];
1034          $newNodeType = $newNode[0];
1035          if ( !in_array( $lastNodeType, array( EZ_TEMPLATE_NODE_TEXT,
1036                                                EZ_TEMPLATE_NODE_VARIABLE ) ) or
1037               !in_array( $newNodeType, array( EZ_TEMPLATE_NODE_TEXT,
1038                                               EZ_TEMPLATE_NODE_VARIABLE ) ) )
1039              return false;
1040          if ( $lastNodeType == EZ_TEMPLATE_NODE_VARIABLE )
1041          {
1042              if ( is_array( $lastNode[1] ) )
1043                  return false;
1044              $lastDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
1045                                                                             $lastNode[2], $lastNode[3],
1046                                                                             $resourceData );
1047              if ( !$lastDataInspection['is-constant'] or
1048                   $lastDataInspection['is-variable'] or
1049                   $lastDataInspection['has-attributes'] or
1050                   $lastDataInspection['has-operators'] )
1051                  return false;
1052              if ( isset( $lastNode[4] ) and
1053                   isset( $lastNode[4]['text-result'] ) and
1054                   !$lastNode[4]['text-result'] )
1055                  return false;
1056          }
1057          if ( $newNodeType == EZ_TEMPLATE_NODE_VARIABLE )
1058          {
1059              if ( is_array( $newNode[1] ) )
1060                  return false;
1061              $newDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
1062                                                                            $newNode[2], $newNode[3],
1063                                                                            $resourceData );
1064              if ( !$newDataInspection['is-constant'] or
1065                   $newDataInspection['is-variable'] or
1066                   $newDataInspection['has-attributes'] or
1067                   $newDataInspection['has-operators'] )
1068                  return false;
1069              if ( isset( $newNode[4] ) and
1070                   isset( $newNode[4]['text-result'] ) and
1071                   !$newNode[4]['text-result'] )
1072                  return false;
1073              if ( isset( $newNode[1] ) and
1074                   $newNode[1] !== false )
1075                  return false;
1076          }
1077          $textElements = array();
1078          $lastNodeData = eZTemplateCompiler::staticNodeData( $lastNode );
1079          $newNodeData = eZTemplateCompiler::staticNodeData( $newNode );
1080          $tpl->appendElementText( $textElements, $lastNodeData, false, false );
1081          $tpl->appendElementText( $textElements, $newNodeData, false, false );
1082          $newData = implode( '', $textElements );
1083          $newPlacement = $lastNode[3];
1084          if ( !is_array( $newPlacement ) )
1085          {
1086              $newPlacement = $newNode[3];
1087          }
1088          else
1089          {
1090              $newPlacement[1][0] = $newNode[3][1][0]; // Line end
1091              $newPlacement[1][1] = $newNode[3][1][1]; // Column end
1092              $newPlacement[1][2] = $newNode[3][1][2]; // Position end
1093          }
1094          $lastNode = false;
1095          $newNode = array( EZ_TEMPLATE_NODE_TEXT,
1096                            false,
1097                            $newData,
1098                            $newPlacement );
1099      }
1100  
1101      /*!
1102       \return the static data for the node \a $node or \c false if
1103               no data could be fetched.
1104               Will only return data from text nodes and variables nodes
1105               without variable lookup, attribute lookup or operators.
1106      */
1107      function staticNodeData( $node )
1108      {
1109          $nodeType = $node[0];
1110          if ( $nodeType == EZ_TEMPLATE_NODE_TEXT )
1111          {
1112              return $node[2];
1113          }
1114          else if ( $nodeType == EZ_TEMPLATE_NODE_VARIABLE )
1115          {
1116              $data = $node[2];
1117              if ( is_array( $data ) and
1118                   count( $data ) > 0 )
1119              {
1120                  $dataType = $data[0][0];
1121                  if ( $dataType == EZ_TEMPLATE_TYPE_STRING or
1122                       $dataType == EZ_TEMPLATE_TYPE_NUMERIC or
1123                       $dataType == EZ_TEMPLATE_TYPE_IDENTIFIER or
1124                       $dataType == EZ_TEMPLATE_TYPE_ARRAY or
1125                       $dataType == EZ_TEMPLATE_TYPE_BOOLEAN )
1126                  {
1127                      return $data[0][1];
1128                  }
1129              }
1130          }
1131          return null;
1132      }
1133  
1134      /*!
1135       Iterates over the items in the tree \a $node and tries to extract static data
1136       from operators which supports it.
1137      */
1138      function processStaticOptimizations( $useComments, &$php, &$tpl, &$node, &$resourceData, &$newNode )
1139      {
1140          $nodeType = $node[0];
1141          if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
1142          {
1143              $children = $node[1];
1144              $newNode[0] = $nodeType;
1145              $newNode[1] = false;
1146              if ( $children )
1147              {
1148                  $newNode[1] = array();
1149                  foreach ( $children as $child )
1150                  {
1151                      $newChild = array();
1152                      eZTemplateCompiler::processStaticOptimizations( $useComments, $php, $tpl, $child, $resourceData, $newChild );
1153                      $newNode[1][] = $newChild;
1154                  }
1155              }
1156          }
1157          else if ( $nodeType == EZ_TEMPLATE_NODE_TEXT )
1158          {
1159              $text = $node[2];
1160              $placement = $node[3];
1161  
1162              $newNode[0] = $nodeType;
1163              $newNode[1] = false;
1164              $newNode[2] = $text;
1165              $newNode[3] = $placement;
1166          }
1167          else if ( $nodeType == EZ_TEMPLATE_NODE_VARIABLE )
1168          {
1169              $variableCustom = $node[1];
1170              $variableData = $node[2];
1171              $variablePlacement = $node[3];
1172              $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
1173                                                                         $variableData, $variablePlacement,
1174                                                                         $resourceData );
1175              if ( isset( $dataInspection['new-data'] ) )
1176              {
1177                  $variableData = $dataInspection['new-data'];
1178              }
1179              $newNode = $node;
1180              $newNode[1] = $variableCustom;
1181              $newNode[2] = $variableData;
1182              unset( $dataInspection );
1183          }
1184          else if ( $nodeType == EZ_TEMPLATE_NODE_FUNCTION )
1185          {
1186              $functionChildren = $node[1];
1187              $functionName = $node[2];
1188              $functionParameters = $node[3];
1189              $functionPlacement = $node[4];
1190  
1191              $newFunctionChildren = array();
1192              if ( is_array( $functionChildren ) )
1193              {
1194                  foreach ( $functionChildren as $functionChild )
1195                  {
1196                      $newChild = array();
1197                      eZTemplateCompiler::processStaticOptimizations( $useComments, $php, $tpl,
1198                                                                          $functionChild, $resourceData, $newChild );
1199                      $newFunctionChildren[] = $newChild;
1200                  }
1201                  $functionChildren = $newFunctionChildren;
1202              }
1203  
1204              $newFunctionParameters = array();
1205              if ( $functionParameters )
1206              {
1207                  foreach ( $functionParameters as $functionParameterName => $functionParameterData )
1208                  {
1209                      $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
1210                                                                                     $functionParameterData, false,
1211                                                                                     $resourceData );
1212                      if ( isset( $dataInspection['new-data'] ) )
1213                      {
1214                          $functionParameterData = $dataInspection['new-data'];
1215                      }
1216                      $newFunctionParameters[$functionParameterName] = $functionParameterData;
1217                  }
1218                  $functionParameters = $newFunctionParameters;
1219              }
1220  
1221              $newNode[0] = $nodeType;
1222              $newNode[1] = $functionChildren;
1223              $newNode[2] = $functionName;
1224              $newNode[3] = $functionParameters;
1225              $newNode[4] = $functionPlacement;
1226              if ( isset( $node[5] ) )
1227                  $newNode[5] = $node[5];
1228          }
1229          else
1230              $newNode = $node;
1231      }
1232  
1233      /*!
1234       Iterates over the template node tree \a $node and returns a new transformed
1235       tree in \a $newNode.
1236       \sa processNodeTransformationRoot, processNodeTransformationChild
1237      */
1238      function processNodeTransformation( $useComments, &$php, &$tpl, &$node, &$resourceData, &$newNode )
1239      {
1240          $newNode = eZTemplateCompiler::processNodeTransformationRoot( $useComments, $php, $tpl, $node, $resourceData );
1241      }
1242  
1243      /*!
1244       Iterates over the nodes \a $nodes and does transformation on them.
1245       \sa processNodeTransformationChildren
1246       \note This method can be called from operator and functions as long as they have the \a $privateData parameter.
1247      */
1248      function processNodeTransformationNodes( &$tpl, &$node, &$nodes, &$privateData )
1249      {
1250          $useComments = $privateData['use-comments'];
1251          $php =& $privateData['php-creator'];
1252          $resourceData =& $privateData['resource-data'];
1253          return eZTemplateCompiler::processNodeTransformationChildren( $useComments, $php, $tpl, $node, $nodes, $resourceData );
1254      }
1255  
1256      /*!
1257       Iterates over the children \a $children and does transformation on them.
1258       \sa processNodeTransformation, processNodeTransformationChild
1259      */
1260      function processNodeTransformationChildren( $useComments, &$php, &$tpl, &$node, &$children, &$resourceData )
1261      {
1262          if ( $children )
1263          {
1264              $newChildren = array();
1265              foreach ( $children as $childNode )
1266              {
1267                  $newChildNode = eZTemplateCompiler::processNodeTransformationChild( $useComments, $php, $tpl, $childNode, $resourceData );
1268                  if ( !$newChildNode )
1269                      $newChildren[] = $childNode;
1270                  else
1271                      $newChildren = array_merge( $newChildren, $newChildNode );
1272              }
1273              if ( count( $newChildren ) > 0 )
1274                  return $newChildren;
1275          }
1276          return $children;
1277      }
1278  
1279      /*!
1280       Iterates over the children of the root node \a $node and does transformation on them.
1281       \sa processNodeTransformation, processNodeTransformationChild
1282      */
1283      function processNodeTransformationRoot( $useComments, &$php, &$tpl, &$node, &$resourceData )
1284      {
1285          $nodeType = $node[0];
1286          if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
1287          {
1288              $children = $node[1];
1289              $newNode = array( $nodeType,
1290                                false );
1291              if ( $children )
1292              {
1293                  $newChildren = array();
1294                  foreach ( $children as $childNode )
1295                  {
1296                      $newChildNode = eZTemplateCompiler::processNodeTransformationChild( $useComments, $php, $tpl, $childNode, $resourceData );
1297                      if ( !$newChildNode )
1298                          $newChildren[] = $childNode;
1299                      else
1300                          $newChildren = array_merge( $newChildren, $newChildNode );
1301                  }
1302                  if ( count( $newChildren ) > 0 )
1303                      $newNode[1] = $newChildren;
1304              }
1305              return $newNode;
1306          }
1307          else
1308              $tpl->error( 'processNodeTransformation', "Unknown root type $nodeType, should be " . EZ_TEMPLATE_NODE_ROOT );
1309          return false;
1310      }
1311  
1312      /*!
1313       Iterates over the children of the function node \a $node and transforms the tree.
1314       If the node is not a function it will return \c false.
1315       \sa processNodeTransformationRoot, processNodeTransformationChild
1316      */
1317      function processNodeTransformationChild( $useComments, &$php, &$tpl, &$node, &$resourceData )
1318      {
1319          $nodeType = $node[0];
1320          if ( $nodeType == EZ_TEMPLATE_NODE_FUNCTION )
1321          {
1322              $nodeCopy = $node;
1323              $functionChildren = $node[1];
1324              $functionName = $node[2];
1325              $functionParameters = $node[3];
1326              $functionPlacement = $node[4];
1327              if ( !isset( $tpl->Functions[$functionName] ) )
1328                  return false;
1329  
1330              if ( is_array( $tpl->Functions[$functionName] ) )
1331              {
1332                  $tpl->loadAndRegisterFunctions( $tpl->Functions[$functionName] );
1333              }
1334              $functionObject =& $tpl->Functions[$functionName];
1335              if ( is_object( $functionObject ) )
1336              {
1337                  $hasTransformationSupport = false;
1338                  $transformChildren = true;
1339                  $transformParameters = false;
1340                  if ( method_exists( $functionObject, 'functionTemplateHints' ) )
1341                  {
1342                      $hints = $functionObject->functionTemplateHints();
1343                      if ( isset( $hints[$functionName] ) and
1344                           isset( $hints[$functionName]['tree-transformation'] ) and
1345                           $hints[$functionName]['tree-transformation'] )
1346                          $hasTransformationSupport = true;
1347                      if ( isset( $hints[$functionName] ) and
1348                           isset( $hints[$functionName]['transform-children'] ) )
1349                          $transformChildren = $hints[$functionName]['transform-children'];
1350                      if ( isset( $hints[$functionName] ) and
1351                           isset( $hints[$functionName]['transform-parameters'] ) )
1352                          $transformParameters = $hints[$functionName]['transform-parameters'];
1353                  }
1354                  if ( $hasTransformationSupport and
1355                       method_exists( $functionObject, 'templateNodeTransformation' ) )
1356                  {
1357                      if ( $transformChildren and
1358                           $functionChildren )
1359                      {
1360                          $newChildren = array();
1361                          foreach ( $functionChildren as $childNode )
1362                          {
1363                              $newChildNode = eZTemplateCompiler::processNodeTransformationChild( $useComments, $php, $tpl, $childNode, $resourceData );
1364                              if ( !$newChildNode )
1365                                  $newChildren[] = $childNode;
1366                              else if ( !is_array( $newChildNode ) )
1367                                  $newChildren[] = $newChildNode;
1368                              else
1369                                  $newChildren = array_merge( $newChildren, $newChildNode );
1370                          }
1371                          if ( count( $newChildren ) > 0 )
1372                              $node[1] = $newChildren;
1373                      }
1374  
1375                      if ( $transformParameters and
1376                           $functionParameters )
1377                      {
1378                          $newParameters = array();
1379                          foreach ( $functionParameters as $parameterName => $parameterElementList )
1380                          {
1381                              $elementTree = $parameterElementList;
1382                              $elementList = $elementTree;
1383                              $newParamNode = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
1384                                                                                                     $elementTree, $elementList, $resourceData );
1385                              if ( !$newParamNode || !is_array( $newParamNode ) )
1386                                  $newParameters[$parameterName] = $parameterElementList;
1387                              else
1388                                  $newParameters[$parameterName] = $newParamNode;
1389                          }
1390                          if ( count( $newParameters ) > 0 )
1391                          {
1392                              $node[3] = $newParameters;
1393                              $functionParameters = $newParameters;
1394                          }
1395                      }
1396  
1397                      $privateData = array( 'use-comments' => $useComments,
1398                                            'php-creator' => &$php,
1399                                            'resource-data' => &$resourceData );
1400                      $newNodes = $functionObject->templateNodeTransformation( $functionName, $node,
1401                                                                               $tpl, $functionParameters, $privateData );
1402                      unset( $privateData );
1403                      if ( !$newNodes )
1404                      {
1405                          $node = $nodeCopy;
1406                          $node[1] = $functionChildren;
1407                          return false;
1408                          return $node;
1409                      }
1410                      return $newNodes;
1411                  }
1412              }
1413              else if ( $resourceData['test-compile'] )
1414              {
1415                  $tpl->warning( '', "Function '$functionName' is not registered.", $functionPlacement );
1416              }
1417  
1418              return false;
1419          }
1420          else if ( $nodeType == EZ_TEMPLATE_NODE_VARIABLE )
1421          {
1422              $elementTree = $node[2];
1423              $elementList = $elementTree;
1424  
1425              $newParameterElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
1426                                                                                             $elementTree, $elementList, $resourceData );
1427              if ( $newParameterElements )
1428              {
1429                  $newNode = $node;
1430                  $newNode[2] = $newParameterElements;
1431                  $newNodes = array( $newNode );
1432                  return $newNodes;
1433              }
1434          }
1435          else if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
1436          {
1437              return eZTemplateCompiler::processNodeTransformationRoot( $useComments, $php, $tpl, $node, $resourceData );
1438          }
1439          else
1440              return false;
1441      }
1442  
1443      /*!
1444       Iterates over the element list \a $elements and transforms them.
1445       \sa processElementTransformationChild
1446      */
1447      function processElementTransformationList( &$tpl, &$node, &$elements, &$privateData )
1448      {
1449          $useComments = $privateData['use-comments'];
1450          $php =& $privateData['php-creator'];
1451          $resourceData =& $privateData['resource-data'];
1452          $elementTree = $elements;
1453          $newElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
1454                                                                                $elementTree, $elements, $resourceData );
1455          if ( $newElements )
1456              return $newElements;
1457          return $elements;
1458      }
1459  
1460      /*!
1461       Iterates over the children of the function node \a $node and transforms the tree.
1462       If the node is not a function it will return \c false.
1463       \sa processNodeTransformationRoot, processNodeTransformationChild
1464      */
1465      function processElementTransformationChild( $useComments, &$php, &$tpl, &$node,
1466                                                  &$elementTree, &$elementList, &$resourceData )
1467      {
1468          $count = count( $elementList );
1469          $lastElement = null;
1470          $newElementList = array();
1471          for ( $i = 0; $i < $count; ++$i )
1472          {
1473              $element =& $elementList[$i];
1474              $elementType = $element[0];
1475              if ( $elementType == EZ_TEMPLATE_TYPE_OPERATOR )
1476              {
1477                  $operatorName = $element[1][0];
1478                  $operatorParameters = array_slice( $element[1], 1 );
1479                  if ( !isset( $tpl->Operators[$operatorName] ) )
1480                      return false;
1481  
1482                  if ( is_array( $tpl->Operators[$operatorName] ) )
1483                  {
1484                      $tpl->loadAndRegisterOperators( $tpl->Operators[$operatorName] );
1485                  }
1486                  $operatorObject =& $tpl->Operators[$operatorName];
1487                  if ( is_object( $operatorObject ) )
1488                  {
1489                      $hasTransformationSupport = false;
1490                      $transformParameters = false;
1491                      $inputAsParameter = false;
1492                      $knownType = 'static';
1493                      if ( method_exists( $operatorObject, 'operatorTemplateHints' ) )
1494                      {
1495                          $hints = $operatorObject->operatorTemplateHints();
1496                          if ( isset( $hints[$operatorName] ) and
1497                               isset( $hints[$operatorName]['element-transformation'] ) and
1498                               $hints[$operatorName]['element-transformation'] )
1499                          {
1500                              $hasTransformationSupport = true;
1501                          }
1502  
1503                          if ( $hasTransformationSupport  and
1504                               isset( $hints[$operatorName]['element-transformation-func'] ) )
1505                          {
1506                              $transformationMethod = $hints[$operatorName]['element-transformation-func'];
1507                          }
1508                          else
1509                          {
1510                              $transformationMethod = 'templateElementTransformation';
1511                          }
1512  
1513                          if ( isset( $hints[$operatorName] ) and
1514                               isset( $hints[$operatorName]['transform-parameters'] ) )
1515                          {
1516                              $transformParameters = $hints[$operatorName]['transform-parameters'];
1517                          }
1518  
1519                          if ( isset( $hints[$operatorName] ) and
1520                               isset( $hints[$operatorName]['input-as-parameter'] ) )
1521                          {
1522                              $inputAsParameter = $hints[$operatorName]['input-as-parameter'];
1523                          }
1524  
1525                          if ( isset( $hints[$operatorName]['output'] ) and !$hints[$operatorName]['output'] )
1526                          {
1527                              $knownType = 'null';
1528                          }
1529                          else if ( isset( $hints[$operatorName]['output-type'] ) )
1530                          {
1531                              $knownType = $hints[$operatorName]['output-type'];
1532                          }
1533                      }
1534                      if ( $hasTransformationSupport and
1535                           method_exists( $operatorObject, $transformationMethod ) )
1536                      {
1537                          $resetNewElementList = false;
1538                          if ( $transformParameters )
1539                          {
1540                              $newParameters = array();
1541                              if ( $inputAsParameter )
1542                              {
1543                                  $newParameterElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
1544                                                                                                                 $elementTree, $newElementList, $resourceData );
1545                                  if ( count( $newParameterElements ) > 0 or
1546                                       $inputAsParameter === 'always' )
1547                                  {
1548                                      $newParameters[] = $newParameterElements;
1549                                      $resetNewElementList = true;
1550                                  }
1551                              }
1552  
1553                              foreach ( $operatorParameters as $operatorParameter )
1554                              {
1555                                  $newParameterElements = eZTemplateCompiler::processElementTransformationChild( $useComments, $php, $tpl, $node,
1556                                                                                                                 $elementTree, $operatorParameter, $resourceData );
1557                                  if ( !$newParameterElements )
1558                                      $newParameters[] = $operatorParameter;
1559                                  else
1560                                      $newParameters[] = $newParameterElements;
1561                              }
1562                              $operatorParameters = $newParameters;
1563                          }
1564  
1565                          $newElements = $operatorObject->$transformationMethod( $operatorName, $node, $tpl, $resourceData,
1566                                                                                 $element, $lastElement, $elementList, $elementTree,
1567                                                                                 $operatorParameters );
1568                          if ( is_array( $newElements ) )
1569                          {
1570                              if ( $resetNewElementList )
1571                              {
1572                                  $newElementList = $newElements;
1573                              }
1574                              else
1575                              {
1576                                  $newElementList = array_merge( $newElementList, $newElements );
1577                              }
1578                          }
1579                          else
1580                          {
1581                              $newElementList[] = $element;
1582                          }
1583                      }
1584                      else
1585                      {
1586                          $newElementList[] = $element;
1587                      }
1588                  }
1589                  else if ( $resourceData['test-compile'] )
1590                  {
1591                      $tpl->warning( '', "Operator '$operatorName' is not registered." );
1592                  }
1593              }
1594              else
1595              {
1596                  $newElementList[] = $element;
1597              }
1598              $lastElement = $element;
1599          }
1600          return $newElementList;
1601      }
1602  
1603      /*!
1604       Iterates over the node tree and removes all placement information.
1605      */
1606      function processRemoveNodePlacement( &$node )
1607      {
1608          $nodeType = $node[0];
1609          if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
1610          {
1611              $nodeChildren =& $node[1];
1612              for ( $i = 0; $i < count( $nodeChildren ); ++$i )
1613              {
1614                  $nodeChild =& $nodeChildren[$i];
1615                  eZTemplateCompiler::processRemoveNodePlacement( $nodeChild );
1616              }
1617          }
1618          else if ( $nodeType == EZ_TEMPLATE_NODE_TEXT )
1619          {
1620              $node[3] = false;
1621          }
1622          else if ( $nodeType == EZ_TEMPLATE_NODE_VARIABLE )
1623          {
1624              $node[3] = false;
1625          }
1626          else if ( $nodeType == EZ_TEMPLATE_NODE_FUNCTION )
1627          {
1628              $node[4] = false;
1629              $nodeChildren =& $node[1];
1630              if ( $nodeChildren )
1631              {
1632                  for ( $i = 0; $i < count( $nodeChildren ); ++$i )
1633                  {
1634                      $nodeChild =& $nodeChildren[$i];
1635                      eZTemplateCompiler::processRemoveNodePlacement( $nodeChild );
1636                  }
1637              }
1638          }
1639          else if ( $nodeType == EZ_TEMPLATE_NODE_OPERATOR )
1640          {
1641          }
1642      }
1643  
1644      /*!
1645       Looks over the variable data \a $variableData and returns an array with
1646       information on the structure.
1647       The following entries are generated.
1648       - is-constant - true if the variable data contains constant data like text and numerics
1649       - is-variable - true if the variable data is a variable lookup
1650       - has-operators - true if operators are present
1651       - has-attributes - true if attributes are used
1652      */
1653      function inspectVariableData( &$tpl, $variableData, $variablePlacement, &$resourceData )
1654      {
1655          $dataInspection = array( 'is-constant' => false,
1656                                   'is-variable' => false,
1657                                   'has-operators' => false,
1658                                   'has-attributes' => false );
1659          if ( !is_array( $variableData ) )
1660              return $dataInspection;
1661          $newVariableData = array();
1662          // Static optimizations, the following items are done:
1663          // - Recognize static data
1664          // - Extract static data, if possible, from operators
1665          // - Remove parameters and input which not be used.
1666          foreach ( $variableData as $variableItem )
1667          {
1668              $variableItemType = $variableItem[0];
1669              $variableItemData = $variableItem[1];
1670              $variableItemPlacement = $variableItem[2];
1671              if ( $variableItemType == EZ_TEMPLATE_TYPE_STRING or
1672                   $variableItemType == EZ_TEMPLATE_TYPE_IDENTIFIER )
1673              {
1674                  $dataInspection['is-constant'] = true;
1675                  $dataInspection['is-variable'] = false;
1676                  $newVariableData[] = $variableItem;
1677              }
1678              else if ( $variableItemType == EZ_TEMPLATE_TYPE_NUMERIC )
1679              {
1680                  $dataInspection['is-constant'] = true;
1681                  $dataInspection['is-variable'] = false;
1682                  $newVariableData[] = $variableItem;
1683              }
1684              else if ( $variableItemType == EZ_TEMPLATE_TYPE_BOOLEAN )
1685              {
1686                  $dataInspection['is-constant'] = true;
1687                  $dataInspection['is-variable'] = false;
1688                  $newVariableData[] = $variableItem;
1689              }
1690              else if ( $variableItemType == EZ_TEMPLATE_TYPE_DYNAMIC_ARRAY )
1691              {
1692                  $dataInspection['is-constant'] = false;
1693                  $dataInspection['is-variable'] = true;
1694                  $newVariableData[] = $variableItem;
1695              }
1696              else if ( $variableItemType == EZ_TEMPLATE_TYPE_ARRAY )
1697              {
1698                  $dataInspection['is-constant'] = true;
1699                  $dataInspection['is-variable'] = false;
1700                  $newVariableData[] = $variableItem;
1701              }
1702              else if ( $variableItemType == EZ_TEMPLATE_TYPE_VARIABLE )
1703              {
1704                  $dataInspection['is-constant'] = false;
1705                  $dataInspection['is-variable'] = true;
1706                  $newVariableData[] = $variableItem;
1707              }
1708              else if ( $variableItemType == EZ_TEMPLATE_TYPE_ATTRIBUTE )
1709              {
1710                  $dataInspection['has-attributes'] = true;
1711                  $newDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
1712                                                                                    $variableItemData, $variableItemPlacement,
1713                                                                                    $resourceData );
1714                  if ( isset( $newDataInspection['new-data'] ) )
1715                  {
1716                      $variableItemData = $newDataInspection['new-data'];
1717                  }
1718                  $variableItem[1] = $variableItemData;
1719                  unset( $newDataInspection );
1720                  $newVariableData[] = $variableItem;
1721              }
1722              else if ( $variableItemType == EZ_TEMPLATE_TYPE_OPERATOR )
1723              {
1724                  $dataInspection['has-operators'] = true;
1725                  $operatorName = $variableItemData[0];
1726                  $operatorHint = eZTemplateCompiler::operatorHint( $tpl, $operatorName );
1727                  $newVariableItem = $variableItem;
1728                  if ( $operatorHint and
1729                       isset( $operatorHint['input'] ) and
1730                       isset( $operatorHint['output'] ) and
1731                       isset( $operatorHint['parameters'] ) )
1732                  {
1733                      if ( !$operatorHint['input'] and
1734                           $operatorHint['output'] )
1735                          $newVariableData = array();
1736                      if ( !isset( $operatorHint) or !$operatorHint['parameters'] )
1737                          $newVariableItem[1] = array( $operatorName );
1738                      if ( isset ( $operatorHint['static'] ) and
1739                           $operatorHint['static'] )
1740                      {
1741                          $operatorStaticData = eZTemplateCompiler::operatorStaticData( $tpl, $operatorName );
1742                          $newVariableItem = eZTemplateCompiler::createStaticVariableData( $tpl, $operatorStaticData, $variableItemPlacement );
1743                          $dataInspection['is-constant'] = true;
1744                          $dataInspection['is-variable'] = false;
1745                          $dataInspection['has-operators'] = false;
1746                      }
1747                  }
1748                  if ( $newVariableItem[0] == EZ_TEMPLATE_TYPE_OPERATOR )
1749                  {
1750                      $tmpVariableItem = $newVariableItem[1];
1751                      $newVariableItem[1] = array( $operatorName );
1752                      for ( $i = 1; $i < count( $tmpVariableItem ); ++$i )
1753                      {
1754                          $operatorParameter = $tmpVariableItem[$i];
1755                          $newDataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
1756                                                                                            $operatorParameter, false,
1757                                                                                            $resourceData );
1758                          if ( isset( $newDataInspection['new-data'] ) )
1759                          {
1760                              $operatorParameter = $newDataInspection['new-data'];
1761                          }
1762                          $newVariableItem[1][] = $operatorParameter;
1763                      }
1764                  }
1765                  $newVariableData[] = $newVariableItem;
1766              }
1767              else if ( $variableItemType == EZ_TEMPLATE_TYPE_VOID )
1768              {
1769                  $tpl->warning( 'TemplateCompiler', "Void datatype should not be used, ignoring it" );
1770              }
1771              else if ( $variableItemType > EZ_TEMPLATE_TYPE_INTERNAL and
1772                        $variableItemType < EZ_TEMPLATE_TYPE_INTERNAL_STOP )
1773              {
1774                  $newVariableData[] = $variableItem;
1775              }
1776              else
1777              {
1778                  $tpl->warning( 'TemplateCompiler', "Unknown data type $variableItemType, ignoring it" );
1779              }
1780          }
1781          $dataInspection['new-data'] = $newVariableData;
1782          return $dataInspection;
1783      }
1784  
1785      /*!
1786       \return the operator hint for the operator \a $operatorName, or \c false if
1787               the operator does not exist or has no hints.
1788      */
1789      function operatorHint( &$tpl, $operatorName )
1790      {
1791          if ( isset( $tpl->Operators[$operatorName] ) and
1792               is_array( $tpl->Operators[$operatorName] ) )
1793          {
1794              $tpl->loadAndRegisterOperators( $tpl->Operators[$operatorName] );
1795          }
1796          $operatorObject =& $tpl->Operators[$operatorName];
1797          $operatorHint = false;
1798          if ( is_object( $operatorObject ) )
1799          {
1800              if ( method_exists( $operatorObject, 'operatorTemplateHints' ) )
1801              {
1802                  $operatorHintArray = $operatorObject->operatorTemplateHints();
1803                  if ( isset( $operatorHintArray[$operatorName] ) )
1804                  {
1805                      $operatorHint = $operatorHintArray[$operatorName];
1806                  }
1807              }
1808          }
1809          else if ( $tpl->testCompile() )
1810          {
1811              $tpl->warning( '', "Operator '$operatorName' is not registered." );
1812          }
1813  
1814          return $operatorHint;
1815      }
1816  
1817      /*!
1818       \return static data from operators which support returning static data,
1819               or \c null if no static data could be extracted.
1820               The operator is specified in \a $operatorName.
1821  
1822      */
1823      function operatorStaticData( &$tpl, $operatorName )
1824      {
1825          if ( is_array( $tpl->Operators[$operatorName] ) )
1826          {
1827              $tpl->loadAndRegisterOperators( $tpl->Operators[$operatorName] );
1828          }
1829          $operatorObject =& $tpl->Operators[$operatorName];
1830          $operatorData = null;
1831          if ( is_object( $operatorObject ) )
1832          {
1833              if ( method_exists( $operatorObject, 'operatorCompiledStaticData' ) )
1834              {
1835                  $operatorData = $operatorObject->operatorCompiledStaticData( $operatorName );
1836              }
1837          }
1838          else if ( $tpl->testCompile() )
1839          {
1840              $tpl->warning( '', "Operator '$operatorName' is not registered." );
1841          }
1842  
1843          return $operatorData;
1844      }
1845  
1846      /*!
1847       Creates a variable data element for the data \a $staticData and returns it.
1848       The type of element depends on the type of the data, strings and booleans
1849       are returned as EZ_TEMPLATE_TYPE_TEXT and EZ_TEMPLATE_TYPE_NUMERIC while other
1850       types are turned into text and returned as EZ_TEMPLATE_TYPE_TEXT.
1851      */
1852      function createStaticVariableData( &$tpl, $staticData, $variableItemPlacement )
1853      {
1854          if ( is_string( $staticData ) )
1855              return array( EZ_TEMPLATE_TYPE_TEXT,
1856                            $staticData,
1857                            $variableItemPlacement );
1858          else if ( is_bool( $staticData ) )
1859              return array( EZ_TEMPLATE_TYPE_BOOLEAN,
1860                            $staticData,
1861                            $variableItemPlacement );
1862          else if ( is_bool( $staticData ) or is_numeric( $staticData ) )
1863              return array( EZ_TEMPLATE_TYPE_NUMERIC,
1864                            $staticData,
1865                            $variableItemPlacement );
1866          else if ( is_array( $staticData ) )
1867              return array( EZ_TEMPLATE_TYPE_ARRAY,
1868                            $staticData,
1869                            $variableItemPlacement );
1870          else
1871              return array( EZ_TEMPLATE_TYPE_TEXT,
1872                            "$staticData",
1873                            $variableItemPlacement );
1874      }
1875  
1876      /*!
1877       Opens the template files specified in \a $placementData
1878       and fetches the text portion defined by the
1879       start and end position. The text is returned or \c null if the
1880       text could not be fetched.
1881      */
1882      function fetchTemplatePiece( $placementData )
1883      {
1884          if ( !isset( $placementData[0] ) or
1885               !isset( $placementData[1] ) or
1886               !isset( $placementData[2] ) )
1887              return null;
1888          $file = $placementData[2];
1889          $startPosition = $placementData[0][2];
1890          $endPosition = $placementData[1][2];
1891          $length = $endPosition - $startPosition;
1892          if ( file_exists( $file ) )
1893          {
1894              if ( $length > 0 )
1895              {
1896                  $fd = fopen( $file, 'rb' );
1897                  fseek( $fd, $startPosition );
1898                  $text = fread( $fd, $length );
1899                  fclose( $fd );
1900                  return $text;
1901              }
1902              else
1903              {
1904                  return '';
1905              }
1906          }
1907          return null;
1908      }
1909  
1910      /*!
1911       Creates the common.php file which has common functions for compiled templates.
1912       If the file already exists if will not create it.
1913      */
1914      function createCommonCompileTemplate()
1915      {
1916          $php = new eZPHPCreator( eZTemplateCompiler::compilationDirectory(), 'common.php' );
1917          if ( $php->exists() )
1918              return;
1919  
1920          $php->addComment( "This file contains functions which are common to all compiled templates.\n\n" .
1921                            'NOTE: This file is autogenerated and should not be modified, any changes will be lost!' );
1922          $php->addSpace();
1923          $php->addDefine( 'EZ_TEMPLATE_COMPILER_COMMON_CODE', true );
1924          $php->addSpace();
1925  
1926          $namespaceStack = array();
1927          $php->addCodePiece( "if ( !isset( \$namespaceStack ) )\n" );
1928          $php->addVariable( 'namespaceStack', $namespaceStack, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'spacing' => 4 ) );
1929          $php->addSpace();
1930  
1931          $lbracket = '{';
1932          $rbracket = '}';
1933          $initText = "if ( !function_exists( 'compiledfetchvariable' ) )
1934  $lbracket
1935      function compiledFetchVariable( &\$vars, \$namespace, \$name )
1936      $lbracket
1937          \$exists = ( array_key_exists( \$namespace, \$vars ) and
1938                      array_key_exists( \$name, \$vars[\$namespace] ) );
1939          if ( \$exists )
1940          $lbracket
1941              \$var = \$vars[\$namespace][\$name];
1942          $rbracket
1943          else
1944              \$var = null;
1945          return \$var;
1946      $rbracket
1947  $rbracket
1948  if ( !function_exists( 'compiledfetchtext' ) )
1949  $lbracket
1950      function compiledFetchText( &\$tpl, \$rootNamespace, \$currentNamespace, \$namespace, &\$var )
1951      $lbracket
1952          \$text = '';
1953          \$tpl->appendElement( \$text, \$var, \$rootNamespace, \$currentNamespace );
1954          return \$text;
1955      $rbracket
1956  $rbracket
1957  if ( !function_exists( 'compiledAcquireResource' ) )
1958  $lbracket
1959      function compiledAcquireResource( \$phpScript, \$key, &\$originalText,
1960                                        &\$tpl, \$rootNamespace, \$currentNamespace )
1961      {
1962          include( '" . eZTemplateCompiler::TemplatePrefix() . "' . \$phpScript );
1963          if ( isset( \$text ) )
1964          {
1965              \$originalText .= \$text;
1966              return true;
1967          }
1968          return false;
1969      }
1970  $rbracket
1971  if ( !function_exists( 'compiledfetchattribute' ) )
1972  $lbracket
1973      function compiledFetchAttribute( &\$value, \$attributeValue )
1974      $lbracket
1975          if ( is_object( \$value ) )
1976          $lbracket
1977              if ( method_exists( \$value, \"attribute\" ) and
1978                   method_exists( \$value, \"hasattribute\" ) )
1979              $lbracket
1980                  if ( \$value->hasAttribute( \$attributeValue ) )
1981                  $lbracket
1982                      unset( \$tempValue );
1983                      \$tempValue = \$value->attribute( \$attributeValue );
1984                      return \$tempValue;
1985                  $rbracket
1986              $rbracket
1987          $rbracket
1988          else if ( is_array( \$value ) )
1989          $lbracket
1990              if ( isset( \$value[\$attributeValue] ) )
1991              $lbracket
1992                  unset( \$tempValue );
1993                  \$tempValue = \$value[\$attributeValue];
1994                  return \$tempValue;
1995              $rbracket
1996          $rbracket
1997          return null;
1998      $rbracket
1999  $rbracket
2000  ";
2001          $php->addCodePiece( $initText );
2002          $php->store( true );
2003      }
2004  
2005      /*!
2006       Figures out the current text name to use in compiled template code and return it.
2007       The names will be text, text1, text2 etc.
2008      */
2009      function currentTextName( $parameters )
2010      {
2011          $textData = array( 'variable' => 'text',
2012                             'counter' => 0 );
2013          if ( isset( $parameters['text-data'] ) )
2014              $textData = $parameters['text-data'];
2015          $name = $textData['variable'];
2016          if ( $textData['counter'] > 0 )
2017              $name .= $textData['counter'];
2018          return $name;
2019      }
2020  
2021      /*!
2022       Increases the counter for the current text name, this ensure a uniqe name for it.
2023      */
2024      function increaseCurrentTextName( &$parameters )
2025      {
2026          $textData = array( 'variable' => 'text',
2027                             'counter' => 0 );
2028          if ( !isset( $parameters['text-data'] ) )
2029              $parameters['text-data'] = $textData;
2030  
2031          $parameters['text-data']['counter']++;
2032      }
2033  
2034      /*!
2035       Decreases a previosuly increased counter for the current text name.
2036      */
2037      function decreaseCurrentTextName( &$parameters )
2038      {
2039          $textData = array( 'variable' => 'text',
2040                             'counter' => 0 );
2041          if ( !isset( $parameters['text-data'] ) )
2042          {
2043              $parameters['text-data'] = $textData;
2044              return;
2045          }
2046  
2047          $parameters['text-data']['counter']--;
2048      }
2049  
2050      function boundVariableName( $variableID, $parameters )
2051      {
2052          $bindMap =& $parameters['variable-bind']['map'][$variableID];
2053          if ( isset( $bindMap ) )
2054              $bindMap = array();
2055      }
2056  
2057      /*!
2058       Generates the PHP code defined in the template node tree \a $node.
2059       The code is generated using the php creator specified in \a $php.
2060      */
2061  
2062      function generatePHPCode( $useComments, &$php, &$tpl, &$node, &$resourceData )
2063      {
2064          $parameters = array();
2065          $currentParameters = array( 'spacing' => 0 );
2066          $nodeType = $node[0];
2067          if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
2068          {
2069              $children = $node[1];
2070              if ( $children )
2071              {
2072                  eZTemplateCompiler::generatePHPCodeChildren( $useComments, $php, $tpl, $children, $resourceData, $parameters, $currentParameters );
2073              }
2074          }
2075          else
2076              $tpl->error( 'generatePHPCode', "Unknown root type $nodeType, should be " . EZ_TEMPLATE_NODE_ROOT );
2077          $php->addSpace();
2078      }
2079  
2080      /*!
2081       Generates the PHP code for all node children specified in \a $nodeChildren.
2082       \sa generatePHPCode
2083      */
2084      function generatePHPCodeChildren( $useComments, &$php, &$tpl, &$nodeChildren, &$resourceData, &$parameters, $currentParameters )
2085      {
2086          foreach ( $nodeChildren as $node )
2087          {
2088              $newNode = false;
2089              $nodeType = $node[0];
2090              if ( $nodeType > EZ_TEMPLATE_NODE_USER_CUSTOM )
2091              {
2092                  // Do custom nodes
2093              }
2094              else if ( $nodeType > EZ_TEMPLATE_NODE_INTERNAL )
2095              {
2096                  // Do custom internal nodes
2097                  if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_CODE_PIECE )
2098                  {
2099                      $codePiece = $node[1];
2100                      $spacing = $currentParameters['spacing'];
2101                      if ( isset( $node[2]['spacing'] ) )
2102                          $spacing += $node[2]['spacing'];
2103                      $php->addCodePiece( $codePiece, array( 'spacing' => $spacing ) );
2104                  }
2105                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_WARNING )
2106                  {
2107                      $warningText = $php->variableText( $node[1], 23, 0, false );
2108                      $warningLabel = false;
2109                      $warningLabelText = '';
2110                      if ( isset( $node[2] ) )
2111                          $warningLabelText = $php->variableText( $node[2], 0, 0, false );
2112                      $spacing = $currentParameters['spacing'];
2113                      if ( isset( $node[3]['spacing'] ) )
2114                          $spacing += $node[3]['spacing'];
2115                      $placementText = 'false';
2116                      if ( isset( $node[4] ) )
2117                          $placementText = $php->variableText( $node[4], 0, 0, false );
2118                      $php->addCodePiece( "\$tpl->warning( " . $warningLabelText . ", " . $warningText . ", " . $placementText . " );", array( 'spacing' => $spacing ) );
2119                  }
2120                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_ERROR )
2121                  {
2122                      $errorText = $php->variableText( $node[1], 21, 0, false );
2123                      $errorLabel = false;
2124                      $errorLabelText = '';
2125                      if ( isset( $node[2] ) )
2126                          $errorLabelText = $php->variableText( $node[2], 0, 0, false );
2127                      $spacing = $currentParameters['spacing'];
2128                      if ( isset( $node[3]['spacing'] ) )
2129                          $spacing += $node[3]['spacing'];
2130                      $placementText = 'false';
2131                      if ( isset( $node[4] ) )
2132                          $placementText = $php->variableText( $node[4], 0, 0, false );
2133                      $php->addCodePiece( "\$tpl->error( " . $errorLabelText . ", " . $errorText . ", " . $placementText . " );", array( 'spacing' => $spacing ) );
2134                  }
2135                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_OUTPUT_READ )
2136                  {
2137                      $variableName = $node[1];
2138                      $spacing = $currentParameters['spacing'];
2139                      if ( isset( $node[2]['spacing'] ) )
2140                          $spacing += $node[2]['spacing'];
2141                      $textName = eZTemplateCompiler::currentTextName( $parameters );
2142                      $assignmentType = $node[3];
2143                      $assignmentText = $php->variableNameText( $variableName, $assignmentType, $node[2] );
2144                      $php->addCodePiece( "$assignmentText\$$textName;", array( 'spacing' => $spacing ) );
2145                  }
2146                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_OUTPUT_ASSIGN )
2147                  {
2148                      $variableName = $node[1];
2149                      $spacing = $currentParameters['spacing'];
2150                      if ( isset( $node[2]['spacing'] ) )
2151                          $spacing += $node[2]['spacing'];
2152                      $textName = eZTemplateCompiler::currentTextName( $parameters );
2153                      $assignmentType = $node[3];
2154                      $assignmentText = $php->variableNameText( $textName, $assignmentType, $node[2] );
2155                      $php->addCodePiece( "$assignmentText\$$variableName;", array( 'spacing' => $spacing ) );
2156                  }
2157                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_OUTPUT_INCREASE )
2158                  {
2159                      $spacing = $currentParameters['spacing'];
2160                      if ( isset( $node[1]['spacing'] ) )
2161                          $spacing += $node[1]['spacing'];
2162                      $textName = eZTemplateCompiler::currentTextName( $parameters );
2163                      $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$textStack ) )\n" .
2164                                          "    \$textStack = array();\n" .
2165                                          "\$textStack[] = \$$textName;\n" .
2166                                          "\$$textName = '';", array( 'spacing' => $spacing ) );
2167                  }
2168                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_OUTPUT_DECREASE )
2169                  {
2170                      $spacing = $currentParameters['spacing'];
2171                      if ( isset( $node[1]['spacing'] ) )
2172                          $spacing += $node[1]['spacing'];
2173                      $textName = eZTemplateCompiler::currentTextName( $parameters );
2174                      $php->addCodePiece( "\$$textName = array_pop( \$textStack );", array( 'spacing' => $spacing ) );
2175                  }
2176                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_SPACING_INCREASE )
2177                  {
2178                      $spacing = $node[1];
2179                      $currentParameters['spacing'] += $spacing;
2180                      continue;
2181                  }
2182                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_SPACING_DECREASE )
2183                  {
2184                      $spacing = $node[1];
2185                      $currentParameters['spacing'] -= $spacing;
2186                      continue;
2187                  }
2188                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_VARIABLE_SET )
2189                  {
2190                      $variableName = $node[1];
2191                      $variableValue = $node[2];
2192                      $spacing = $currentParameters['spacing'];
2193                      if ( isset( $node[3]['spacing'] ) )
2194                          $spacing += $node[3]['spacing'];
2195                      $php->addVariable( $variableName, $variableValue, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'spacing' => $spacing ) );
2196                  }
2197                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_VARIABLE_UNSET )
2198                  {
2199                      $variableName = $node[1];
2200                      $spacing = $currentParameters['spacing'];
2201                      if ( isset( $node[2]['spacing'] ) )
2202                          $spacing += $node[2]['spacing'];
2203  
2204                      if ( is_array( $variableName ) )
2205                      {
2206                          $namespace = $variableName[0];
2207                          $namespaceScope = $variableName[1];
2208                          $variableName = $variableName[2];
2209                          $namespaceText = eZTemplateCompiler::generateMergeNamespaceCode( $php, $tpl, $namespace, $namespaceScope, array( 'spacing' => $spacing ), true );
2210                          if ( !is_string( $namespaceText ) )
2211                              $namespaceText = "\$namespace";
2212                          $variableNameText = $php->variableText( $variableName, 0, 0, false );
2213                          if ( isset( $node[2]['remember_set'] ) and $node[2]['remember_set'] )
2214                          {
2215                              $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( isset( \$setArray[$namespaceText][$variableNameText] ) )\n".
2216                                                  "{\n" );
2217                              $spacing += 4;
2218                          }
2219                          if ( isset( $node[2]['local-variable'] ) )
2220                          {
2221                              $php->addCodePiece( "\$tpl->unsetLocalVariable( $variableNameText, $namespaceText );\n",
2222                                                  array( 'spacing' => $spacing ) );
2223                          }
2224                          else
2225                          {
2226                              $php->addCodePiece( "unset( \$vars[$namespaceText][$variableNameText] );",
2227                                                  array( 'spacing' => $spacing ) );
2228                          }
2229  
2230                          if ( isset( $node[2]['remember_set'] ) and $node[2]['remember_set'] )
2231                          {
2232                              $php->addCodePiece( "\n}\n" );
2233                              $spacing -= 4;
2234                          }
2235                      }
2236                      else
2237                      {
2238                          $php->addVariableUnset( $variableName, array( 'spacing' => $spacing ) );
2239                      }
2240                  }
2241                  else if ( ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_RESOURCE_ACQUISITION ) ||
2242                            ( $nodeType == EZ_TEMPLATE_NODE_OPTIMIZED_RESOURCE_ACQUISITION ) )
2243                  {
2244                      $resource = $node[1];
2245                      $resourceObject =& $tpl->resourceHandler( $resource );
2246                      if ( !$resourceObject )
2247                          continue;
2248  
2249                      $spacing = $currentParameters['spacing'];
2250                      if ( isset( $node[7]['spacing'] ) )
2251                          $spacing += $node[7]['spacing'];
2252                      $newRootNamespace = $node[8];
2253                      $resourceVariableName = $node[9];
2254                      $resourceFilename = isset( $node[10] ) ? $node[10] : false;
2255  
2256                      /* We can only use fallback code if we know upfront which
2257                       * template is included; it does not work if we are using
2258                       * something from the ezobjectforwarder which makes the
2259                       * uriMap an array */
2260                      $useFallbackCode = true;
2261                      $uriMap = $node[2];
2262                      if ( is_string( $uriMap ) )
2263                      {
2264                          $uriMap = array( $uriMap );
2265                      }
2266                      else
2267                      {
2268                          $useFallbackCode = false;
2269                      }
2270  
2271                      $resourceMap = array();
2272                      $hasCompiledCode = false;
2273                      foreach ( $uriMap as $uriKey => $originalURI )
2274                      {
2275                          $uri = $originalURI;
2276                          if ( $resource )
2277                              $uri = $resource . ':' . $uri;
2278                          unset( $tmpResourceData );
2279                          $tmpResourceData = $tpl->resourceData( $resourceObject, $uri, $node[1], $originalURI );
2280                          $uriText = $php->variableText( $uri, 0, 0, false );
2281  
2282                          $resourceCanCache = true;
2283                          if ( !$resourceObject->servesStaticData() )
2284                              $resourceCanCache = false;
2285                          if ( !$tpl->isCachingAllowed() )
2286                              $resourceCanCache = false;
2287  
2288                          $tmpResourceData['text'] = null;
2289                          $tmpResourceData['root-node'] = null;
2290                          $tmpResourceData['compiled-template'] = false;
2291                          $tmpResourceData['time-stamp'] = null;
2292                          $tmpResourceData['key-data'] = null;
2293                          $tmpResourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
2294                          $subSpacing = 0;
2295                          $hasResourceData = false;
2296  
2297                          $savedLocale = setlocale( LC_CTYPE, null );
2298                          if ( isset( $GLOBALS['eZTemplateCompilerResourceCache'][$tmpResourceData['template-filename']] ) )
2299                          {
2300                              $tmpFileName = $tmpResourceData['template-filename'];
2301                              unset( $tmpResourceData );
2302                              $tmpResourceData = $GLOBALS['eZTemplateCompilerResourceCache'][$tmpFileName];
2303                              $tmpResourceData['compiled-template'] = true;
2304                              $tmpResourceData['use-comments'] = eZTemplateCompiler::isCommentsEnabled();
2305                              $hasResourceData = true;
2306                              $hasCompiledCode = true;
2307                          }
2308                          else if ( $useFallbackCode )
2309                          {
2310                              // If we can use fallback code we don't need to compile the templates in advance
2311                              // Simply fake that it has been compiled by setting some variables
2312                              // Note: Yes this is a hack, but rewriting this code is not an easy task
2313                              if ( $resourceObject->handleResource( $tpl, $tmpResourceData, $node[4], $node[5] ) )
2314                              {
2315                                  $tmpResourceData['compiled-template'] = true;
2316                                  $hasResourceData = true;
2317                                  $hasCompiledCode = true;
2318                              }
2319                          }
2320                          else
2321                          {
2322                              if ( $resourceObject->handleResource( $tpl, $tmpResourceData, $node[4], $node[5] ) )
2323                              {
2324                                  if ( !$tmpResourceData['compiled-template'] and
2325                                       $tmpResourceData['root-node'] === null )
2326                                  {
2327                                      $root =& $tmpResourceData['root-node'];
2328                                      $root = array( EZ_TEMPLATE_NODE_ROOT, false );
2329                                      $templateText =& $tmpResourceData["text"];
2330                                      $keyData = $tmpResourceData['key-data'];
2331                                      $rootNamespace = '';
2332                                      $tpl->parse( $templateText, $root, $rootNamespace, $tmpResourceData );
2333                                      $hasResourceData = false;
2334                                  }
2335  
2336                                  /* We always DO need to execute this part if we
2337                                   * don't have any fallback code. If we can
2338                                   * generate the fallback code we make the
2339                                   * included template compile on demand */
2340                                  if ( !$tmpResourceData['compiled-template'] and
2341                                       $resourceCanCache and
2342                                       $tpl->canCompileTemplate( $tmpResourceData, $node[5] ) and
2343                                       !$useFallbackCode )
2344                                  {
2345                                      $generateStatus = $tpl->compileTemplate( $tmpResourceData, $node[5] );
2346  
2347                                      // Time limit #2:
2348                                      /* We reset the time limit to 60 seconds to
2349                                       * ensure that remaining template has
2350                                       * enough time to compile. However if time
2351                                       * limit is unlimited (0) we leave it be */
2352                                      $maxExecutionTime = ini_get( 'max_execution_time' );
2353                                      if ( $maxExecutionTime != 0 && $maxExecutionTime < 60 )
2354                                      {
2355                                          @set_time_limit( 60 );
2356                                      }
2357  
2358                                      if ( $generateStatus )
2359                                          $tmpResourceData['compiled-template'] = true;
2360                                  }
2361                              }
2362                              $GLOBALS['eZTemplateCompilerResourceCache'][$tmpResourceData['template-filename']] =& $tmpResourceData;
2363                          }
2364                          setlocale( LC_CTYPE, $savedLocale );
2365                          $textName = eZTemplateCompiler::currentTextName( $parameters );
2366                          if ( $tmpResourceData['compiled-template'] )
2367                          {
2368                              $hasCompiledCode = true;
2369  //                            if ( !eZTemplateCompiler::isFallbackResourceCodeEnabled() )
2370  //                                $useFallbackCode = false;
2371                              $keyData = $tmpResourceData['key-data'];
2372                              $templatePath = $tmpResourceData['template-name'];
2373                              $key = $resourceObject->cacheKey( $keyData, $tmpResourceData, $templatePath, $node[5] );
2374                              $cacheFileName = eZTemplateCompiler::compilationFilename( $key, $tmpResourceData );
2375  
2376                              $directory = eZTemplateCompiler::compilationDirectory();
2377                              $phpScript = eZDir::path( array( $directory, $cacheFileName ) );
2378                              $phpScriptText = $php->variableText( $phpScript, 0, 0, false );
2379                              $resourceMap[$uriKey] = array( 'key' => $uriKey,
2380                                                             'uri' => $uri,
2381                                                             'phpscript' => $phpScript );
2382                          }
2383                      }
2384  
2385                      if ( $useComments )
2386                      {
2387                          $variablePlacement = $node[6];
2388                          if ( $variablePlacement )
2389                          {
2390                              $originalText = eZTemplateCompiler::fetchTemplatePiece( $variablePlacement );
2391                              $php->addComment( "Resource Acquisition:", true, true, array( 'spacing' => $spacing ) );
2392                              $php->addComment( $originalText, true, true, array( 'spacing' => $spacing ) );
2393                          }
2394                      }
2395  
2396                      if ( $hasCompiledCode )
2397                      {
2398                          if ( $resourceVariableName )
2399                          {
2400                              $phpScriptText = '$phpScript';
2401                              $phpScriptArray = array();
2402  
2403                              foreach ( $resourceMap as $resourceMapItem )
2404                              {
2405                                  $phpScriptArray[$resourceMapItem['key']] = $resourceMapItem['phpscript'];
2406                              }
2407  
2408                              if ( !$resourceFilename ) /* Not optimized version */
2409                              {
2410                                  $php->addVariable( "phpScriptArray", $phpScriptArray, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array( 'spacing' => $spacing ) );
2411                                  $resourceVariableNameText = "\$$resourceVariableName";
2412                                  $php->addCodePiece( "\$phpScript = isset( \$phpScriptArray[$resourceVariableNameText] ) ? \$phpScriptArray[$resourceVariableNameText] : false;\n", array( 'spacing' => $spacing ) );
2413                              }
2414                              else /* Optimised version */
2415                              {
2416                                  $php->addVariable( "phpScript", $phpScriptArray[$node[10]], EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, array('spacing' => $spacing ) );
2417                              }
2418  
2419                              // The default is to only check if it exists
2420                              $modificationCheckText = "file_exists( $phpScriptText )";
2421                              if  ( eZTemplateCompiler::isDevelopmentModeEnabled() )
2422                              {
2423                                  $modificationCheckText = "@filemtime( $phpScriptText ) > filemtime( $uriText )";
2424                              }
2425                              $php->addCodePiece( "\$resourceFound = false;\nif " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( $phpScriptText !== false and $modificationCheckText )\n{\n", array( 'spacing' => $spacing ) );
2426                          }
2427                          else
2428                          {
2429                              $php->addCodePiece( "\$resourceFound = false;\n", array( 'spacing' => $spacing ) );
2430                              $phpScript = $resourceMap[0]['phpscript'];
2431                              $phpScriptText = $php->variableText( $phpScript, 0, 0, false );
2432                              // Not sure where this should come from
2433  //                         if ( $resourceIndex > 0 )
2434  //                             $php->addCodePiece( "else " );
2435                              // The default is to only check if it exists
2436                              $modificationCheckText = "file_exists( $phpScriptText )";
2437                              if  ( eZTemplateCompiler::isDevelopmentModeEnabled() )
2438                              {
2439                                  $modificationCheckText = "@filemtime( $phpScriptText ) > filemtime( $uriText )";
2440                              }
2441                              $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( $modificationCheckText )\n{\n", array( 'spacing' => $spacing ) );
2442  
2443                          }
2444  
2445                          /* Generate code to do a namespace switch and includes the template */
2446                          $code = "\$resourceFound = true;\n\$namespaceStack[] = array( \$rootNamespace, \$currentNamespace );\n";
2447                          if ( $newRootNamespace )
2448                          {
2449                              $newRootNamespaceText = $php->variableText( $newRootNamespace, 0, 0, false );
2450                              $code .= "\$currentNamespace = \$rootNamespace = !\$currentNamespace ? $newRootNamespaceText : ( \$currentNamespace . ':' . $newRootNamespaceText );\n";
2451                          }
2452                          else
2453                          {
2454                              $code .= "\$rootNamespace = \$currentNamespace;\n";
2455                          }
2456  
2457                          $code .=
2458                              "\$tpl->createLocalVariablesList();\n" .
2459                              "\$tpl->appendTemplateFetch( $uriText );\n" . // Make sure the template file is recorded, like in loadURIRoot
2460                              "include( '" . eZTemplateCompiler::TemplatePrefix() . "' . $phpScriptText );\n" .
2461                              "\$tpl->unsetLocalVariables();\n" .
2462                              "\$tpl->destroyLocalVariablesList();\n" .
2463                              "list( \$rootNamespace, \$currentNamespace ) = array_pop( \$namespaceStack );\n";
2464  
2465                          $php->addCodePiece( $code, array( 'spacing' => $spacing + 4 ) );
2466                          if ( $useFallbackCode )
2467                              $php->addCodePiece( "}\nelse\n{\n    \$resourceFound = true;\n", array( 'spacing' => $spacing ) );
2468                          else
2469                              $php->addCodePiece( "}\n", array( 'spacing' => $spacing ) );
2470                          $subSpacing = 4;
2471                      }
2472                      else
2473                      {
2474                          /* Yes, this is a hack, but it is required because
2475                           * sometimes the generated nodes after this one emit an
2476                           * else statement while there is no accompanied if */
2477                          $php->addCodePiece( "\nif " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "(false)\n{\n}\n" );
2478                      }
2479  
2480                      /* The fallback code will be added if we need to process an
2481                       * URI, this will also compile a template then. We need to
2482                       * do the namespace switch manually here otherwise the
2483                       * processed template will be run on the node from which
2484                       * the template was included from. */
2485                      if ( $useFallbackCode )
2486                      {
2487                          $code = "\$resourceFound = true;\n\$namespaceStack[] = array( \$rootNamespace, \$currentNamespace );\n";
2488                          if ( $newRootNamespace )
2489                          {
2490                              $newRootNamespaceText = $php->variableText( $newRootNamespace, 0, 0, false );
2491                              $code .= "\$currentNamespace = \$rootNamespace = !\$currentNamespace ? $newRootNamespaceText : ( \$currentNamespace . ':' . $newRootNamespaceText );\n";
2492                          }
2493                          else
2494                          {
2495                              $code .= "\$rootNamespace = \$currentNamespace;\n";
2496                          }
2497                          $php->addCodePiece( $code );
2498  
2499                          $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 ) );
2500                          $php->addCodePiece( "list( \$rootNamespace, \$currentNamespace ) = array_pop( \$namespaceStack );\n" );
2501                      }
2502  
2503                      if ( $hasCompiledCode and $useFallbackCode )
2504                      {
2505                          $php->addCodePiece( "}\n", array( 'spacing' => $spacing ) );
2506                      }
2507                  }
2508                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_NAMESPACE_CHANGE )
2509                  {
2510                      $variableData = $node[1];
2511                      $spacing = $currentParameters['spacing'];
2512                      if ( isset( $node[2]['spacing'] ) )
2513                          $spacing += $node[2]['spacing'];
2514                      $php->addCodePiece( "\$namespaceStack[] = \$currentNamespace;\n", array( 'spacing' => $spacing ) );
2515                      $php->addCodePiece( '$currentNamespace .= ( $currentNamespace ? ":" : "" ) . \''. $variableData[0][1] . '\';' . "\n", array( 'spacing' => $spacing ) );
2516                  }
2517                  else if ( $nodeType == EZ_TEMPLATE_NODE_INTERNAL_NAMESPACE_RESTORE )
2518                  {
2519                      $spacing = $currentParameters['spacing'];
2520                      if ( isset( $node[1]['spacing'] ) )
2521                          $spacing += $node[1]['spacing'];
2522                      $php->addCodePiece( "\$currentNamespace = array_pop( \$namespaceStack );\n", array( 'spacing' => $spacing ) );
2523                  }
2524                  else if ( $nodeType == EZ_TEMPLATE_NODE_OPTIMIZED_INIT )
2525                  {
2526                      $code = <<<END
2527  \$node = ( array_key_exists( \$rootNamespace, \$vars ) and array_key_exists( "node", \$vars[\$rootNamespace] ) ) ? \$vars[\$rootNamespace]["node"] : null;
2528  if ( is_object( \$node ) )
2529  \$object = \$node->attribute( 'object' );
2530  if ( isset( \$object ) && is_object( \$object ) )
2531  \$nod_{$resourceData['uniqid']} = \$object->attribute( 'data_map' );
2532  else
2533  \$nod_{$resourceData['uniqid']} = false;
2534  unset( \$node, \$object );
2535  
2536  END;
2537                      $php->addCodePiece($code);
2538                      // Tell the rest of the system that we have create the nod_* variable
2539                      $resourceData['node-object-cached'] = true;
2540                  }
2541                  else
2542                      eZDebug::writeWarning( "Unknown internal template node type $nodeType, ignoring node for code generation",
2543                                             'eZTemplateCompiler:generatePHPCodeChildren' );
2544              }
2545              else if ( $nodeType == EZ_TEMPLATE_NODE_ROOT )
2546              {
2547                  $children = $node[1];
2548                  if ( $children )
2549                  {
2550                      $newCurrentParameters = $currentParameters;
2551                      $newCurrentParameters['spacing'] += 4;
2552                      eZTemplateCompiler::generatePHPCodeChildren( $useComments, $php, $tpl, $children, $resourceData, $parameters, $newCurrentParameters );
2553                  }
2554                  continue;
2555              }
2556              else if ( $nodeType == EZ_TEMPLATE_NODE_TEXT )
2557              {
2558                  $text = $node[2];
2559                  if ( $text != '' )
2560                  {
2561                      $variablePlacement = $node[3];
2562                      $originalText = eZTemplateCompiler::fetchTemplatePiece( $variablePlacement );
2563                      if ( $useComments )
2564                      {
2565                          $php->addComment( "Text start:", true, true, array( 'spacing' => $currentParameters['spacing'] ) );
2566                          $php->addComment( $originalText, true, true, array( 'spacing' => $currentParameters['spacing'] ) );
2567                          $php->addComment( "Text end:", true, true, array( 'spacing' => $currentParameters['spacing'] ) );
2568                      }
2569                      $php->addVariable( eZTemplateCompiler::currentTextName( $parameters ),
2570                                         $text, EZ_PHPCREATOR_VARIABLE_APPEND_TEXT,
2571                                         array( 'spacing' => $currentParameters['spacing'] ) );
2572                  }
2573                  continue;
2574              }
2575              else if ( $nodeType == EZ_TEMPLATE_NODE_VARIABLE )
2576              {
2577                  $variableAssignmentName = $node[1];
2578                  $variableData = $node[2];
2579                  $variablePlacement = $node[3];
2580  
2581                  $variableParameters = array();
2582                  if ( isset( $node[4] ) and
2583                       $node[4] )
2584                      $variableParameters = $node[4];
2585                  $variableOnlyExisting = isset( $node[5] ) ? $node[5] : false;
2586                  $variableOverWrite = isset( $node[6] ) ? $node[6] : false;
2587                  $rememberSet = isset( $node[7] ) ? $node[7] : false;
2588  
2589                  $spacing = $currentParameters['spacing'];
2590                  if ( isset( $variableParameters['spacing'] ) )
2591                      $spacing += $variableParameters['spacing'];
2592                  $variableParameters = array_merge( array( 'variable-name' => 'var',
2593                                                            'text-result' => true ),
2594                                                     $variableParameters );
2595                  $dataInspection = eZTemplateCompiler::inspectVariableData( $tpl,
2596                                                                             $variableData, $variablePlacement,
2597                                                                             $resourceData );
2598                  $newNode = $node;
2599                  $newNode[1] = false;
2600  
2601                  $treatVariableDataAsNonObject = isset( $variableParameters['treat-value-as-non-object'] ) && $variableParameters['treat-value-as-non-object'];
2602  
2603                  if ( $useComments )
2604                  {
2605                      $php->addComment( "Variable data: " .
2606                                        "Is constant: " . ( $dataInspection['is-constant'] ? 'Yes' : 'No' ) .
2607                                        " Is variable: " . ( $dataInspection['is-variable'] ? 'Yes' : 'No' ) .
2608                                        " Has attributes: " . ( $dataInspection['has-attributes'] ? 'Yes' : 'No' ) .
2609                                        " Has operators: " . ( $dataInspection['has-operators'] ? 'Yes' : 'No' ),
2610                                        true, true, array( 'spacing' => $spacing )
2611                                        );
2612                      $originalText = eZTemplateCompiler::fetchTemplatePiece( $variablePlacement );
2613                      $php->addComment( '{' . $originalText . '}', true, true, array( 'spacing' => $spacing ) );
2614                  }
2615                  $generatedVariableName = $variableParameters['variable-name'];
2616                  $assignVariable = false;
2617                  if ( $variableAssignmentName !== false )
2618                  {
2619                      if ( is_array( $variableAssignmentName ) )
2620                      {
2621                          $variableParameters['text-result'] = false;
2622                          $assignVariable = true;
2623                      }
2624                      else
2625                      {
2626                          $generatedVariableName = $variableAssignmentName;
2627                          $variableParameters['text-result'] = false;
2628                      }
2629                  }
2630  
2631                  $isStaticElement = false;
2632                  $nodeElements = $node[2];
2633                  $knownTypes = array();
2634                  if ( eZTemplateNodeTool::isStaticElement( $nodeElements ) and
2635                       !$variableParameters['text-result'] )
2636                  {
2637                      $variableText = $php->variableText( eZTemplateNodeTool::elementStaticValue( $nodeElements ), 0, 0, false );
2638                      $isStaticElement = true;
2639                  }
2640                  else if ( eZTemplateNodeTool::isPHPVariableElement( $nodeElements ) and
2641                            !$variableParameters['text-result'] )
2642                  {
2643                      $variableText = '$' . eZTemplateNodeTool::elementStaticValue( $nodeElements );
2644                      $isStaticElement = true;
2645                  }
2646                  else
2647                  {
2648                      $variableText = "\$$generatedVariableName";
2649                      eZTemplateCompiler::generateVariableCode( $php, $tpl, $node, $knownTypes, $dataInspection,
2650                                                                array( 'spacing' => $spacing,
2651                                                                       'variable' => $generatedVariableName,
2652                                                                       'treat-value-as-non-object' => $treatVariableDataAsNonObject,
2653                                                                       'counter' => 0 ),
2654                                                                $resourceData );
2655                  }
2656  
2657                  if ( $variableParameters['text-result'] )
2658                  {
2659                      $textName = eZTemplateCompiler::currentTextName( $parameters );
2660                      if ( count( $knownTypes ) == 0 or in_array( 'objectproxy', $knownTypes ) )
2661                      {
2662                          $php->addCodePiece( "\$$textName .= ( is_object( \$$generatedVariableName ) ? compiledFetchText( \$tpl, \$rootNamespace, \$currentNamespace, false, \$$generatedVariableName ) : \$$generatedVariableName );" .  ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "\n" .
2663                                              "unset( \$$generatedVariableName );\n", array( 'spacing' => $spacing ) );
2664                      }
2665                      else
2666                      {
2667                          $php->addCodePiece( "\$$textName .= \$$generatedVariableName;\n" .
2668                                              "unset( \$$generatedVariableName );\n", array( 'spacing' => $spacing ) );
2669                      }
2670                  }
2671                  else if ( $assignVariable )
2672                  {
2673                      $namespace = $variableAssignmentName[0];
2674                      $namespaceScope = $variableAssignmentName[1];
2675                      $variableName = $variableAssignmentName[2];
2676                      $namespaceText = eZTemplateCompiler::generateMergeNamespaceCode( $php, $tpl, $namespace, $namespaceScope, array( 'spacing' => $spacing ), true );
2677                      if ( !is_string( $namespaceText ) )
2678                          $namespaceText = "\$namespace";
2679                      $variableNameText = $php->variableText( $variableName, 0, 0, false );
2680                      $unsetVariableText = false;
2681                      if ( $variableOnlyExisting )
2682                      {
2683                          if ( !$isStaticElement )
2684                              $unsetVariableText = "\n    unset( $variableText );";
2685                          $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( array_key_exists( $namespaceText, \$vars ) && array_key_exists( $variableNameText, \$vars[$namespaceText] ) )\n".
2686                                              "{\n".
2687                                              "    \$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText\n".
2688                                              "}",
2689                                              array( 'spacing' => $spacing ) );
2690                      }
2691                      else if ( $variableOverWrite )
2692                      {
2693                          if ( !$isStaticElement )
2694                              $unsetVariableText = "\nunset( $variableText );";
2695                          if ( isset( $variableParameters['local-variable'] ) )
2696                          {
2697                              $php->addCodePiece( "\$tpl->setLocalVariable( $variableNameText, $variableText, $namespaceText );\n" ,
2698                                                  array( 'spacing' => $spacing ) );
2699                          }
2700                          else
2701                          {
2702                              $php->addCodePiece( "\$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText",
2703                                                  array( 'spacing' => $spacing ) );
2704                          }
2705  
2706                      }
2707                      else if ( $rememberSet )
2708                      {
2709                          if ( !$isStaticElement )
2710                              $unsetVariableText = "\n    unset( $variableText );";
2711                          $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$vars[$namespaceText][$variableNameText] ) )\n".
2712                                              "{\n".
2713                                              "    \$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText\n".
2714                                              "    \$setArray[$namespaceText][$variableNameText] = true;\n".
2715                                              "}\n",
2716                                              array( 'spacing' => $spacing ) );
2717                      }
2718                      else
2719                      {
2720                          if ( !$isStaticElement )
2721                              $unsetVariableText = "\n    unset( $variableText );";
2722                          $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$vars[$namespaceText][$variableNameText] ) )\n{\n    \$vars[$namespaceText][$variableNameText] = $variableText;$unsetVariableText\n}",
2723                                              array( 'spacing' => $spacing ) );
2724                      }
2725                  }
2726                  else if ( $variableAssignmentName !== false and $isStaticElement )
2727                  {
2728                      $php->addCodePiece( "\$$generatedVariableName = $variableText;", array( 'spacing' => $spacing ) );
2729                  }
2730                  else if ( $variableAssignmentName !== false and !$isStaticElement and !$treatVariableDataAsNonObject )
2731                  {
2732                      // Normal assignment from an expression, no need to anything extra
2733                  }
2734                  unset( $dataInspection );
2735              }
2736              else if ( $nodeType == EZ_TEMPLATE_NODE_FUNCTION )
2737              {
2738                  $functionChildren = $node[1];
2739                  $functionName = $node[2];
2740                  $functionParameters = $node[3];
2741                  $functionPlacement = $node[4];
2742  
2743                  $newNode = array( $nodeType,
2744                                    false,
2745                                    $functionName,
2746                                    $functionParameters,
2747                                    $functionPlacement );
2748  
2749                  $parameterText = 'No parameters';
2750                  if ( $functionParameters )
2751                  {
2752                      $parameterText = "Parameters: ". implode( ', ', array_keys( $functionParameters ) );
2753                  }
2754                  if ( $useComments )
2755                  {
2756                      $php->addComment( "Function: $functionName, $parameterText", true, true, array( 'spacing' => $currentParameters['spacing'] ) );
2757                      $originalText = eZTemplateCompiler::fetchTemplatePiece( $functionPlacement );
2758                      $php->addComment( '{' . $originalText . '}', true, true, array( 'spacing' => $currentParameters['spacing'] ) );
2759                  }
2760                  if ( isset( $node[5] ) )
2761                  {
2762                      $functionHook = $node[5];
2763                      $functionHookCustomFunction = $functionHook['function'];
2764                      if ( $functionHookCustomFunction )
2765                      {
2766                          $functionHookCustomFunction = array_merge( array( 'add-function-name' => false,
2767                                                                            'add-hook-name' => false,
2768                                                                            'add-template-handler' => true,
2769                                                                            'add-function-hook-data' => false,
2770                                                                            'add-function-parameters' => true,
2771                                                                            'add-function-placement' => false,
2772                                                                            'add-calculated-namespace' => false,
2773                                                                            'add-namespace' => true,
2774                                                                            'add-input' => false,
2775                                                                            'return-value' => false ),
2776                                                                     $functionHookCustomFunction );
2777                          if ( !isset( $parameters['hook-result-variable-counter'][$functionName] ) )
2778                              $parameters['hook-result-variable-counter'][$functionName] = 0;
2779                          if ( $functionHookCustomFunction['return-value'] )
2780                              $parameters['hook-result-variable-counter'][$functionName]++;
2781                          $hookResultName = $functionName . 'Result' . $parameters['hook-result-variable-counter'][$functionName];
2782                          if ( $functionHookCustomFunction['add-input'] )
2783                              $parameters['hook-result-variable-counter'][$functionName]--;
2784                          $functionHookCustomFunctionName = $functionHookCustomFunction['name'];
2785                          $codeText = '';
2786                          if ( $functionHookCustomFunction['return-value'] )
2787                              $codeText = "\$$hookResultName = ";
2788                          if ( $functionHookCustomFunction['static'] )
2789                          {
2790                              $hookClassName = $functionHookCustomFunction['class-name'];
2791                              $codeText .= "$hookClassName::$functionHookCustomFunctionName( ";
2792                          }
2793                          else
2794                              $codeText .= "\$functionObject->$functionHookCustomFunctionName( ";
2795                          $codeTextLength = strlen( $codeText );
2796  
2797                          $functionNameText = $php->variableText( $functionName, 0, 0, false );
2798                          $functionChildrenText = $php->variableText( $functionChildren, $codeTextLength, 0, false );
2799  
2800                          $inputFunctionParameters = $functionParameters;
2801                          if ( $functionHookCustomFunction['add-calculated-namespace'] )
2802                              unset( $inputFunctionParameters['name'] );
2803                          $functionParametersText = $php->variableText( $inputFunctionParameters, $codeTextLength, 0, false );
2804  
2805                          $functionPlacementText = $php->variableText( $functionPlacement, $codeTextLength, 0, false );
2806                          $functionHookText = $php->variableText( $functionHook, $codeTextLength, 0, false );
2807  
2808                          $functionHookName = $functionHook['name'];
2809                          $functionHookNameText = $php->variableText( $functionHookName, 0, 0, false );
2810  
2811                          $codeParameters = array();
2812                          if ( $functionHookCustomFunction['add-function-name'] )
2813                              $codeParameters[] = $functionNameText;
2814                          if ( $functionHookCustomFunction['add-hook-name'] )
2815                              $codeParameters[] = $functionHookNameText;
2816                          if ( $functionHookCustomFunction['add-function-hook-data'] )
2817                              $codeParameters[] = $functionHookText;
2818                          if ( $functionHookCustomFunction['add-template-handler'] )
2819                              $codeParameters[] = "\$tpl";
2820                          if ( $functionHookCustomFunction['add-function-parameters'] )
2821                              $codeParameters[] = $functionParametersText;
2822                          if ( $functionHookCustomFunction['add-function-placement'] )
2823                              $codeParameters[] = $functionPlacementText;
2824                          if ( $functionHookCustomFunction['add-calculated-namespace'] )
2825                          {
2826                              $name = '';
2827                              if ( isset( $functionParameters['name'] ) )
2828                              {
2829                                  $nameParameter = $functionParameters['name'];
2830                                  $nameInspection = eZTemplateCompiler::inspectVariableData( $tpl,
2831                                                                                             $nameParameter, $functionPlacement,
2832                                                                                             $resourceData );
2833                                  if ( $nameInspection['is-constant'] and
2834                                       !$nameInspection['is-variable'] and
2835                                       !$nameInspection['has-attributes'] and
2836                                       !$nameInspection['has-operators'] )
2837                                  {
2838                                      $nameData = $nameParameter[0][1];
2839                                      $nameText = $php->variableText( $nameData, 0, 0, false );
2840                                      $php->addCodePiece( "if ( \$currentNamespace != '' )
2841      \$name = \$currentNamespace . ':' . $nameText;
2842  else
2843      \$name = $nameText;\n", array( 'spacing' => $currentParameters['spacing'] ) );
2844                                      $codeParameters[] = "\$name";
2845                                  }
2846                                  else
2847                                  {
2848                                      $persistence = array();
2849                                      $knownTypes = array();
2850                                      eZTemplateCompiler::generateVariableCode( $php, $tpl, $nameParameter, $knownTypes, $nameInspection,
2851                                                                                $persistence,
2852                                                                                array( 'variable' => 'name',
2853                                                                                       'counter' => 0 ),
2854                                                                                $resourceData );
2855                                      $php->addCodePiece( "if " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( \$currentNamespace != '' )
2856  {
2857      if ( \$name != '' )
2858          \$name = \"\$currentNamespace:\$name\";
2859      else
2860          \$name = \$currentNamespace;
2861  }\n", array( 'spacing' => $currentParameters['spacing'] ) );
2862                                      $codeParameters[] = "\$name";
2863                                  }
2864                              }
2865                              else
2866                              {
2867                                  $codeParameters[] = "\$currentNamespace";
2868                              }
2869                          }
2870                          if ( $functionHookCustomFunction['add-namespace'] )
2871                              $codeParameters[] = "\$rootNamespace, \$currentNamespace";
2872                          if ( $functionHookCustomFunction['add-input'] )
2873                              $codeParameters[] = "\$$hookResultName";
2874                          $codeText .= implode( ",\n" . str_repeat( ' ', $codeTextLength ),
2875                                                $codeParameters );
2876                          $codeText .= " );\n";
2877                          if ( $functionHookCustomFunction['static'] )
2878                          {
2879                              $hookFile = $functionHookCustomFunction['php-file'];
2880                              $hookFileText = $php->variableText( $hookFile, 0, 0, false );
2881                              $php->addCodePiece( "include_once( $hookFileText );\n", array( 'spacing' => $currentParameters['spacing'] ) );
2882                          }
2883                          else
2884                              $php->addCodePiece( "\$functionObject = \$tpl->fetchFunctionObject( $functionNameText );\n", array( 'spacing' => $currentParameters['spacing'] ) );
2885                          $php->addCodePiece( $codeText, array( 'spacing' => $currentParameters['spacing'] ) );
2886                      }
2887                      else
2888                      {
2889                          $functionNameText = $php->variableText( $functionName, 0, 0, false );
2890                          $functionChildrenText = $php->variableText( $functionChildren, 52, 0, false );
2891                          $functionParametersText = $php->variableText( $functionParameters, 52, 0, false );
2892                          $functionPlacementText = $php->variableText( $functionPlacement, 52, 0, false );
2893  
2894                          $functionHookText = $php->variableText( $functionHook, 52, 0, false );
2895                          $functionHookName = $functionHook['name'];
2896                          $functionHookNameText = $php->variableText( $functionHookName, 0, 0, false );
2897                          $functionHookParameters = $functionHook['parameters'];
2898                          $php->addCodePiece( "\$functionObject = \$tpl->fetchFunctionObject( $functionNameText );
2899  \$hookResult = \$functionObject->templateHookProcess( $functionNameText, $functionHookNameText,
2900                                                      $functionHookText,
2901                                                      \$tpl,
2902                                                      $functionParametersText,
2903                                                      $functionPlacementText,
2904                                                      \$rootNamespace, \$currentNamespace );
2905  ", array( 'spacing' => $currentParameters['spacing'] ) );
2906                      }
2907                  }
2908                  else
2909                  {
2910                      $textName = eZTemplateCompiler::currentTextName( $parameters );
2911                      $functionNameText = $php->variableText( $functionName, 0, 0, false );
2912                      $functionChildrenText = $php->variableText( $functionChildren, 22, 0, false );
2913                      $functionParametersText = $php->variableText( $functionParameters, 22, 0, false );
2914                      $functionPlacementText = $php->variableText( $functionPlacement, 22, 0, false );
2915                      $php->addCodePiece( "\$textElements = array();
2916  \$tpl->processFunction( $functionNameText, \$textElements,
2917                         $functionChildrenText,
2918                         $functionParametersText,
2919                         $functionPlacementText,
2920                         \$rootNamespace, \$currentNamespace );
2921  \$$textName .= implode( '', \$textElements );\n", array( 'spacing' => $currentParameters['spacing'] ) );
2922                  }
2923              }
2924              $php->addSpace();
2925          }
2926      }
2927  
2928      /*!
2929       Generates PHP code which will do namespace merging.
2930       The namespace to merge with is specified in \a $namespace and
2931       the scope of the merging is defined by \a $namespaceScope.
2932      */
2933      function generateMergeNamespaceCode( &$php, &$tpl, $namespace, $namespaceScope, $parameters = array(), $skipSimpleAssignment = false )
2934      {
2935          if ( $namespace != '' )
2936          {
2937              if ( $namespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_GLOBAL )
2938              {
2939                  $php->addVariable( 'namespace', $namespace, EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, $parameters );
2940              }
2941              else if ( $namespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_LOCAL )
2942              {
2943                  $php->addCodePiece( "\$namespace = \$rootNamespace;
2944  if ( \$namespace == '' )
2945      \$namespace = \"$namespace\";
2946  else
2947      \$namespace .= ':$namespace';
2948  ", $parameters );
2949              }
2950              else if ( $namespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_RELATIVE )
2951              {
2952                  $php->addCodePiece( "\$namespace = \$currentNamespace;
2953  if ( \$namespace == '' )
2954      \$namespace = \"$namespace\";
2955  else
2956      \$namespace .= ':$namespace';
2957  ", $parameters );
2958              }
2959          }
2960          else
2961          {
2962              if ( $namespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_GLOBAL )
2963              {
2964                  if ( $skipSimpleAssignment )
2965                      return "''";
2966                  $php->addVariable( 'namespace', '', EZ_PHPCREATOR_VARIABLE_ASSIGNMENT, $parameters );
2967              }
2968              else if ( $namespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_LOCAL )
2969              {
2970                  if ( $skipSimpleAssignment )
2971                      return "\$rootNamespace";
2972                  $php->addCodePiece( "\$namespace = \$rootNamespace;\n", $parameters );
2973              }
2974              else if ( $namespaceScope == EZ_TEMPLATE_NAMESPACE_SCOPE_RELATIVE )
2975              {
2976                  if ( $skipSimpleAssignment )
2977                      return "\$currentNamespace";
2978                  $php->addCodePiece( "\$namespace = \$currentNamespace;\n", $parameters );
2979              }
2980          }
2981          return true;
2982      }
2983  
2984      /*!
2985       Generates PHP code for the variable node \a $node.
2986       Use generateVariableDataCode if you want to create code for arbitrary variable data structures.
2987      */
2988      function generateVariableCode( &$php, &$tpl, $node, &$knownTypes, $dataInspection, $parameters, &$resourceData )
2989      {
2990          $variableData = $node[2];
2991          $persistence = array();
2992          eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $variableData, $knownTypes, $dataInspection, $persistence, $parameters, $resourceData );
2993      }
2994  
2995      /*!
2996       Generates PHP code for the variable tree structure in \a $variableData.
2997       The code will contain string, numeric and identifier assignment,
2998       variable lookup, attribute lookup and operator execution.
2999       Use generateVariableCode if you want to create code for a variable tree node.
3000      */
3001      function generateVariableDataCode( &$php, &$tpl, $variableData, &$knownTypes, $dataInspection, &$persistence, $parameters, &$resourceData )
3002      {
3003          $staticTypeMap = array( EZ_TEMPLATE_TYPE_STRING => 'string',
3004                                  EZ_TEMPLATE_TYPE_NUMERIC => 'numeric',
3005                                  EZ_TEMPLATE_TYPE_IDENTIFIER => 'string',
3006                                  EZ_TEMPLATE_TYPE_ARRAY => 'array',
3007                                  EZ_TEMPLATE_TYPE_BOOLEAN => 'boolean' );
3008  
3009          $variableAssignmentName = $parameters['variable'];
3010          $variableAssignmentCounter = $parameters['counter'];
3011          $spacing = 0;
3012          $optimizeNode = false;
3013          if ( isset( $parameters['spacing'] ) )
3014              $spacing = $parameters['spacing'];
3015          if ( $variableAssignmentCounter > 0 )
3016              $variableAssignmentName .= $variableAssignmentCounter;
3017  
3018          // We need to unset the assignment variable before any elements are processed
3019          // This ensures that we don't work on existing variables
3020          $php->addCodePiece( "unset( \$$variableAssignmentName );\n", array( 'spacing' => $spacing ) );
3021  
3022          if ( is_array( $variableData ) )
3023          {
3024          foreach ( $variableData as $index => $variableDataItem )
3025          {
3026              $variableDataType = $variableDataItem[0];
3027              if ( $variableDataType == EZ_TEMPLATE_TYPE_STRING or
3028                   $variableDataType == EZ_TEMPLATE_TYPE_NUMERIC or
3029                   $variableDataType == EZ_TEMPLATE_TYPE_IDENTIFIER or
3030                   $variableDataType == EZ_TEMPLATE_TYPE_ARRAY or
3031                   $variableDataType == EZ_TEMPLATE_TYPE_BOOLEAN )
3032              {
3033                  $knownTypes = array_unique( array_merge( $knownTypes, array( $staticTypeMap[$variableDataType] ) ) );
3034                  $dataValue = $variableDataItem[1];
3035                  $dataText = $php->variableText( $dataValue, 0, 0, false );
3036                  $php->addCodePiece( "\$$variableAssignmentName = $dataText;\n", array( 'spacing' => $spacing ) );
3037              }
3038              else if ( $variableDataType == EZ_TEMPLATE_TYPE_OPTIMIZED_NODE )
3039              {
3040                  $optimizeNode = true;
3041                  if ( !isset( $resourceData['node-object-cached'] ) )
3042                      $tpl->error( "Attribute node-object-cached of variable \$resourceData was not found but variable node EZ_TEMPLATE_TYPE_OPTIMIZED_NODE is still present. This should not happen" );
3043                  $php->addCodePiece("\$$variableAssignmentName = \$nod_{$resourceData['uniqid']};\n");
3044  
3045                  // If optimized node is not set, use unoptimized code.
3046                  $php->addCodePiece( "if ( !\$$variableAssignmentName )\n{\n" );
3047              }
3048              else if ( $variableDataType == EZ_TEMPLATE_TYPE_OPTIMIZED_ARRAY_LOOKUP )
3049              {
3050                  $code = ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/\n" ) : "" );
3051  
3052                  // This code is used a lot so we create a variable for it
3053                  $phpVar = "\$$variableAssignmentName";
3054                  $indexName = "'{$variableDataItem[1][0][1]}'";
3055  
3056                  // Add sanity checking
3057                  $code .= ( "if ( !isset( {$phpVar}[{$indexName}] ) )\n" .
3058                             "{\n" .
3059                             "    \$tpl->error( 'eZTemplateCompiler" . ( $resourceData['use-comments'] ? ( ":" . __LINE__ ) : "" ) . "', \"PHP variable \\$phpVar"."[{$indexName}] does not exist, cannot fetch the value.\" );\n" .
3060                             "    $phpVar = null;\n" .
3061                             "}\n" .
3062                             "else\n    " );
3063  
3064                  // Add the actual code
3065                  $code .= "$phpVar = {$phpVar}[{$indexName}];\n";
3066  
3067                  $php->addCodePiece( $code );
3068              }
3069              else if ( $variableDataType == EZ_TEMPLATE_TYPE_OPTIMIZED_ATTRIBUTE_LOOKUP )
3070              {
3071                  $code = ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/\n" ) : "" );
3072                  $code .= <<<END
3073  if ( !is_object( \${$variableAssignmentName} ) )
3074  {
3075      \${$variableAssignmentName} = null;
3076  }
3077  else if ( \${$variableAssignmentName}->hasAttribute( "{$variableDataItem[1][0][1]}" ) )
3078  {
3079      \${$variableAssignmentName} = \${$variableAssignmentName}->attribute( "{$variableDataItem[1][0][1]}" );
3080  }
3081  
3082  END;
3083                  $php->addCodePiece($code);
3084              }
3085              else if ( $variableDataType == EZ_TEMPLATE_TYPE_OPTIMIZED_CONTENT_CALL )
3086              {
3087                  // Line number comment
3088                  $code = ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/\n" ) : "" );
3089  
3090                  // This code is used a lot so we create a variable for it
3091                  $phpVar = "\$$variableAssignmentName";
3092  
3093                  // Add sanity checking
3094                  $code .= ( "if ( !is_object( $phpVar ) )\n" .
3095                             "{\n" .
3096                             "    \$tpl->error( 'eZTemplateCompiler" . ( $resourceData['use-comments'] ? ( ":" . __LINE__ ) : "" ) . "', \"PHP variable \\$phpVar is not an object, cannot fetch content()\" );\n" .
3097                             "    $phpVar = null;\n" .
3098                             "}\n" .
3099                             "else\n" .
3100                             "{\n" );
3101  
3102                  // Add the actual code
3103                  $code .= "     {$phpVar}Tmp = {$phpVar}->content();\n" .
3104                           "     unset( $phpVar );\n" .
3105                           "     $phpVar = {$phpVar}Tmp;\n" .
3106                           "     unset( {$phpVar}Tmp );\n}\n";
3107  
3108                  $php->addCodePiece( $code );
3109              }
3110              else if ( $variableDataType == EZ_TEMPLATE_TYPE_PHP_VARIABLE )
3111              {
3112                  $knownTypes = array();
3113                  $phpVariableName = $variableDataItem[1];
3114                  $php->addCodePiece( "\$$variableAssignmentName = \$$phpVariableName;\n", array( 'spacing' => $spacing ) );
3115              }
3116              else if ( $variableDataType == EZ_TEMPLATE_TYPE_VARIABLE )
3117              {
3118                  $knownTypes = array();
3119                  $namespace = $variableDataItem[1][0];
3120                  $namespaceScope = $variableDataItem[1][1];
3121                  $variableName = $variableDataItem[1][2];
3122                  $namespaceText = eZTemplateCompiler::generateMergeNamespaceCode( $php, $tpl, $namespace, $namespaceScope, array( 'spacing' => $spacing ), true );
3123                  if ( !is_string( $namespaceText ) )
3124                      $namespaceText = "\$namespace";
3125                  $variableNameText = $php->variableText( $variableName, 0, 0, false );
3126                  $code = "unset( \$$variableAssignmentName );\n";
3127                  $code .= "\$$variableAssignmentName = ( array_key_exists( $namespaceText, \$vars ) and array_key_exists( $variableNameText, \$vars[$namespaceText] ) ) ? \$vars[$namespaceText][$variableNameText] : null;\n";
3128                  $php->addCodePiece( $code,
3129                                      array( 'spacing' => $spacing ) );
3130              }
3131              else if ( $variableDataType == EZ_TEMPLATE_TYPE_ATTRIBUTE )
3132              {
3133                  $knownTypes = array();
3134                  $newParameters = $parameters;
3135                  $newParameters['counter'] += 1;
3136                  $tmpVariableAssignmentName = $newParameters['variable'];
3137                  $tmpVariableAssignmentCounter = $newParameters['counter'];
3138                  if ( $tmpVariableAssignmentCounter > 0 )
3139                      $tmpVariableAssignmentName .= $tmpVariableAssignmentCounter;
3140                  if ( eZTemplateNodeTool::isStaticElement( $variableDataItem[1] ) )
3141                  {
3142                      $attributeStaticValue = eZTemplateNodeTool::elementStaticValue( $variableDataItem[1] );
3143                      $attributeText = $php->variableText( $attributeStaticValue, 0, 0, false );
3144                  }
3145                  else
3146                  {
3147                      $newParameters['counter'] += 1;
3148                      $tmpKnownTypes = array();
3149                      eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $variableDataItem[1], $tmpKnownTypes, $dataInspection,
3150                                                                    $persistence, $newParameters, $resourceData );
3151                      $newVariableAssignmentName = $newParameters['variable'];
3152                      $newVariableAssignmentCounter = $newParameters['counter'];
3153                      if ( $newVariableAssignmentCounter > 0 )
3154                          $newVariableAssignmentName .= $newVariableAssignmentCounter;
3155                      $attributeText = "\$$newVariableAssignmentName";
3156                  }
3157                  $php->addCodePiece( "\$$tmpVariableAssignmentName = compiledFetchAttribute( \$$variableAssignmentName, $attributeText );\n" .
3158                                      "unset( \$$variableAssignmentName );\n" .
3159                                      "\$$variableAssignmentName = \$$tmpVariableAssignmentName;\n",
3160                                      array( 'spacing' => $spacing ) );
3161  
3162                  // End if optimized node object is null/false. See also eZTemplateOptimizer::optimizeVariable()
3163                  if ( $optimizeNode &&
3164                       $index == 3 )
3165                  {
3166                      $php->addCodePiece( "}\n" );
3167                  }
3168              }
3169              else if ( $variableDataType == EZ_TEMPLATE_TYPE_OPERATOR )
3170              {
3171                  $knownTypes = array();
3172                  $operatorParameters = $variableDataItem[1];
3173                  $operatorName = $operatorParameters[0];
3174                  $operatorParameters = array_splice( $operatorParameters, 1 );
3175                  $operatorNameText = $php->variableText( $operatorName, 0, 0, false );
3176                  $operatorParametersText = $php->variableText( $operatorParameters, 23, 0, false );
3177  
3178                  $operatorHint = eZTemplateCompiler::operatorHint( $tpl, $operatorName );
3179                  if ( isset( $operatorHint['output'] ) and $operatorHint['output'] )
3180                  {
3181                      if ( isset( $operatorHint['output-type'] ) )
3182                      {
3183                          $knownType = $operatorHint['output-type'];
3184                          if ( is_array( $knownType ) )
3185                              $knownTypes = array_merge( $knownTypes, $knownType );
3186                          else
3187                              $knownTypes[] = $knownType;
3188                          $knownTypes = array_unique( $knownTypes );
3189                      }
3190                      else
3191                          $knownTypes[] = 'static';
3192                  }
3193  
3194                  $php->addCodePiece( "if (! isset( \$$variableAssignmentName ) ) \$$variableAssignmentName = NULL;\n", array ( 'spacing' => $spacing ) );
3195                  $php->addCodePiece( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$variableAssignmentName ) and method_exists( \$$variableAssignmentName, 'templateValue' ) )\n" .
3196                                                    "    \$$variableAssignmentName = \$$variableAssignmentName" . "->templateValue();\n" );
3197                  $php->addCodePiece( "\$" . $variableAssignmentName . "Data = array( 'value' => \$$variableAssignmentName );
3198  \$tpl->processOperator( $operatorNameText,
3199                         $operatorParametersText,
3200                         \$rootNamespace, \$currentNamespace, \$" . $variableAssignmentName . "Data, false, false );
3201  \$$variableAssignmentName = \$" . $variableAssignmentName . "Data['value'];
3202  unset( \$" . $variableAssignmentName . "Data );\n",
3203                                      array( 'spacing' => $spacing ) );
3204              }
3205              else if ( $variableDataType == EZ_TEMPLATE_TYPE_VOID )
3206              {
3207              }
3208              else if ( $variableDataType == EZ_TEMPLATE_TYPE_DYNAMIC_ARRAY )
3209              {
3210                  $knownTypes = array_unique( array_merge( $knownTypes, array( 'array' ) ) );
3211                  $code = '%output% = array( ';
3212  
3213                  $matchMap = array( '%input%', '%output%' );
3214                  $replaceMap = array( '$' . $variableAssignmentName, '$' . $variableAssignmentName );
3215                  $unsetList = array();
3216                  $counter = 1;
3217                  $paramCount = 0;
3218  
3219                  $values = $variableDataItem[2];
3220                  $newParameters = $parameters;
3221                  foreach ( $values as $key => $value )
3222                  {
3223                      if ( $paramCount != 0 )
3224                      {
3225                          $code .= ', ';
3226                      }
3227                      ++$paramCount;
3228                      $code .= '\'' . $key . '\' => ';
3229                      if( eZTemplateNodeTool::isStaticElement( $value ) )
3230                      {
3231                          $code .= eZPHPCreator::variableText( eZTemplateNodeTool::elementStaticValue( $value ), 0, 0, false );
3232                          continue;
3233                      }
3234                      $code .= '%' . $counter . '%';
3235                      $newParameters['counter'] += 1;
3236                      $newVariableAssignmentName = $newParameters['variable'];
3237                      $newVariableAssignmentCounter = $newParameters['counter'];
3238                      if ( $newVariableAssignmentCounter > 0 )
3239                          $newVariableAssignmentName .= $newVariableAssignmentCounter;
3240                      $matchMap[] = '%' . $counter . '%';
3241                      $replaceMap[] = '$' . $newVariableAssignmentName;
3242                      $unsetList[] = $newVariableAssignmentName;
3243                      $tmpKnownTypes = array();
3244                      eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $value, $tmpKnownTypes, $dataInspection,
3245                                                                    $persistence, $newParameters, $resourceData );
3246                      ++$counter;
3247                  }
3248  
3249                  $code .= ' );';
3250                  $code = str_replace( $matchMap, $replaceMap, $code );
3251                  $php->addCodePiece( $code, array( 'spacing' => $spacing ) );
3252                  $php->addVariableUnsetList( $unsetList, array( 'spacing' => $spacing ) );
3253              }
3254              else if ( $variableDataType == EZ_TEMPLATE_TYPE_INTERNAL_CODE_PIECE )
3255              {
3256                  $code = $variableDataItem[1];
3257                  $values = false;
3258                  $matchMap = array( '%input%', '%output%' );
3259                  $replaceMap = array( '$' . $variableAssignmentName, '$' . $variableAssignmentName );
3260                  $unsetList = array();
3261                  $counter = 1;
3262                  if ( isset( $variableDataItem[3] ) && is_array( $variableDataItem[3] ) )
3263                  {
3264                      $newParameters = $parameters;
3265                      $values = $variableDataItem[3];
3266                      foreach ( $values as $value )
3267                      {
3268                          $newParameters['counter'] += 1;
3269                          $newVariableAssignmentName = $newParameters['variable'];
3270                          $newVariableAssignmentCounter = $newParameters['counter'];
3271                          if ( $newVariableAssignmentCounter > 0 )
3272                              $newVariableAssignmentName .= $newVariableAssignmentCounter;
3273                          if ( eZTemplateNodeTool::isStaticElement( $value ) )
3274                          {
3275                              $staticValue = eZTemplateNodeTool::elementStaticValue( $value );
3276                              $staticValueText = $php->variableText( $staticValue, 0, 0, false );
3277                              if ( preg_match( "/%code$counter%/", $code ) )
3278                              {
3279                                  $matchMap[] = '%code' . $counter . '%';
3280                                  $replaceMap[] = '';
3281                              }
3282                              $matchMap[] = '%' . $counter . '%';
3283                              $replaceMap[] = $staticValueText;
3284                          }
3285                          else
3286                          {
3287                              $matchMap[] = '%' . $counter . '%';
3288                              $replaceMap[] = '$' . $newVariableAssignmentName;
3289                              $unsetList[] = $newVariableAssignmentName;
3290                              if ( preg_match( "/%code$counter%/", $code ) )
3291                              {
3292                                  $tmpPHP = new eZPHPCreator( '', '', eZTemplateCompiler::TemplatePrefix() );
3293                                  $tmpKnownTypes = array();
3294                                  eZTemplateCompiler::generateVariableDataCode( $tmpPHP, $tpl, $value, $tmpKnownTypes, $dataInspection,
3295                                                                                $persistence, $newParameters, $resourceData );
3296                                  $newCode = $tmpPHP->fetch( false );
3297                                  if ( count( $tmpKnownTypes ) == 0 or in_array( 'objectproxy', $tmpKnownTypes ) )
3298                                  {
3299                                      $newCode .= ( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$newVariableAssignmentName ) and method_exists( \$$newVariableAssignmentName, 'templateValue' ) )\n" .
3300                                                    "    \$$newVariableAssignmentName = \$$newVariableAssignmentName" . "->templateValue();\n" );
3301                                  }
3302                                  $matchMap[] = '%code' . $counter . '%';
3303                                  $replaceMap[] = $newCode;
3304                              }
3305                              else
3306                              {
3307                                  $tmpKnownTypes = array();
3308                                  eZTemplateCompiler::generateVariableDataCode( $php, $tpl, $value, $tmpKnownTypes, $dataInspection,
3309                                                                                $persistence, $newParameters, $resourceData );
3310                                  if ( !$parameters['treat-value-as-non-object'] and ( count( $tmpKnownTypes ) == 0 or in_array( 'objectproxy', $tmpKnownTypes ) ) )
3311                                  {
3312                                      $php->addCodePiece( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$newVariableAssignmentName ) and method_exists( \$$newVariableAssignmentName, 'templateValue' ) )\n" .
3313                                                          "    \$$newVariableAssignmentName = \$$newVariableAssignmentName" . "->templateValue();\n",
3314                                                          array( 'spacing' => $spacing ) );
3315                                  }
3316                              }
3317                          }
3318                          ++$counter;
3319                      }
3320                  }
3321                  if ( isset( $variableDataItem[4] ) && ( $variableDataItem[4] !== false ) )
3322                  {
3323                      $values = $variableDataItem[4];
3324  
3325                      for ( $i = 0; $i < $values; $i++ )
3326                      {
3327                          $newParameters['counter'] += 1;
3328                          $newVariableAssignmentName = $newParameters['variable'];
3329                          $newVariableAssignmentCounter = $newParameters['counter'];
3330                          if ( $newVariableAssignmentCounter > 0 )
3331                              $newVariableAssignmentName .= $newVariableAssignmentCounter;
3332                          $matchMap[] = '%tmp' . ( $i + 1 ) . '%';
3333                          $replaceMap[] = '$' . $newVariableAssignmentName;
3334                          $unsetList[] = $newVariableAssignmentName;
3335                      }
3336                  }
3337                  if ( isset( $variableDataItem[5] ) and $variableDataItem[5] )
3338                  {
3339                      if ( is_array( $variableDataItem[5] ) )
3340                          $knownTypes = array_unique( array_merge( $knownTypes, $variableDataItem[5] ) );
3341                      else if ( is_string( $variableDataItem[5] ) )
3342                          $knownTypes = array_unique( array_merge( $knownTypes, array( $variableDataItem[5] ) ) );
3343                      else
3344                          $knownTypes = array_unique( array_merge( $knownTypes, array( 'static' ) ) );
3345                  }
3346                  $code = str_replace( $matchMap, $replaceMap, $code );
3347                  $php->addCodePiece( $code, array( 'spacing' => $spacing ) );
3348                  $php->addVariableUnsetList( $unsetList, array( 'spacing' => $spacing ) );
3349              }
3350          }
3351          }
3352          // After the entire expression line is done we try to extract the actual value if proxies are used
3353          $php->addCodePiece( "if (! isset( \$$variableAssignmentName ) ) \$$variableAssignmentName = NULL;\n" );
3354          $php->addCodePiece( "while " . ( $resourceData['use-comments'] ? ( "/*TC:" . __LINE__ . "*/" ) : "" ) . "( is_object( \$$variableAssignmentName ) and method_exists( \$$variableAssignmentName, 'templateValue' ) )\n" .
3355                              "    \$$variableAssignmentName = \$$variableAssignmentName" . "->templateValue();\n" );
3356      }
3357  }
3358  
3359  ?>


Généré le : Sat Feb 24 10:30:04 2007 par Balluche grâce à PHPXref 0.7