eZ Publish  [4.0]
eztemplateloop.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZTemplateLoop class
00004 //
00005 // Created on: <23-Feb-2005 17:46:42 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 // private class, should not be used outside of this file
00033 class eZTemplateLoopSequence
00034 {
00035     function eZTemplateLoopSequence( $array )
00036     {
00037         $this->ArrayRef = $array;
00038         $this->CurVal   =  current( $this->ArrayRef );
00039     }
00040 
00041     function val()
00042     {
00043         return $this->CurVal;
00044     }
00045 
00046     function next()
00047     {
00048         if( ( $this->CurVal = next( $this->ArrayRef ) ) === false )
00049         {
00050             reset( $this->ArrayRef );
00051             $this->CurVal = current( $this->ArrayRef );
00052         }
00053     }
00054 
00055     public $ArrayRef;
00056     public $CurVal;
00057 }
00058 
00059 /*!
00060   \class eZTemplateLoop eztemplateloop.php
00061   \ingroup eZTemplateFunctions
00062   \brief Code common for the loop functions in processed mode.
00063 */
00064 class eZTemplateLoop
00065 {
00066     function eZTemplateLoop( $functionName, &$functionParameters, $functionChildren, $functionPlacement,
00067                              $tpl, &$textElements, $rootNamespace, $currentNamespace )
00068     {
00069         $this->SkipDelimiter         = true;
00070         $this->SkipSequenceIncrement = false;
00071         $this->Delimiter             = null;
00072         $this->Initialized           = true;
00073         $this->SequenceVarName       = null;
00074         $this->Sequence              = null;
00075         $this->LoopVariablesNames    = array();
00076 
00077 
00078         $this->FunctionName       = $functionName;
00079         $this->FunctionParameters =& $functionParameters;
00080         $this->FunctionChildren   = $functionChildren;
00081 
00082         $this->Tpl                = $tpl;
00083         $this->TextElements       =& $textElements;
00084         $this->RootNamespace      = $rootNamespace;
00085         $this->CurrentNamespace   = $currentNamespace;
00086         $this->FunctionPlacement  = $functionPlacement;
00087 
00088         $this->Initialized = $this->processFunctionParameters();
00089     }
00090 
00091     /*!
00092     \return true on success, false otherwise.
00093     */
00094     function processFunctionParameters()
00095     {
00096         $params =& $this->FunctionParameters;
00097 
00098         if ( !isset( $params['sequence_array'] ) || !count( $params['sequence_array'] ) )
00099             return true;
00100 
00101         $this->parseParamVarName( 'sequence_var', $seqVarName );
00102 
00103         if ( !$seqVarName )
00104         {
00105             $this->Tpl->error( $this->FunctionName, "Empty sequence variable name." );
00106             return false;
00107         }
00108 
00109         $this->initLoopVariable( $seqVarName );
00110 
00111         $seqArray = $this->Tpl->elementValue( $params['sequence_array'],
00112                                               $this->RootNamespace, $this->CurrentNamespace, $this->FunctionPlacement );
00113 
00114         $this->Sequence        = new eZTemplateLoopSequence( $seqArray );
00115         $this->SequenceVarName = $seqVarName;
00116 
00117         return true;
00118     }
00119 
00120     /*!
00121      * \return true if the object has been correctly initialized, false otherwise
00122      */
00123     function initialized()
00124     {
00125         return $this->Initialized;
00126     }
00127 
00128     /*! Export current loop sequence value to the template variable
00129      *  specified in loop parameters.
00130      */
00131     function setSequenceVar()
00132     {
00133         if ( !$this->hasSequence() )
00134             return;
00135 
00136         $this->Tpl->setVariable( $this->SequenceVarName,  $this->Sequence->val(), $this->RootNamespace );
00137     }
00138 
00139     /*!
00140      * Should be called each time a new iteration is started.
00141      *  Resets some internal variables.
00142      */
00143     function resetIteration()
00144     {
00145         $this->SkipDelimiter         = false;
00146         $this->SkipSequenceIncrement = false;
00147     }
00148 
00149     /*!
00150      * Increment current sequence value.
00151      */
00152     function incrementSequence()
00153     {
00154         if ( $this->hasSequence() && !$this->SkipSequenceIncrement )
00155             $this->Sequence->next();
00156     }
00157 
00158     /*!
00159      * Returns true if sequence has been specified for the loop in its parameters.
00160      */
00161     function hasSequence()
00162     {
00163         return !is_null( $this->Sequence );
00164     }
00165 
00166 
00167     /*!
00168      * Destroys template variables defined by the loop.
00169      */
00170     function cleanup()
00171     {
00172         // destroy loop variable(s)
00173         foreach ( $this->LoopVariablesNames as $varName )
00174             $this->Tpl->unsetVariable( $varName, $this->RootNamespace );
00175     }
00176 
00177     /*
00178      * Processes loop children, i.e. all tags and text that is
00179      * between start and end tags of the loop.
00180      * Besides, does special handling of {break}, {skip}, {continue} and {delimiter} tags.
00181      *
00182      * \return true if the caller loop should break, false otherwise
00183      */
00184     function processChildren()
00185     {
00186         if ( !is_array( $this->FunctionChildren ) )
00187         {
00188             return false;
00189         }
00190         foreach ( array_keys( $this->FunctionChildren ) as $childKey )
00191         {
00192             $child = $this->FunctionChildren[$childKey];
00193 
00194             if ( $child[0] == eZTemplate::NODE_FUNCTION ) // check child type
00195             {
00196                 $childFunctionName = $child[2];
00197 
00198                 if ( $childFunctionName == 'break' )
00199                     return true;
00200                 elseif ( $childFunctionName == 'continue' )
00201                 {
00202                     $this->SkipSequenceIncrement = true;
00203                     break;
00204                 }
00205                 elseif ( $childFunctionName == 'skip' )
00206                 {
00207                     $this->SkipSequenceIncrement = true;
00208                     $this->SkipDelimiter = true;
00209                     break;
00210                 }
00211                 elseif ( $childFunctionName == 'delimiter' )
00212                 {
00213                     if ( is_null( $this->Delimiter ) )
00214                         $this->Delimiter = $child;
00215                     continue;
00216                 }
00217             }
00218 
00219             $rslt = $this->Tpl->processNode( $child, $this->TextElements, $this->RootNamespace, $this->CurrentNamespace );
00220 
00221             // break/continue/skip might be found in a child function's (usually {if}) children
00222             if ( is_array( $rslt ) )
00223             {
00224                 if ( array_key_exists( 'breakFunctionFound', $rslt ) )
00225                     return true;
00226                 elseif ( array_key_exists( 'continueFunctionFound', $rslt ) )
00227                 {
00228                     $this->SkipSequenceIncrement = true;
00229                     break;
00230                 }
00231                 elseif ( array_key_exists( 'skipFunctionFound', $rslt ) )
00232                 {
00233                     $this->SkipSequenceIncrement = true;
00234                     $this->SkipDelimiter = true;
00235                     break;
00236                 }
00237             }
00238 
00239         } // foreach
00240 
00241         return false;
00242     }
00243 
00244     /*!
00245      * If \c $loopCondition is true, shows delimiter (if one has been specified).
00246      * \param $index is needed for processing delimiter parameters such as modulo.
00247      *        Is current iteration index.
00248      * \return true if the caller loop should break, false otherwise
00249      */
00250     function processDelimiter( $index = false )
00251     {
00252         if ( is_null( $this->Delimiter ) || $this->SkipDelimiter )
00253             return false;
00254 
00255         $delimiterChildren = $this->Delimiter[1];
00256         $delimiterParameters = $this->Delimiter[3]; // Get parameters
00257         $delimiterMatch = true;
00258         // Check for "modulo"
00259         if ( isset( $delimiterParameters["modulo"] ) and $index !== false )
00260         {
00261             $delimiterModulo = $delimiterParameters["modulo"];
00262             $modulo = $this->Tpl->elementValue( $delimiterModulo, $this->RootNamespace, $this->FunctionName, $this->FunctionPlacement );
00263             $modulo = trim( $modulo );
00264             if ( is_numeric( $modulo ) )
00265                 $delimiterMatch = ( $index % $modulo ) == 0;
00266         }
00267         if ( $delimiterMatch )
00268         {
00269             foreach ( $delimiterChildren as $delimiterChild )
00270             {
00271                 $this->Tpl->processNode( $delimiterChild, $this->TextElements, $this->RootNamespace, $this->CurrentNamespace );
00272             }
00273         }
00274 
00275         return false;
00276     }
00277 
00278     /*!
00279      * Parses the given function parameter that is supposed to contain a variable name.
00280      * Extracted variable name is stored to $dst.
00281      *
00282      * @param $paramName Parameter name.
00283      * @param $dst       Where to store parameter value.
00284      * @return           false if specified parameter is not found or it is wrong, otherwise true is returned.
00285      */
00286     function parseParamVarName( $paramName, &$dst )
00287     {
00288         $dst = null;
00289 
00290         if ( !isset( $this->FunctionParameters[$paramName] ) ||
00291              !count( $this->FunctionParameters[$paramName] ) )
00292             return false;
00293 
00294         list( $varNsName, $varNsType, $varName ) = $this->FunctionParameters[$paramName][0][1];
00295 
00296         if ( $varNsType != eZTemplate::NAMESPACE_SCOPE_LOCAL || $varNsName )
00297         {
00298             $this->Tpl->error( $this->FunctionName,
00299                                'Loop variables can be defined in root namespace only (e.g. $foo, but not $#foo or $:foo.)' );
00300             return false;
00301         }
00302 
00303         $dst = $varName;
00304         return true;
00305     }
00306 
00307     /*!
00308      * Parses given function parameter and makes sure that it is not a proxy object ({section} loop iterator).
00309      *
00310      * @param  $paramName      Parameter name.
00311      * @param  $dst            Where to store parameter value.
00312      * @param  $isProxyObject  boolean true is stored here if value of the parameter is a proxy object.
00313      * @return                 false if specified parameter is not found or it is wrong, otherwise true is returned.
00314      */
00315     function parseScalarParamValue( $paramName, &$dst, &$isProxyObject )
00316     {
00317         $dst = null;
00318 
00319         if ( !isset( $this->FunctionParameters[$paramName] ) || !count( $this->FunctionParameters[$paramName] ) )
00320             return false;
00321 
00322         // get parameter value
00323         $dst = $this->Tpl->elementValue( $this->FunctionParameters[$paramName], $this->RootNamespace,
00324                                          $this->CurrentNamespace, $this->FunctionPlacement, false, true );
00325 
00326         // check if a proxy object ({section} loop iterator) was involved in the parameter value
00327         if ( isset( $this->FunctionParameters[$paramName]['proxy-object-found'] ) )
00328         {
00329             $isProxyObject = true;
00330             unset( $this->FunctionParameters[$paramName]['proxy-object-found'] ); // just not to leave garbage
00331         }
00332         else
00333             $isProxyObject = false;
00334 
00335         return true;
00336     }
00337 
00338     /*!
00339      * Parses value the given function parameter and stores it to $dst.
00340      *
00341      * @param  $paramName      Parameter name.
00342      * @param  $dst            Where to store parameter value.
00343      * @return                 false if specified parameter is not found or it is wrong, otherwise true is returned.
00344      */
00345     function parseParamValue( $paramName, &$dst )
00346     {
00347         $dst = null;
00348 
00349         if ( !isset( $this->FunctionParameters[$paramName] ) || !count( $this->FunctionParameters[$paramName] ) )
00350             return false;
00351 
00352         $dst = $this->Tpl->elementValue( $this->FunctionParameters[$paramName], $this->RootNamespace,
00353                                          $this->CurrentNamespace, $this->FunctionPlacement );
00354         return true;
00355     }
00356 
00357     /*!
00358      * Checks if the given loop variable already exists. If it doesn't, store its name for later cleanup.
00359      * Otherwise shows a warning message.
00360      *
00361      * @see eZTemplateLoop::$loopVariablesNames
00362      */
00363     function initLoopVariable( $varName )
00364     {
00365         if ( $this->Tpl->hasVariable( $varName, $this->RootNamespace ) )
00366             $this->Tpl->warning( $this->FunctionName, "Variable '$varName' already exists." );
00367         else
00368             $this->LoopVariablesNames[] = $varName;
00369     }
00370 
00371     ///
00372     /// \privatesection
00373     ///
00374 
00375     public $FunctionName;
00376     public $FunctionParameters;
00377     public $FunctionChildren;
00378     public $FunctionPlacement;
00379 
00380     public $SkipDelimiter;
00381     public $SkipSequenceIncrement;
00382     public $delimiter;
00383 
00384     public $Tpl;
00385     public $TextElements;
00386     public $RootNamespace;
00387     public $CurrentNamespace;
00388 
00389     public $Initialized;
00390     public $Sequence;
00391     public $SequenceVarName;
00392     /*!
00393      * Before we create a new loop variable, we check if it already exists.
00394      * If it doesn't, we store its name in this array, so that we know
00395      * which variables to destroy after the loop execution finishes.
00396      */
00397     public $LoopVariablesNames;
00398 }
00399 
00400 ?>