|
eZ Publish
[trunk]
|
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 ?>