eZ Publish  [4.0]
eztemplateforfunction.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZTemplateForFunction class
00004 //
00005 // Created on: <21-Feb-2005 12:38:26 vs>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*!
00032   \class eZTemplateForFunction eztemplateforfunction.php
00033   \ingroup eZTemplateFunctions
00034   \brief FOR loop
00035 
00036   Syntax:
00037 \code
00038     {for <number> to <number> as $itemVar [sequence <array> as $seqVar]}
00039         [{delimiter}...{/delimiter}]
00040         [{break}]
00041         [{continue}]
00042         [{skip}]
00043     {/for}
00044 \endcode
00045 
00046   Examples:
00047 \code
00048     {for 1 to 5 as $i}
00049         i: {$i}<br/>
00050     {/for}
00051 
00052     {for 5 to 1 as $i}
00053         i: {$i}<br/>
00054     {/for}
00055 \endcode
00056 */
00057 
00058 class eZTemplateForFunction
00059 {
00060     const FUNCTION_NAME = 'for';
00061 
00062     /*!
00063      * Returns an array of the function names, required for eZTemplate::registerFunctions.
00064      */
00065     function &functionList()
00066     {
00067         $functionList = array( eZTemplateForFunction::FUNCTION_NAME );
00068         return $functionList;
00069     }
00070 
00071     /*!
00072      * Returns the attribute list.
00073      * key:   parameter name
00074      * value: can have children
00075      */
00076     function attributeList()
00077     {
00078         return array( 'delimiter' => true,
00079                       'break'     => false,
00080                       'continue'  => false,
00081                       'skip'      => false );
00082     }
00083 
00084 
00085     /*!
00086      * Returns the array with hits for the template compiler.
00087      */
00088     function functionTemplateHints()
00089     {
00090         return array( eZTemplateForFunction::FUNCTION_NAME => array( 'parameters' => true,
00091                                                               'static' => false,
00092                                                               'transform-parameters' => true,
00093                                                               'tree-transformation' => true ) );
00094     }
00095 
00096     /*!
00097      * Compiles the function and its children into PHP code.
00098      */
00099     function templateNodeTransformation( $functionName, &$node,
00100                                          $tpl, $parameters, $privateData )
00101     {
00102         // {for <first_val> to <last_val> as $<loop_var> [sequence <sequence_array> as $<sequence_var>]}
00103 
00104         $newNodes = array();
00105         $tpl->ForCounter++;
00106         $nodePlacement = eZTemplateNodeTool::extractFunctionNodePlacement( $node );
00107         $uniqid        =  md5( $nodePlacement[2] ) . "_" . $tpl->ForCounter;
00108 
00109         require_once( 'lib/eztemplate/classes/eztemplatecompiledloop.php' );
00110         $loop = new eZTemplateCompiledLoop( eZTemplateForFunction::FUNCTION_NAME,
00111                                             $newNodes, $parameters, $nodePlacement, $uniqid,
00112                                             $node, $tpl, $privateData );
00113 
00114         $variableStack   = "for_variable_stack_$uniqid";
00115         $namesArray = array( "for_firstval_$uniqid", "for_lastval_$uniqid", "for_i_$uniqid" );
00116 
00117         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "// for begins" );
00118         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( !isset( \$$variableStack ) ) \$$variableStack = array();" );
00119         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "\$" . $variableStack ."[] = compact( '" . implode( "', '", $namesArray ) . "' );" );
00120 
00121         $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $parameters['first_val'], $nodePlacement, array( 'treat-value-as-non-object' => true ), "for_firstval_$uniqid" );
00122         $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $parameters['last_val'],  $nodePlacement, array( 'treat-value-as-non-object' => true ), "for_lastval_$uniqid"  );
00123 
00124         $loop->initVars();
00125 
00126         // loop header
00127         $modifyLoopCounterCode = "\$for_firstval_$uniqid < \$for_lastval_$uniqid ? \$for_i_${uniqid}++ : \$for_i_${uniqid}--"; // . ";\n";
00128         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "for ( \$for_i_$uniqid = \$for_firstval_$uniqid ; ; $modifyLoopCounterCode )\n{" );
00129         $newNodes[] = eZTemplateNodeTool::createSpacingIncreaseNode();
00130         // Check for index
00131         $indexArray = isset( $parameters['loop_var'][0][1] ) ? $parameters['loop_var'][0][1] : array( "", 2, "default_index_$uniqid" );
00132         $newNodes[] = eZTemplateNodeTool::createVariableNode( false, "for_i_$uniqid", $nodePlacement,
00133                                                               array( 'text-result' => true ), $indexArray, false, true, true );
00134 
00135         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( !( \$for_firstval_$uniqid < \$for_lastval_$uniqid ? " .
00136                                                                "\$for_i_$uniqid <= \$for_lastval_$uniqid : " .
00137                                                                "\$for_i_$uniqid >= \$for_lastval_$uniqid ) )\n" .
00138                                                                "   break;\n" );
00139 
00140         $loop->processBody();
00141 
00142         // loop footer
00143         $newNodes[] = eZTemplateNodeTool::createSpacingDecreaseNode();
00144         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "} // for" );
00145 
00146         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( count( \$$variableStack ) ) extract( array_pop( \$$variableStack ) );\n" );
00147         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "else\n{\n" );
00148         $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( $indexArray );
00149         $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "for_firstval_$uniqid" );
00150         $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "for_lastval_$uniqid" );
00151         $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "for_i_$uniqid" );
00152         $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( $variableStack );
00153         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "}\n" );
00154         $loop->cleanup();
00155         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "// for ends\n" );
00156 
00157         return $newNodes;
00158     }
00159 
00160     /*!
00161      * Actually executes the function and its children (in processed mode).
00162      */
00163     function process( $tpl, &$textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace )
00164     {
00165         /*
00166          * Check function parameters
00167          */
00168 
00169         require_once( 'lib/eztemplate/classes/eztemplateloop.php' );
00170         $loop = new eZTemplateLoop( eZTemplateForFunction::FUNCTION_NAME,
00171                                     $functionParameters, $functionChildren, $functionPlacement,
00172                                     $tpl, $textElements, $rootNamespace, $currentNamespace );
00173 
00174         if ( !$loop->initialized() )
00175             return;
00176 
00177         $loop->parseScalarParamValue( 'first_val', $firstVal, $firstValIsProxy );
00178         $loop->parseScalarParamValue( 'last_val',  $lastVal,  $lastValIsProxy  );
00179 
00180         if ( $firstValIsProxy || $lastValIsProxy )
00181         {
00182             $tpl->error( eZTemplateForFunction::FUNCTION_NAME,
00183                          "Proxy objects ({section} loop iterators) cannot be used to specify the range \n" .
00184                          "(this will lead to indefinite loops in compiled mode).\n" .
00185                          "Please explicitly dereference the proxy object like this: \$current_node.item." );
00186             return;
00187         }
00188 
00189         $loop->parseParamVarName( 'loop_var' , $loopVarName );
00190 
00191         if ( is_null( $firstVal ) || is_null( $lastVal ) || !$loopVarName )
00192         {
00193             $tpl->error( eZTemplateForFunction::FUNCTION_NAME, "Wrong arguments passed." );
00194             return;
00195         }
00196 
00197         if ( !is_numeric( $firstVal ) || !is_numeric( $lastVal ) )
00198         {
00199             $tpl->error( eZTemplateForFunction::FUNCTION_NAME, "Both 'from' and 'to' values can only be numeric." );
00200             return;
00201         }
00202 
00203         $loop->initLoopVariable( $loopVarName );
00204 
00205         /*
00206          * Everything is ok, run the 'for' loop itself
00207          */
00208         for ( $i = $firstVal; $firstVal < $lastVal ? $i <= $lastVal : $i >= $lastVal; )
00209         {
00210             // set loop variable
00211             $tpl->setVariable( $loopVarName, $i, $rootNamespace );
00212 
00213             $loop->setSequenceVar(); // set sequence variable (if specified)
00214             $loop->processDelimiter();
00215             $loop->resetIteration();
00216 
00217             if ( $loop->processChildren() )
00218                 break;
00219 
00220             // increment loop variable here for delimiter to be processed correctly
00221             $firstVal < $lastVal ? $i++ : $i--;
00222 
00223             $loop->incrementSequence();
00224         } // for
00225 
00226         $loop->cleanup();
00227     }
00228 
00229     /*!
00230      * Returns true, telling the template parser that the function can have children.
00231      */
00232     function hasChildren()
00233     {
00234         return true;
00235     }
00236 }
00237 
00238 ?>