PageRenderTime 72ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/eztemplate/classes/eztemplatecompiler.php

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