eZ Publish  [4.0]
eztemplateblockfunction.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZTemplateBlockFunction class
00004 //
00005 // Created on: <01-Mar-2002 13:50:33 amos>
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 eZTemplateBlockFunction eztemplateblockfunction.php
00033   \ingroup eZTemplateFunctions
00034   \brief Advanced block handling
00035 
00036   set-block
00037   Renders all it's children as text and sets it as a template variable.
00038   This is useful for allowing one template to return multiple text portions,
00039   for instance an email template could set subject as a block and return
00040   the rest as body.
00041 
00042 \code
00043 {set-block name=Space scope=global variable=text}
00044 {$item} - {$item2}
00045 {/set-block}
00046 \endcode
00047 
00048   append-block
00049   Similar to set-block but will make the variable an array where each append-block
00050   adds an item.
00051 
00052 \code
00053 {append-block scope=global variable=extra_header_data}
00054 <script language=jscript src={"/extension/xmleditor/dhtml/ezeditor.js"|ezroot}></script>
00055 <link rel="stylesheet" type="text/css" href={"/extension/xmleditor/dhtml/toolbar.css"|ezroot}>
00056 {/append-block}
00057 \endcode
00058 
00059   run-once
00060   Makes sure that the block is run only once.
00061 
00062 \code
00063 {run-once}
00064 <p>This appears only one time</p>
00065 {/run-once}
00066 \endcode
00067 */
00068 
00069 class eZTemplateBlockFunction
00070 {
00071     const SCOPE_RELATIVE = 1;
00072     const SCOPE_ROOT = 2;
00073     const SCOPE_GLOBAL = 3;
00074 
00075     /*!
00076      Initializes the object with names.
00077     */
00078     function eZTemplateBlockFunction( $blockName = 'set-block',
00079                                       $appendBlockName = 'append-block',
00080                                       $onceName = 'run-once' )
00081     {
00082         $this->BlockName = $blockName;
00083         $this->AppendBlockName = $appendBlockName;
00084         $this->OnceName = $onceName;
00085     }
00086 
00087     /*!
00088      Returns an array containing the name of the block function, default is "block".
00089      The name is specified in the constructor.
00090     */
00091     function functionList()
00092     {
00093         return array( $this->BlockName, $this->AppendBlockName, $this->OnceName );
00094     }
00095 
00096     function functionTemplateHints()
00097     {
00098         return array( $this->BlockName => array( 'parameters' => true,
00099                                                  'static' => false,
00100                                                  'transform-children' => true,
00101                                                  'tree-transformation' => true,
00102                                                  'transform-parameters' => true ),
00103                       $this->AppendBlockName => array( 'parameters' => true,
00104                                                        'static' => false,
00105                                                        'transform-children' => true,
00106                                                        'tree-transformation' => true,
00107                                                        'transform-parameters' => true ),
00108                       $this->OnceName => array( 'parameters' => false,
00109                                                 'static' => false,
00110                                                 'transform-children' => true,
00111                                                 'tree-transformation' => true ) );
00112     }
00113 
00114     function templateNodeTransformation( $functionName, &$node,
00115                                          $tpl, $parameters, $privateData )
00116     {
00117         if ( $functionName == $this->BlockName or
00118              $functionName == $this->AppendBlockName )
00119         {
00120             if ( !isset( $parameters['variable'] ) )
00121                 return false;
00122 
00123             $scope = eZTemplate::NAMESPACE_SCOPE_RELATIVE;
00124             if ( isset( $parameters['scope'] ) )
00125             {
00126                 if ( !eZTemplateNodeTool::isStaticElement( $parameters['scope'] ) )
00127                     return false;
00128                 $scopeText = eZTemplateNodeTool::elementStaticValue( $parameters['scope'] );
00129                 if ( $scopeText == 'relative' )
00130                     $scope = eZTemplate::NAMESPACE_SCOPE_RELATIVE;
00131                 else if ( $scopeText == 'root' )
00132                     $scope = eZTemplate::NAMESPACE_SCOPE_LOCAL;
00133                 else if ( $scopeText == 'global' )
00134                     $scope = eZTemplate::NAMESPACE_SCOPE_GLOBAL;
00135             }
00136 
00137             $name = '';
00138             if ( isset( $parameters['name'] ) )
00139             {
00140                 if ( !eZTemplateNodeTool::isStaticElement( $parameters['name'] ) )
00141                     return false;
00142                 $name = eZTemplateNodeTool::elementStaticValue( $parameters['name'] );
00143             }
00144             $variableName = eZTemplateNodeTool::elementStaticValue( $parameters['variable'] );
00145 
00146             $newNodes = array();
00147 
00148             $children = eZTemplateNodeTool::extractFunctionNodeChildren( $node );
00149 
00150             $newNodes[] = eZTemplateNodeTool::createOutputVariableIncreaseNode();
00151             $newNodes = array_merge( $newNodes, $children );
00152             $newNodes[] = eZTemplateNodeTool::createAssignFromOutputVariableNode( 'blockText' );
00153             if ( $functionName == $this->AppendBlockName )
00154             {
00155                 $data = array( eZTemplateNodeTool::createVariableElement( $variableName, $name, $scope ) );
00156                 $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $data, false, array(),
00157                                                                       'blockData' );
00158 
00159                 // This block checks whether the append-block variable is an array or not.
00160                 // TODO: This is a temporary solution and should also check whether the template variable exists.
00161                 // This new solution requires probably writing the createVariableElement and createVariableNode your self.
00162                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( is_null ( \$blockData ) ) \$blockData = array();" );
00163                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( is_array ( \$blockData ) ) \$blockData[] = \$blockText;" );
00164                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "else eZDebug::writeError( \"Variable '$variableName' is already in use.\" );" );
00165                 $newNodes[] = eZTemplateNodeTool::createVariableNode( false, 'blockData', false, array(),
00166                                                                       array( $name, $scope, $variableName ), false, true, true );
00167                 $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( 'blockData' );
00168             }
00169             else
00170             {
00171                 $newNodes[] = eZTemplateNodeTool::createVariableNode( false, 'blockText', false, array(),
00172                                                                       array( $name, $scope, $variableName ), false, true, true );
00173             }
00174             $newNodes[] = eZTemplateNodeTool::createVariableUnsetNode( 'blockText' );
00175             $newNodes[] = eZTemplateNodeTool::createOutputVariableDecreaseNode();
00176 
00177             return $newNodes;
00178         }
00179         else if ( $functionName == $this->OnceName )
00180         {
00181             $functionPlacement = eZTemplateNodeTool::extractFunctionNodePlacement( $node );
00182             $key = $this->placementKey( $functionPlacement );
00183             $newNodes = array();
00184             if ( $key !== false )
00185             {
00186                 $keyText = eZPHPCreator::variableText( $key, 0, 0, false );
00187                 $placementText = eZPHPCreator::variableText( $functionPlacement, 0, 0, false );
00188                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if ( !isset( \$GLOBALS['eZTemplateRunOnceKeys'][$keyText] ) )\n" .
00189                                                                        "{\n" .
00190                                                                        "    \$GLOBALS['eZTemplateRunOnceKeys'][$keyText] = $placementText;" );
00191                 $children = eZTemplateNodeTool::extractFunctionNodeChildren( $node );
00192                 $newNodes[] = eZTemplateNodeTool::createSpacingIncreaseNode( 4 );
00193                 $newNodes = array_merge( $newNodes, $children );
00194                 $newNodes[] = eZTemplateNodeTool::createSpacingDecreaseNode( 4 );
00195                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "}" );
00196             }
00197             return $newNodes;
00198         }
00199         return false;
00200     }
00201 
00202     /*!
00203      Processes the function with all it's children.
00204     */
00205     function process( $tpl, &$textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace )
00206     {
00207         switch ( $functionName )
00208         {
00209             case $this->BlockName:
00210             case $this->AppendBlockName:
00211             {
00212                 $children = $functionChildren;
00213                 $parameters = $functionParameters;
00214 
00215                 $scope = eZTemplateBlockFunction::SCOPE_RELATIVE;
00216                 if ( isset( $parameters["scope"] ) )
00217                 {
00218                     $scopeText = $tpl->elementValue( $parameters["scope"], $rootNamespace, $currentNamespace, $functionPlacement );
00219                     if ( $scopeText == 'relative' )
00220                         $scope = eZTemplateBlockFunction::SCOPE_RELATIVE;
00221                     else if ( $scopeText == 'root' )
00222                         $scope = eZTemplateBlockFunction::SCOPE_ROOT;
00223                     else if ( $scopeText == 'global' )
00224                         $scope = eZTemplateBlockFunction::SCOPE_GLOBAL;
00225                     else
00226                         $tpl->warning( $functionName, "Scope value '$scopeText' is not valid, use either 'relative', 'root' or 'global'", $functionPlacement );
00227                 }
00228 
00229                 $name = null;
00230                 if ( isset( $parameters["name"] ) )
00231                     $name = $tpl->elementValue( $parameters["name"], $rootNamespace, $currentNamespace, $functionPlacement );
00232                 if ( $name === null )
00233                 {
00234                     if ( $scope == eZTemplateBlockFunction::SCOPE_RELATIVE )
00235                         $name = $currentNamespace;
00236                     else if ( $scope == eZTemplateBlockFunction::SCOPE_ROOT )
00237                         $name = $rootNamespace;
00238                     else
00239                         $name = '';
00240                 }
00241                 else
00242                 {
00243                     if ( $scope == eZTemplateBlockFunction::SCOPE_RELATIVE and
00244                          $currentNamespace != '' )
00245                         $name = "$currentNamespace:$name";
00246                     else if ( $scope == eZTemplateBlockFunction::SCOPE_ROOT and
00247                               $rootNamespace != '' )
00248                         $name = "$rootNamespace:$name";
00249                 }
00250                 $variableItem = null;
00251                 if ( isset( $parameters["variable"] ) )
00252                 {
00253                     $hasLoopItemParameter = true;
00254                     $variableItem = $tpl->elementValue( $parameters["variable"], $rootNamespace, $currentNamespace, $functionPlacement );
00255                 }
00256                 else
00257                 {
00258                     $tpl->missingParameter( $functionName, 'variable' );
00259                     return;
00260                 }
00261 
00262                 $childTextElements = array();
00263                 if ( is_array( $children ) )
00264                 {
00265                     foreach ( array_keys( $children ) as $childKey )
00266                     {
00267                         $child =& $children[$childKey];
00268                         $tpl->processNode( $child, $childTextElements, $rootNamespace, $name );
00269                     }
00270                 }
00271                 $text = implode( '', $childTextElements );
00272                 if ( $functionName == $this->AppendBlockName )
00273                 {
00274                     $textArray = array();
00275                     if ( $tpl->hasVariable( $variableItem, $name ) )
00276                     {
00277                         $textArray = $tpl->variable( $variableItem, $name );
00278                         if ( !is_array( $textArray ) )
00279                         {
00280                            $tpl->warning( $functionName, "Variable '$variableItem' is already in use.", $functionPlacement );
00281                            return;
00282                         }
00283                     }
00284                     $textArray[] = $text;
00285                     $tpl->setVariable( $variableItem, $textArray, $name );
00286                 }
00287                 else
00288                     $tpl->setVariable( $variableItem, $text, $name );
00289             } break;
00290 
00291             case $this->OnceName:
00292             {
00293                 $key = $this->placementKey( $functionPlacement );
00294                 if ( $key !== false and !$this->hasPlacementKey( $key ) )
00295                 {
00296                     $this->registerPlacementKey( $key, $functionPlacement );
00297 
00298                     if ( is_array( $functionChildren ) )
00299                     {
00300                         foreach ( array_keys( $functionChildren ) as $childKey )
00301                         {
00302                             $child =& $functionChildren[$childKey];
00303                             $tpl->processNode( $child, $textElements, $rootNamespace, $currentNamespace );
00304                         }
00305                     }
00306                 }
00307             } break;
00308         }
00309     }
00310 
00311     function resetFunction( $functionName )
00312     {
00313         if ( $functionName == $this->OnceName )
00314         {
00315             unset( $GLOBALS['eZTemplateRunOnceKeys'] );
00316         }
00317     }
00318 
00319     /*!
00320      Generates an md5 key from the start, stop and file of the template function and returns it.
00321      \return false if the key could not be made.
00322     */
00323     function placementKey( $placement )
00324     {
00325         if ( isset( $placement[0] ) and
00326              isset( $placement[1] ) and
00327              isset( $placement[2] ) )
00328         {
00329             $input = $placement[0][0] . ',' . $placement[0][1] . "\n";
00330             $input .= $placement[1][0] . ',' . $placement[1][1] . "\n";
00331             $input .= $placement[2];
00332             return md5( $input );
00333         }
00334         return false;
00335     }
00336 
00337     /*!
00338      \return true if the placement key is registered which means that the block has already been run.
00339     */
00340     function hasPlacementKey( $key )
00341     {
00342         return isset( $GLOBALS['eZTemplateRunOnceKeys'][$key] );
00343     }
00344 
00345     /*!
00346      Registers the placement key \a $key with the data \a $placement.
00347     */
00348     function registerPlacementKey( $key, $placement )
00349     {
00350         return $GLOBALS['eZTemplateRunOnceKeys'][$key] = $placement;
00351     }
00352 
00353     /*!
00354      Returns true.
00355     */
00356     function hasChildren()
00357     {
00358         return true;
00359     }
00360 
00361     /// \privatesection
00362     /// Name of the function
00363     public $BlockName;
00364     public $AppendBlockName;
00365     public $OnceName;
00366 }
00367 
00368 ?>