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