eZ Publish  [4.0]
eztemplatecompiledloop.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZTemplateCompiledLoop class
00004 //
00005 // Created on: <17-Mar-2005 11:26:59 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 /*!
00033   \class eZTemplateCompiledLoop eztemplatecompiledloop.php
00034   \ingroup eZTemplateFunctions
00035   \brief Common code for compiling the loop functions
00036 */
00037 class eZTemplateCompiledLoop
00038 {
00039     function eZTemplateCompiledLoop( $name, &$newNodes, $parameters, $nodePlacement, $uniqid,
00040                                      $node, $tpl, $privateData )
00041     {
00042         $this->Name          = $name;
00043         $this->Parameters    = $parameters;
00044         $this->NodePlacement = $nodePlacement;
00045         $this->UniqID        = $uniqid;
00046         $this->NewNodes      =& $newNodes;
00047         $this->Node          = $node;
00048         $this->Tpl           = $tpl;
00049         $this->PrivateData   = $privateData;
00050     }
00051 
00052     /*!
00053      * Returns true if sequence has been specified for the loop in its parameters.
00054      */
00055     function hasSequence()
00056     {
00057         return isset( $this->Parameters['sequence_var'] );
00058     }
00059 
00060     /*!
00061      * Destroys PHP and template variables defined by the loop.
00062      */
00063     function cleanup()
00064     {
00065         if ( $this->hasSequence() )
00066             $this->destroySequenceVars();
00067 
00068         $this->NewNodes[] = eZTemplateNodeTool::createCodePieceNode( "\$skipDelimiter = false;" );
00069     }
00070 
00071     /*!
00072     \private
00073     */
00074     function destroySequenceVars()
00075     {
00076         $fName      = $this->Name;
00077         $uniqid     = $this->UniqID;
00078         $this->NewNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "${fName}_sequence_array_$uniqid" );
00079         $this->NewNodes[] = eZTemplateNodeTool::createVariableUnsetNode( "${fName}_sequence_var_$uniqid" );
00080         $this->NewNodes[] = eZTemplateNodeTool::createVariableUnsetNode( $this->Parameters['sequence_var'][0][1] );
00081     }
00082 
00083 
00084     /*!
00085      * Create PHP and template variables representing sequence specified for the loop.
00086      */
00087     function createSequenceVars()
00088     {
00089         if ( !$this->hasSequence() )
00090             return;
00091 
00092         $fName      = $this->Name;
00093         $uniqid     = $this->UniqID;
00094         $this->NewNodes[] = eZTemplateNodeTool::createCodePieceNode( "// creating sequence variables for \{$fName} loop" );
00095         $this->NewNodes[] = eZTemplateNodeTool::createVariableNode( false,
00096                                                                     $this->Parameters['sequence_array'],
00097                                                                     $this->NodePlacement,
00098                                                                     array( 'treat-value-as-non-object' => true, 'text-result' => false ),
00099                                                                     "${fName}_sequence_array_$uniqid" );
00100         $this->NewNodes[] = eZTemplateNodeTool::createCodePieceNode( "\$${fName}_sequence_var_$uniqid = current( \$${fName}_sequence_array_$uniqid );\n" );
00101     }
00102 
00103     /*!
00104      * Export current sequence value to the template variable specified in loop parameters.
00105      */
00106     function setCurrentSequenceValue()
00107     {
00108         if ( !$this->hasSequence() )
00109             return;
00110 
00111         $fName    = $this->Name;
00112         $uniqid   = $this->UniqID;
00113         $seqVar   = "${fName}_sequence_var_$uniqid";
00114         $this->NewNodes[] = eZTemplateNodeTool::createCodePieceNode( "// setting current sequence value" );
00115         $this->NewNodes[] = eZTemplateNodeTool::createVariableNode( false, $seqVar, $this->NodePlacement, array(),
00116                                                                     $this->Parameters['sequence_var'][0][1],
00117                                                                     false, true, true );
00118     }
00119 
00120     /*!
00121      * Increments loop sequence.
00122      */
00123     function iterateSequence()
00124     {
00125         if ( !$this->hasSequence() )
00126             return;
00127 
00128         $fName    = $this->Name;
00129         $uniqid   = $this->UniqID;
00130         $seqArray = "${fName}_sequence_array_$uniqid";
00131         $seqVar   = "${fName}_sequence_var_$uniqid";
00132         $alterSeqValCode =
00133             "if ( ( \$$seqVar = next( \$$seqArray ) ) === false )\n" .
00134             "{\n" .
00135             "   reset( \$$seqArray );\n" .
00136             "   \$$seqVar = current( \$$seqArray );\n" .
00137             "}\n";
00138         $this->NewNodes[] = eZTemplateNodeTool::createCodePieceNode( "// sequence iteration" );
00139         $this->NewNodes[] = eZTemplateNodeTool::createCodePieceNode( $alterSeqValCode );
00140     }
00141 
00142 
00143     /*
00144      * Compiles loop children (=code residing between start and end tags of the loop).
00145      * Besides, does special handling of {break}, {continue}, {skip} and {delimiter} functions.
00146      * \return true if the caller loop should break, false otherwise
00147      */
00148     function processChildren()
00149     {
00150         // process the loop body
00151         $children            = eZTemplateNodeTool::extractFunctionNodeChildren( $this->Node );
00152         $transformedChildren = eZTemplateCompiler::processNodeTransformationNodes( $this->Tpl, $this->Node, $children, $this->PrivateData );
00153 
00154         $childrenNodes = array();
00155         $delimiter = null;
00156 
00157         if ( is_array( $transformedChildren ) )
00158         {
00159             foreach ( $transformedChildren as $child )
00160             {
00161                 if ( $child[0] == eZTemplate::NODE_FUNCTION ) // check child type
00162                 {
00163                     $childFunctionName = $child[2];
00164                     if ( $childFunctionName == 'delimiter' )
00165                     {
00166                         // save delimiter for it to be processed below
00167                         $delimiter = $child;
00168                         continue;
00169                     }
00170                     elseif ( $childFunctionName == 'break' )
00171                     {
00172                         $childrenNodes[] = eZTemplateNodeTool::createCodePieceNode( "break;\n" );
00173                         continue;
00174                     }
00175                     elseif ( $childFunctionName == 'continue' )
00176                     {
00177                         $childrenNodes[] = eZTemplateNodeTool::createCodePieceNode( "continue;\n" );
00178                         continue;
00179                     }
00180                     elseif ( $childFunctionName == 'skip' )
00181                     {
00182                         $childrenNodes[] = eZTemplateNodeTool::createCodePieceNode( "\$skipDelimiter = true;\ncontinue;\n" );
00183                         continue;
00184                     }
00185                 }
00186 
00187                 $childrenNodes[] = $child;
00188             }
00189         }
00190 
00191         if ( $delimiter ) // if delimiter is specified
00192         {
00193             $delimiterNodes = eZTemplateNodeTool::extractNodes( $children,
00194                                                     array( 'match' => array( 'type' => 'equal',
00195                                                                              'matches' => array( array( 'match-keys' => array( 0 ),
00196                                                                                                        'match-with' => eZTemplate::NODE_FUNCTION ),
00197                                                                                                  array( 'match-keys' => array( 2 ),
00198                                                                                                         'match-with' => 'delimiter' ) ) ) ) );
00199             $delimiterNode = false;
00200             if ( count( $delimiterNodes ) > 0 )
00201                 $delimiterNode = $delimiterNodes[0];
00202 
00203             $delimiterChildren = eZTemplateNodeTool::extractFunctionNodeChildren( $delimiterNode );
00204             $delimiterParameters = eZTemplateNodeTool::extractFunctionNodeParameters( $delimiterNode );
00205 
00206             $checkModulo = array();
00207             $checkModuloEnd = array();
00208             $delemiterModuloValue = array();
00209             if ( isset( $delimiterParameters['modulo'] ) )
00210             {
00211                 switch ( $this->Name )
00212                 {
00213                     case 'foreach':
00214                     {
00215                         $delimiterModulo = $delimiterParameters['modulo'];
00216                         $delimiterModulo = eZTemplateCompiler::processElementTransformationList( $this->Tpl, $delimiterModulo, $delimiterModulo, $this->PrivateData );
00217                         // Get unique index
00218                         $currentIndex = "\$fe_i_$this->UniqID";
00219 
00220                         if ( eZTemplateNodeTool::isStaticElement( $delimiterModulo ) )
00221                         {
00222                             $moduloValue = (int)eZTemplateNodeTool::elementStaticValue( $delimiterModulo );
00223                             $matchCode = "( ( $currentIndex ) % $moduloValue ) == 0";
00224                         }
00225                         else
00226                         {
00227                             $delemiterModuloValue[] = eZTemplateNodeTool::createVariableNode( false, $delimiterModulo, eZTemplateNodeTool::extractFunctionNodePlacement( $this->Node ),
00228                                                                                         array( 'spacing' => 0 ), 'moduloValue' );
00229                             $matchCode = "( ( $currentIndex ) % \$moduloValue ) == 0";
00230                         }
00231                         $checkModulo[] = eZTemplateNodeTool::createCodePieceNode( "if ( $matchCode ) // Check modulo\n{" );
00232                         $checkModulo[] = eZTemplateNodeTool::createSpacingIncreaseNode( 4 );
00233 
00234                         $checkModuloEnd[] = eZTemplateNodeTool::createSpacingDecreaseNode( 4 );
00235                         $checkModuloEnd[] = eZTemplateNodeTool::createCodePieceNode( "}\n" );
00236                     }
00237                 }
00238             }
00239             $delimiterNodes = array();
00240             $delimiterNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( \$skipDelimiter )\n" .
00241                                                                          "    \$skipDelimiter = false;\n" .
00242                                                                          "else\n" .
00243                                                                          "{ // delimiter begins" );
00244             $delimiterNodes[] = eZTemplateNodeTool::createSpacingIncreaseNode();
00245             if ( is_array( $delimiter[1] ) ) // if delimiter has children
00246             {
00247                 // If modulo is specified
00248                 $delimiterNodes = array_merge( $delimiterNodes, $checkModulo );
00249 
00250                 foreach ( $delimiter[1] as $delimiterChild )
00251                     $delimiterNodes[] = $delimiterChild;
00252 
00253                 // Set end of checking for modulo
00254                 $delimiterNodes = array_merge( $delimiterNodes, $checkModuloEnd );
00255             }
00256 
00257             $delimiterNodes[] = eZTemplateNodeTool::createSpacingDecreaseNode();
00258             $delimiterNodes[] = eZTemplateNodeTool::createCodePieceNode( "} // delimiter ends\n" );
00259 
00260             // we place its code right before other loop children,
00261             // if delemiter and modulo are specified and value of modulo is not static
00262             // $delemiterModuloValue is initialization of variable
00263             // we should place initialization of moduloValue before checking for delimiter
00264             $childrenNodes = array_merge( $delemiterModuloValue, $delimiterNodes, $childrenNodes );
00265         }
00266 
00267         $this->NewNodes = array_merge( $this->NewNodes, $childrenNodes );
00268     }
00269 
00270     /*!
00271      * Generates loop body.
00272      */
00273     function processBody()
00274     {
00275         // export current sequence value to the specified template variable <$sequence_var>
00276         $this->setCurrentSequenceValue();
00277 
00278         // process the loop body
00279         $this->processChildren();
00280 
00281         $this->iterateSequence();
00282     }
00283 
00284     /*!
00285      * create PHP and template variables needed for the loop.
00286      */
00287     function initVars()
00288     {
00289         // initialize delimiter processing
00290         $this->NewNodes[] = eZTemplateNodeTool::createCodePieceNode( "\$skipDelimiter = true;" );
00291 
00292         // initialize sequence
00293         $this->createSequenceVars();
00294     }
00295 
00296     ///
00297     /// \privatesection
00298     ///
00299     public $Name;
00300     public $Parameters;
00301     public $NodePlacement;
00302     public $UniqID;
00303     public $NewNodes;
00304     public $Node;
00305     public $Tpl;
00306     public $PrivateData;
00307 
00308 }
00309 
00310 ?>