PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/eztemplate/classes/eztemplatecompiler.php

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