PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/eztemplate/classes/eztemplateforfunction.php

http://github.com/ezsystems/ezpublish
PHP | 216 lines | 114 code | 36 blank | 66 comment | 10 complexity | e5a1da51679511b4f033a30961422037 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * File containing the eZTemplateForFunction 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 eZTemplateForFunction eztemplateforfunction.php
  12. \ingroup eZTemplateFunctions
  13. \brief FOR loop
  14. Syntax:
  15. \code
  16. {for <number> to <number> as $itemVar [sequence <array> as $seqVar]}
  17. [{delimiter}...{/delimiter}]
  18. [{break}]
  19. [{continue}]
  20. [{skip}]
  21. {/for}
  22. \endcode
  23. Examples:
  24. \code
  25. {for 1 to 5 as $i}
  26. i: {$i}<br/>
  27. {/for}
  28. {for 5 to 1 as $i}
  29. i: {$i}<br/>
  30. {/for}
  31. \endcode
  32. */
  33. class eZTemplateForFunction
  34. {
  35. const FUNCTION_NAME = 'for';
  36. /*!
  37. * Returns an array of the function names, required for eZTemplate::registerFunctions.
  38. */
  39. function functionList()
  40. {
  41. $functionList = array( eZTemplateForFunction::FUNCTION_NAME );
  42. return $functionList;
  43. }
  44. /*!
  45. * Returns the attribute list.
  46. * key: parameter name
  47. * value: can have children
  48. */
  49. function attributeList()
  50. {
  51. return array( 'delimiter' => true,
  52. 'break' => false,
  53. 'continue' => false,
  54. 'skip' => false );
  55. }
  56. /*!
  57. * Returns the array with hits for the template compiler.
  58. */
  59. function functionTemplateHints()
  60. {
  61. return array( eZTemplateForFunction::FUNCTION_NAME => array( 'parameters' => true,
  62. 'static' => false,
  63. 'transform-parameters' => true,
  64. 'tree-transformation' => true ) );
  65. }
  66. /*!
  67. * Compiles the function and its children into PHP code.
  68. */
  69. function templateNodeTransformation( $functionName, &$node,
  70. $tpl, $parameters, $privateData )
  71. {
  72. // {for <first_val> to <last_val> as $<loop_var> [sequence <sequence_array> as $<sequence_var>]}
  73. $newNodes = array();
  74. $tpl->ForCounter++;
  75. $nodePlacement = eZTemplateNodeTool::extractFunctionNodePlacement( $node );
  76. $uniqid = md5( $nodePlacement[2] ) . "_" . $tpl->ForCounter;
  77. $loop = new eZTemplateCompiledLoop( eZTemplateForFunction::FUNCTION_NAME,
  78. $newNodes, $parameters, $nodePlacement, $uniqid,
  79. $node, $tpl, $privateData );
  80. $variableStack = "for_variable_stack_$uniqid";
  81. $namesArray = array( "for_firstval_$uniqid", "for_lastval_$uniqid", "for_i_$uniqid" );
  82. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "// for begins" );
  83. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( !isset( \$$variableStack ) ) \$$variableStack = [];" );
  84. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "\$" . $variableStack ."[] = @compact( '" . implode( "', '", $namesArray ) . "' );" );
  85. $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $parameters['first_val'], $nodePlacement, array( 'treat-value-as-non-object' => true ), "for_firstval_$uniqid" );
  86. $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $parameters['last_val'], $nodePlacement, array( 'treat-value-as-non-object' => true ), "for_lastval_$uniqid" );
  87. $loop->initVars();
  88. // loop header
  89. $modifyLoopCounterCode = "\$for_firstval_$uniqid < \$for_lastval_$uniqid ? \$for_i_${uniqid}++ : \$for_i_${uniqid}--"; // . ";\n";
  90. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "for ( \$for_i_$uniqid = \$for_firstval_$uniqid ; ; $modifyLoopCounterCode )\n{" );
  91. $newNodes[] = eZTemplateNodeTool::createSpacingIncreaseNode();
  92. // Check for index
  93. $indexArray = isset( $parameters['loop_var'][0][1] ) ? $parameters['loop_var'][0][1] : array( "", 2, "default_index_$uniqid" );
  94. $newNodes[] = eZTemplateNodeTool::createVariableNode( false, "for_i_$uniqid", $nodePlacement,
  95. array( 'text-result' => true ), $indexArray, false, true, true );
  96. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( !( \$for_firstval_$uniqid < \$for_lastval_$uniqid ? " .
  97. "\$for_i_$uniqid <= \$for_lastval_$uniqid : " .
  98. "\$for_i_$uniqid >= \$for_lastval_$uniqid ) )\n" .
  99. " break;\n" );
  100. $loop->processBody();
  101. // loop footer
  102. $newNodes[] = eZTemplateNodeTool::createSpacingDecreaseNode();
  103. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "} // for" );
  104. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( count( \$$variableStack ) ) extract( array_pop( \$$variableStack ) );\n" );
  105. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "else\n{\n" );
  106. $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( $indexArray );
  107. $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "for_firstval_$uniqid" );
  108. $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "for_lastval_$uniqid" );
  109. $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "for_i_$uniqid" );
  110. $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( $variableStack );
  111. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "}\n" );
  112. $loop->cleanup();
  113. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "// for ends\n" );
  114. return $newNodes;
  115. }
  116. /*!
  117. * Actually executes the function and its children (in processed mode).
  118. */
  119. function process( $tpl, &$textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace )
  120. {
  121. /*
  122. * Check function parameters
  123. */
  124. $loop = new eZTemplateLoop( eZTemplateForFunction::FUNCTION_NAME,
  125. $functionParameters, $functionChildren, $functionPlacement,
  126. $tpl, $textElements, $rootNamespace, $currentNamespace );
  127. if ( !$loop->initialized() )
  128. return;
  129. $loop->parseScalarParamValue( 'first_val', $firstVal, $firstValIsProxy );
  130. $loop->parseScalarParamValue( 'last_val', $lastVal, $lastValIsProxy );
  131. if ( $firstValIsProxy || $lastValIsProxy )
  132. {
  133. $tpl->error( eZTemplateForFunction::FUNCTION_NAME,
  134. "Proxy objects ({section} loop iterators) cannot be used to specify the range \n" .
  135. "(this will lead to indefinite loops in compiled mode).\n" .
  136. "Please explicitly dereference the proxy object like this: \$current_node.item." );
  137. return;
  138. }
  139. $loop->parseParamVarName( 'loop_var' , $loopVarName );
  140. if ( $firstVal === null || $lastVal === null || !$loopVarName )
  141. {
  142. $tpl->error( eZTemplateForFunction::FUNCTION_NAME, "Wrong arguments passed." );
  143. return;
  144. }
  145. if ( !is_numeric( $firstVal ) || !is_numeric( $lastVal ) )
  146. {
  147. $tpl->error( eZTemplateForFunction::FUNCTION_NAME, "Both 'from' and 'to' values can only be numeric." );
  148. return;
  149. }
  150. $loop->initLoopVariable( $loopVarName );
  151. /*
  152. * Everything is ok, run the 'for' loop itself
  153. */
  154. for ( $i = $firstVal; $firstVal < $lastVal ? $i <= $lastVal : $i >= $lastVal; )
  155. {
  156. // set loop variable
  157. $tpl->setVariable( $loopVarName, $i, $rootNamespace );
  158. $loop->setSequenceVar(); // set sequence variable (if specified)
  159. $loop->processDelimiter();
  160. $loop->resetIteration();
  161. if ( $loop->processChildren() )
  162. break;
  163. // increment loop variable here for delimiter to be processed correctly
  164. $firstVal < $lastVal ? $i++ : $i--;
  165. $loop->incrementSequence();
  166. } // for
  167. $loop->cleanup();
  168. }
  169. /*!
  170. * Returns true, telling the template parser that the function can have children.
  171. */
  172. function hasChildren()
  173. {
  174. return true;
  175. }
  176. }
  177. ?>