eZ Publish  [trunk]
eztemplatecacheblock.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZTemplateCacheBlock class.
00004  *
00005  * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
00006  * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
00007  * @version //autogentag//
00008  * @package lib
00009  */
00010 
00011 /*!
00012   \class eZTemplateCacheBlock eztemplatecacheblock.php
00013   \brief Cache block
00014 
00015 */
00016 
00017 class eZTemplateCacheBlock
00018 {
00019     /*!
00020      Helper function for retrieving a cache-block entry which can be used by any custom code.
00021 
00022      \param $keys Array or string which is used for key. To ensure uniqueness prefix or add an entry which is unique to your code.
00023      \param $subtreeExpiry The subtree expiry value, use null to disable or a string. See subtreeCacheSubDir for more details.
00024      \param $ttl Amount of seconds the cache should live, use null, 0 or -1 to disable TTL.
00025      \param $useGlobalExpiry Boolean which controls if the global content expiry value should be used or not.
00026 
00027      Returns an array with the file handler objects as the first entry and the content data as the second.
00028      If the content could not be retrieved the content contains the object eZClusterFileFailure.
00029 
00030 
00031      Example of usage:
00032      \code
00033      list($handler, $data) = eZTemplateCacheBlock::retrieve( array( 'my_cool_key', $id, ), $nodeID, 60 ); // lives 60 seconds
00034      if ( !$data instanceof eZClusterFileFailure )
00035      {
00036          echo $data;
00037      }
00038      else
00039      {
00040          // ... generate the data
00041          $data = '...';
00042          $handler->storeCache( array( 'scope'      => 'template-block',
00043                                       'binarydata' => $data ) );
00044      }
00045      \endcode
00046 
00047      Note: Because of the cluster code the storeCache() call must occur to ensure stability.
00048 
00049      */
00050     static function retrieve( $keys, $subtreeExpiry, $ttl, $useGlobalExpiry = true )
00051     {
00052         $nodeID = $subtreeExpiry ? eZTemplateCacheBlock::decodeNodeID( $subtreeExpiry ) : false;
00053         $cachePath = eZTemplateCacheBlock::cachePath( eZTemplateCacheBlock::keyString( $keys ), $nodeID );
00054         return eZTemplateCacheBlock::handle( $cachePath, $nodeID, $ttl, $useGlobalExpiry );
00055     }
00056 
00057     /*!
00058      \static
00059      Helper function for the compiled code, similar to retrieve() but requires the $cachePath to be calculated up front.
00060      */
00061     static function handle( $cachePath, $nodeID, $ttl, $useGlobalExpiry = true )
00062     {
00063         $globalExpiryTime = -1;
00064         eZExpiryHandler::registerShutdownFunction();
00065         if ( $useGlobalExpiry )
00066         {
00067             $globalExpiryTime = eZExpiryHandler::getTimestamp( 'template-block-cache', -1 );
00068         }
00069 
00070         $cacheHandler = eZClusterFileHandler::instance( $cachePath );
00071 
00072         $subtreeExpiry = -1;
00073         // Perform an extra check if the DB handler is in use,
00074         // get the modified_subnode value from the specified node ($nodeID)
00075         // and use it as an extra expiry value.
00076         if ( $cacheHandler instanceof eZDBFileHandler or $cacheHandler instanceof eZDFSFileHandler )
00077         {
00078             $subtreeExpiry = eZTemplateCacheBlock::getSubtreeModification( $nodeID );
00079         }
00080         $globalExpiryTime = max( eZExpiryHandler::getTimestamp( 'global-template-block-cache', -1 ), // This expiry value is the true global expiry for cache-blocks
00081                                  $globalExpiryTime,
00082                                  $subtreeExpiry );
00083 
00084         if ( $ttl == 0 )
00085             $ttl = -1;
00086         return array( &$cacheHandler,
00087                       $cacheHandler->processCache( array( 'eZTemplateCacheBlock', 'retrieveContent' ), null,
00088                                                    $ttl, $globalExpiryTime ) );
00089     }
00090 
00091     /*!
00092      Figures out the modification time for the subtree by looking up the database using $nodeID.
00093      If $nodeID is set to false no lookup is done and it will return -1.
00094      */
00095     static function getSubtreeModification( $nodeID )
00096     {
00097         if ( $nodeID === false )
00098             return -1;
00099         $nodeID = (int)$nodeID;
00100         $sql = "SELECT modified_subnode FROM ezcontentobject_tree WHERE node_id=$nodeID";
00101         $db = eZDB::instance();
00102         $rows = $db->arrayQuery( $sql );
00103         if ( count( $rows ) > 0 )
00104             return $rows[0]['modified_subnode'];
00105         return -1;
00106     }
00107 
00108     /*!
00109      \static
00110      Calculates the key entry for the function placement array $functionPlacement and returns it.
00111 
00112      \note This function is placed in this class to reduce the need to load the class eZTemplateCacheFunction
00113            when the templates are compiled. This reduces memory usage.
00114      */
00115     static function placementString( $functionPlacement )
00116     {
00117         $placementString =  $functionPlacement[0][0] . "_";
00118         $placementString .= $functionPlacement[0][1] . "_";
00119         $placementString .= $functionPlacement[1][0] . "_";
00120         $placementString .= $functionPlacement[1][1] . "_";
00121         $placementString .= $functionPlacement[2];
00122         return $placementString;
00123     }
00124 
00125     /*!
00126      \static
00127      Calculates the key string from the key values $keys.
00128 
00129      Note: Arrays are traversed recursively.
00130      */
00131     static function keyString( $keys )
00132     {
00133         return serialize( $keys );
00134     }
00135 
00136     /*!
00137      \static
00138      Calculates the cache path based on the key string $keyString and $nodeID.
00139 
00140      See subtreeCacheSubDir() for more details on the $nodeID parameter.
00141      */
00142     static function cachePath( $keyString, $nodeID = false )
00143     {
00144         $filename = eZSys::ezcrc32( $keyString ) . ".cache";
00145 
00146         $phpDir = eZTemplateCacheBlock::templateBlockCacheDir();
00147         if ( is_numeric( $nodeID ) )
00148         {
00149             $phpDir .= eZTemplateCacheBlock::calculateSubtreeCacheDir( $nodeID, $filename );
00150         }
00151         else
00152         {
00153             $phpDir .= $filename[0] . '/' . $filename[1] . '/' . $filename[2];
00154         }
00155 
00156         $phpPath = $phpDir . '/' . $filename;
00157         return $phpPath;
00158     }
00159 
00160     /*!
00161      \static
00162      Returns base directory where template block caches are stored.
00163     */
00164     static function templateBlockCacheDir()
00165     {
00166         $cacheDir = eZSys::cacheDirectory() . '/template-block/' ;
00167         return $cacheDir;
00168     }
00169 
00170     /*!
00171      \static
00172      Figures out the node ID for the $subtreeExpiryParameter.
00173 
00174      The parameter $subtreeExpiryParameter is expiry value is usually taken from the template operator and can be one of:
00175      - A numerical value which represents the node ID (the fastest approach)
00176      - A string containing 'content/view/full/xxx' where xx is the node ID number, the number will be extracted.
00177      - A string containing a nice url which will be decoded into a node ID using the database (slowest approach).
00178     */
00179     static function decodeNodeID( $subtreeExpiryParameter )
00180     {
00181         $nodeID = false;
00182         if ( !is_numeric( $subtreeExpiryParameter ) )
00183         {
00184             $nodePathString = '';
00185 
00186             // clean up $subtreeExpiryParameter
00187             $subtreeExpiryParameter = trim( $subtreeExpiryParameter, '/' );
00188 
00189             $nodeID = false;
00190             $subtree = $subtreeExpiryParameter;
00191 
00192             if ( $subtree == '' )
00193             {
00194                 // 'subtree_expiry' is empty => use root node.
00195                 $nodeID = 2;
00196             }
00197             else
00198             {
00199                 $nonAliasPath = 'content/view/full/';
00200 
00201                 if ( strpos( $subtree, $nonAliasPath ) === 0 )
00202                 {
00203                     // 'subtree_expiry' is like 'content/view/full/2'
00204                     $nodeID = (int)substr( $subtree, strlen( $nonAliasPath ) );
00205                 }
00206                 else
00207                 {
00208                     // 'subtree_expiry' is url_alias
00209                     $nodeID = eZURLAliasML::fetchNodeIDByPath( $subtree );
00210                     if ( !$nodeID )
00211                     {
00212                         eZDebug::writeError( "Could not find path_string '$subtree' for 'subtree_expiry' node.", __METHOD__ );
00213                     }
00214                     else
00215                     {
00216                         $nodeID = (int)$nodeID;
00217                     }
00218                 }
00219             }
00220         }
00221         else
00222         {
00223             $nodeID = (int)$subtreeExpiryParameter;
00224         }
00225         return $nodeID;
00226     }
00227 
00228     /*!
00229      \static
00230      Returns path of the directory where 'subtree_expiry' caches are stored.
00231 
00232      See decodeNodeID() for details on the $subtreeExpiryParameter parameter.
00233     */
00234     static function calculateSubtreeCacheDir( $nodeID, $cacheFilename )
00235     {
00236         $cacheDir = eZTemplateCacheBlock::subtreeCacheSubDirForNode( $nodeID );
00237         $cacheDir .= '/' . $cacheFilename[0] . '/' . $cacheFilename[1] . '/' . $cacheFilename[2];
00238 
00239         return $cacheDir;
00240     }
00241 
00242     /*!
00243      \static
00244      Returns path of the directory where 'subtree_expiry' caches are stored.
00245 
00246      See decodeNodeID() for details on the $subtreeExpiryParameter parameter.
00247 
00248      \note If you know the node ID you can use calculateSubtreeCacheDir() instead.
00249     */
00250     static function subtreeCacheSubDir( $subtreeExpiryParameter, $cacheFilename )
00251     {
00252         $nodeID = eZTemplateCacheBlock::decodeNodeID( $subtreeExpiryParameter );
00253         return eZTemplateCacheBlock::calculateSubtreeCacheDir( $nodeID, $cacheFilename );
00254     }
00255 
00256     /*!
00257      \static
00258      Builds and returns path from $nodeID, e.g. if $nodeID = 23 then path = subtree/2/3
00259     */
00260     static function subtreeCacheSubDirForNode( $nodeID )
00261     {
00262         $cacheDir = eZTemplateCacheBlock::subtreeCacheBaseSubDir();
00263 
00264         if ( is_numeric( $nodeID ) )
00265         {
00266             $nodeID = (string)$nodeID;
00267             $length = strlen( $nodeID );
00268             $pos = 0;
00269             while ( $pos < $length )
00270             {
00271                 $cacheDir .= '/' . $nodeID[$pos];
00272                 ++$pos;
00273             }
00274         }
00275         else
00276         {
00277             eZDebug::writeWarning( "Unable to determine cacheDir for nodeID = $nodeID", __METHOD__ );
00278         }
00279 
00280         $cacheDir .= '/cache';
00281         return $cacheDir;
00282     }
00283 
00284     /*!
00285      \static
00286      Returns base directory where 'subtree_expiry' caches are stored.
00287     */
00288     static function subtreeCacheBaseSubDir()
00289     {
00290         return 'subtree';
00291     }
00292 
00293     /*!
00294      \static
00295      Callback function to get the contents of the specified filename.
00296 
00297      \param $fname Name of file
00298      \param $mtime Modified time of file.
00299      */
00300     static function retrieveContent( $fname, $mtime )
00301     {
00302         return file_get_contents( $fname );
00303     }
00304 }
00305 
00306 ?>