eZ Publish  [4.0]
eztemplatecachefunction.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZTemplateCacheFunction class
00004 //
00005 // Created on: <28-Feb-2003 15:06:33 bf>
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 eZTemplateCacheFunction eztemplatecachefunction.php
00033   \ingroup eZTemplateFunctions
00034   \brief Advanced cache handling
00035 
00036 */
00037 
00038 //include_once( 'lib/eztemplate/classes/eztemplatecacheblock.php' );
00039 
00040 class eZTemplateCacheFunction
00041 {
00042     const DEFAULT_TTL = 7200; // 2 hours = 60*60*2
00043 
00044     /*!
00045      Initializes the object with names.
00046     */
00047     function eZTemplateCacheFunction( $blockName = 'cache-block' )
00048     {
00049         $this->BlockName = $blockName;
00050     }
00051 
00052     /*!
00053      Returns an array containing the name of the block function, default is "block".
00054      The name is specified in the constructor.
00055     */
00056     function functionList()
00057     {
00058         return array( $this->BlockName );
00059     }
00060 
00061     function functionTemplateHints()
00062     {
00063         return array( $this->BlockName => array( 'parameters' => true,
00064                                                  'static' => false,
00065                                                  'transform-children' => true,
00066                                                  'tree-transformation' => true,
00067                                                  'transform-parameters' => true ) );
00068     }
00069 
00070     function templateNodeTransformation( $functionName, &$node,
00071                                          $tpl, $parameters, $privateData )
00072     {
00073         $ini = eZINI::instance();
00074         $children = eZTemplateNodeTool::extractFunctionNodeChildren( $node );
00075         if ( $ini->variable( 'TemplateSettings', 'TemplateCache' ) != 'enabled' )
00076         {
00077             return $children;
00078         }
00079 
00080         $functionPlacement = eZTemplateNodeTool::extractFunctionNodePlacement( $node );
00081         $placementKeyString = eZTemplateCacheBlock::placementString( $functionPlacement );
00082 
00083         $newNodes = array();
00084         $ignoreContentExpiry = false;
00085 
00086         if ( isset( $parameters['expiry'] ) )
00087         {
00088             if ( eZTemplateNodeTool::isStaticElement( $parameters['expiry'] ) )
00089             {
00090                 $expiryValue = eZTemplateNodeTool::elementStaticValue( $parameters['expiry'] );
00091                 $ttlCode = $expiryValue > 0 ? eZPHPCreator::variableText( $expiryValue , 0, 0, false ) : 'null';
00092             }
00093             else
00094             {
00095                 $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $parameters['expiry'], false, array(), 'localExpiry' );
00096                 $ttlCode = "( \$localExpiry > 0 ? \$localExpiry : null )";
00097             }
00098         }
00099         else
00100         {
00101             $ttlCode = eZPHPCreator::variableText( self::DEFAULT_TTL, 0, 0, false );
00102         }
00103 
00104         if ( isset( $parameters['ignore_content_expiry'] ) )
00105         {
00106             $ignoreContentExpiry = eZTemplateNodeTool::elementStaticValue( $parameters['ignore_content_expiry'] );
00107         }
00108 
00109         $keysData = false;
00110         $hasKeys = false;
00111         $subtreeExpiryData = null;
00112         $subtreeValue = null;
00113         if ( isset( $parameters['keys'] ) )
00114         {
00115             $keysData = $parameters['keys'];
00116             $hasKeys = true;
00117         }
00118         if ( isset( $parameters['subtree_expiry'] ) )
00119         {
00120             $subtreeExpiryData = $parameters['subtree_expiry'];
00121             if ( !eZTemplateNodeTool::isStaticElement( $subtreeExpiryData ) )
00122                 $hasKeys = true;
00123             else
00124                 $subtreeValue = eZTemplateNodeTool::elementStaticValue( $subtreeExpiryData );
00125 
00126             $ignoreContentExpiry = true;
00127         }
00128         $accessName = false;
00129         if ( isset( $GLOBALS['eZCurrentAccess']['name'] ) )
00130             $accessName = $GLOBALS['eZCurrentAccess']['name'];
00131         if ( $hasKeys )
00132         {
00133             $placementKeyStringText = eZPHPCreator::variableText( $placementKeyString, 0, 0, false );
00134             $accessNameText = eZPHPCreator::variableText( $accessName, 0, 0, false );
00135             $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $keysData, false, array(), 'cacheKeys' );
00136             $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $subtreeExpiryData, false, array(), 'subtreeExpiry' );
00137 
00138             $code = ( "//include_once( 'lib/eztemplate/classes/eztemplatecacheblock.php' );\n" .
00139                       "\$cacheKeys = array( \$cacheKeys, $placementKeyStringText, $accessNameText );\n" );
00140             $cachePathText = "\$cachePath";
00141         }
00142         else
00143         {
00144             $nodeID = $subtreeValue ? eZTemplateCacheBlock::decodeNodeID( $subtreeValue ) : false;
00145             $cachePath = eZTemplateCacheBlock::cachePath( eZTemplateCacheBlock::keyString( array( $placementKeyString, $accessName ) ), $nodeID );
00146             $code = ( "//include_once( 'lib/eztemplate/classes/eztemplatecacheblock.php' );\n" );
00147             $cachePathText = eZPHPCreator::variableText( $cachePath, 0, 0, false );
00148         }
00149 
00150         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( $code );
00151 
00152         $code = '';
00153 
00154         $codePlacementHash = md5( $placementKeyString );
00155         if ( $hasKeys )
00156         {
00157             $code .= "list(\$cacheHandler_{$codePlacementHash}, \$contentData) =\n  eZTemplateCacheBlock::retrieve( \$cacheKeys, \$subtreeExpiry, $ttlCode, " . ($ignoreContentExpiry ? "false" : "true") . " );\n";
00158         }
00159         else
00160         {
00161             $nodeIDText = var_export( $nodeID, true );
00162             $code .= "list(\$cacheHandler_{$codePlacementHash}, \$contentData) =\n  eZTemplateCacheBlock::handle( $cachePathText, $nodeIDText, $ttlCode, " . ($ignoreContentExpiry ? "false" : "true") . " );\n";
00163         }
00164         $code .=
00165             "if ( !( \$contentData instanceof eZClusterFileFailure ) )\n" .
00166             "{\n";
00167 
00168         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( $code, array( 'spacing' => 0 ) );
00169         $newNodes[] = eZTemplateNodeTool::createWriteToOutputVariableNode( 'contentData', array( 'spacing' => 4 ) );
00170         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "    unset( \$contentData );\n" .
00171                                                                "}\n" .
00172                                                                "else\n" .
00173                                                                "{\n" .
00174                                                                "    unset( \$contentData );" );
00175 
00176         $newNodes[] = eZTemplateNodeTool::createOutputVariableIncreaseNode( array( 'spacing' => 4 ) );
00177         $newNodes[] = eZTemplateNodeTool::createSpacingIncreaseNode( 4 );
00178         $newNodes = array_merge( $newNodes, $children );
00179         $newNodes[] = eZTemplateNodeTool::createSpacingDecreaseNode( 4 );
00180         $newNodes[] = eZTemplateNodeTool::createAssignFromOutputVariableNode( 'cachedText', array( 'spacing' => 4 ) );
00181 
00182         $code =
00183             "\$cacheHandler_{$codePlacementHash}->storeCache( array( 'scope' => 'template-block', 'binarydata' => \$cachedText ) );\n";
00184 
00185         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( $code, array( 'spacing' => 4 ) );
00186         $newNodes[] = eZTemplateNodeTool::createOutputVariableDecreaseNode( array( 'spacing' => 4 ) );
00187         $newNodes[] = eZTemplateNodeTool::createWriteToOutputVariableNode( 'cachedText', array( 'spacing' => 4 ) );
00188         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "    unset( \$cachedText, \$cacheHandler_{$codePlacementHash} );\n}\n" );
00189 
00190         return $newNodes;
00191     }
00192 
00193     /*!
00194      Processes the function with all it's children.
00195     */
00196     function process( $tpl, &$textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace )
00197     {
00198         switch ( $functionName )
00199         {
00200             case $this->BlockName:
00201             {
00202                 // Check for disabled cache.
00203                 $ini = eZINI::instance();
00204                 if ( $ini->variable( 'TemplateSettings', 'TemplateCache' ) != 'enabled' )
00205                 {
00206                     $text = eZTemplateCacheFunction::processUncached( $tpl, $functionChildren,
00207                                                                       $rootNamespace, $currentNamespace );
00208                     $textElements[] = $text;
00209                     return;
00210                 }
00211                 else
00212                 {
00213                     $text = eZTemplateCacheFunction::processCachedPreprocess( $tpl,  $functionChildren,
00214                                                                               $functionParameters, $functionPlacement,
00215                                                                               $rootNamespace, $currentNamespace );
00216                     $textElements[] = $text;
00217                 }
00218             } break;
00219         }
00220     }
00221 
00222     function processCachedPreprocess( $tpl, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace )
00223     {
00224         $keys                = null;
00225         $subtreeExpiry       = null;
00226         $expiry              = self::DEFAULT_TTL;
00227         $ignoreContentExpiry = null;
00228         $subtreeExpiry       = null;
00229 
00230         if ( isset( $functionParameters["keys"] ) )
00231         {
00232             $keys = $tpl->elementValue( $functionParameters["keys"], $rootNamespace, $currentNamespace, $functionPlacement );
00233         }
00234         if ( isset( $functionParameters['subtree_expiry'] ) )
00235         {
00236             $subtreeExpiry = $tpl->elementValue( $functionParameters["subtree_expiry"], $rootNamespace, $currentNamespace, $functionPlacement );
00237         }
00238         if ( isset( $functionParameters["expiry"] ) )
00239         {
00240             $expiry = $tpl->elementValue( $functionParameters["expiry"], $rootNamespace, $currentNamespace, $functionPlacement );
00241         }
00242         if ( isset( $functionParameters["ignore_content_expiry"] ) )
00243         {
00244             $ignoreContentExpiry = $tpl->elementValue( $functionParameters["ignore_content_expiry"], $rootNamespace, $currentNamespace, $functionPlacement ) === true;
00245         }
00246         if ( isset( $functionParameters['subtree_expiry'] ) )
00247         {
00248             $ignoreContentExpiry = true;
00249         }
00250 
00251         $placementString = eZTemplateCacheBlock::placementString( $functionPlacement );
00252 
00253         return eZTemplateCacheFunction::processCached( $tpl, $functionChildren, $rootNamespace, $currentNamespace,
00254                                                        $placementString, $keys, $subtreeExpiry, $expiry, $ignoreContentExpiry );
00255     }
00256 
00257     function processCached( $tpl, $functionChildren, $rootNamespace, $currentNamespace,
00258                             $placementString, $keys, $subtreeExpiry, $expiry, $ignoreContentExpiry )
00259     {
00260         // Fetch the current siteaccess
00261         $accessName = false;
00262         if ( isset( $GLOBALS['eZCurrentAccess']['name'] ) )
00263             $accessName = $GLOBALS['eZCurrentAccess']['name'];
00264         if ( $keys === null )
00265         {
00266             $keyArray = array( $placementString, $accessName );
00267         }
00268         else
00269         {
00270             $keyArray = array( $keys, $placementString, $accessName );
00271         }
00272 
00273         $nodeID = $subtreeExpiry ? eZTemplateCacheBlock::decodeNodeID( $subtreeExpiry ) : false;
00274         $phpPath = eZTemplateCacheBlock::cachePath( eZTemplateCacheBlock::keyString( $keyArray ), $nodeID );
00275 
00276         $ttl = $expiry > 0 ? $expiry : null;
00277 
00278         if ( $subtreeExpiry !== null )
00279         {
00280             $ignoreContentExpiry = true;
00281         }
00282         else if ( $ignoreContentExpiry === null )
00283         {
00284             $ignoreContentExpiry = false;
00285         }
00286 
00287         $globalExpiryTime = -1;
00288         eZExpiryHandler::registerShutdownFunction();
00289         if ( $ignoreContentExpiry == false )
00290         {
00291             $globalExpiryTime = eZExpiryHandler::getTimestamp( 'template-block-cache', -1 );
00292         }
00293         $globalExpiryTime = max( eZExpiryHandler::getTimestamp( 'global-template-block-cache', -1 ), // This expiry value is the true global expiry for cache-blocks
00294                                  $globalExpiryTime );
00295 
00296         // Check if we can restore
00297         require_once( 'kernel/classes/ezclusterfilehandler.php' );
00298         $cacheFile = eZClusterFileHandler::instance( $phpPath );
00299         $args = array( "tpl" => $tpl,
00300                        "functionChildren" => $functionChildren,
00301                        "rootNamespace" => $rootNamespace,
00302                        "currentNamespace" => $currentNamespace );
00303         return $cacheFile->processCache( array( 'eZTemplateCacheBlock', 'retrieveContent' ),
00304                                          array( $this, 'generateProcessedContent' ),
00305                                          $ttl,
00306                                          $globalExpiryTime,
00307                                          $args );
00308     }
00309 
00310     function generateProcessedContent( $fname, $args )
00311     {
00312         extract( $args );
00313         $content = eZTemplateCacheFunction::processUncached( $tpl, $functionChildren, $rootNamespace, $currentNamespace );
00314         return array( 'scope'      => 'template-block',
00315                       'content'    => $content,
00316                       'binarydata' => $content );
00317     }
00318 
00319     /*!
00320      \private
00321      \static
00322      Performs processing of the cache-block using the non-compiled way and with caching off.
00323      */
00324     function processUncached( $tpl, $functionChildren, $rootNamespace, $currentNamespace )
00325     {
00326         $children = $functionChildren;
00327 
00328         $childTextElements = array();
00329         if ( is_array( $children ) )
00330         {
00331             foreach ( array_keys( $children ) as $childKey )
00332             {
00333                 $child =& $children[$childKey];
00334                 $tpl->processNode( $child, $childTextElements, $rootNamespace, $currentNamespace );
00335             }
00336         }
00337         $text = implode( '', $childTextElements );
00338         return $text;
00339     }
00340 
00341     /*!
00342      Returns true.
00343     */
00344     function hasChildren()
00345     {
00346         return true;
00347     }
00348 
00349     // Deprecated functions follow
00350 
00351     /*!
00352      \static
00353      \deprecated
00354      Returns base directory where 'subtree_expiry' caches are stored.
00355     */
00356     static function subtreeCacheBaseSubDir()
00357     {
00358         return eZTemplateCacheBlock::subtreeCacheBaseSubDir();
00359     }
00360 
00361     /*!
00362      \static
00363      \deprecated Does not seem to be used
00364      Returns base directory where expired 'subtree_expiry' caches are stored.
00365     */
00366     static function expiryTemplateBlockCacheDir()
00367     {
00368         //include_once( 'lib/ezutils/classes/ezsys.php' );
00369         $expiryCacheDir = eZSys::cacheDirectory() . '/' . 'template-block-expiry';
00370         return $expiryCacheDir;
00371     }
00372 
00373     /*!
00374      \static
00375      \deprecated
00376      Returns base directory where template block caches are stored.
00377     */
00378     static function templateBlockCacheDir()
00379     {
00380         return eZTemplateCacheBlock::templateBlockCacheDir();
00381     }
00382 
00383     /*!
00384      \static
00385      \deprecated
00386      Returns path of the directory where 'subtree_expiry' caches are stored.
00387     */
00388     static function subtreeCacheSubDir( $subtreeExpiryParameter, $cacheFilename )
00389     {
00390         return eZTemplateCacheBlock::subtreeCacheSubDir( $subtreeExpiryParameter, $cacheFilename );
00391     }
00392 
00393     /*!
00394      \static
00395      \deprecated
00396      Builds and returns path from $nodeID, e.g. if $nodeID = 23 then path = subtree/2/3
00397     */
00398     static function subtreeCacheSubDirForNode( $nodeID )
00399     {
00400         return eZTemplateCacheBlock::subtreeCacheSubDirForNode( $nodeID );
00401     }
00402 
00403     /// \privatesection
00404     /// Name of the function
00405     public $BlockName;
00406 }
00407 
00408 ?>