eZ Publish  [4.1]
ezcontentcachemanager.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZContentCacheManager class
00004 //
00005 // Created on: <23-Sep-2004 12:52:38 jb>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.1.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2009 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 /*! \file
00032 */
00033 
00034 /*!
00035   \class eZContentCacheManager ezcontentcachemanager.php
00036   \brief Figures out relations between objects, nodes and classes for cache management
00037 
00038   This class works together with eZContentCache to manage the cache files
00039   for content viewing. This class takes care of finding out the relationship
00040   and then passes a list of nodes to eZContentCache which does the actual
00041   clearing.
00042 
00043   The manager uses special rules in 'viewcache.ini' to figure relationships.
00044   \sa eZContentCache
00045 */
00046 
00047 require_once( 'access.php' );
00048 
00049 class eZContentCacheManager
00050 {
00051     // Clear cache types
00052     const CLEAR_NO_CACHE       = 0;
00053     const CLEAR_NODE_CACHE     = 1;
00054     const CLEAR_PARENT_CACHE   = 2;
00055     const CLEAR_RELATING_CACHE = 4;
00056     const CLEAR_KEYWORD_CACHE  = 8;
00057     const CLEAR_SIBLINGS_CACHE = 16;
00058     const CLEAR_ALL_CACHE      = 31;
00059     const CLEAR_DEFAULT        = 15; // CLEAR_NODE_CACHE and CLEAR_PARENT_CACHE and CLEAR_RELATING_CACHE and CLEAR_KEYWORD_CACHE
00060 
00061     /*!
00062      \static
00063      Appends parent nodes ids of \a $object to \a $nodeIDList array.
00064      \param $versionNum The version of the object to use or \c true for current version
00065      \param[out] $nodeIDList Array with node IDs
00066     */
00067     static function appendParentNodeIDs( $object, $versionNum, &$nodeIDList )
00068     {
00069         foreach ( $object->parentNodeIDArray() as $parentNodeID )
00070         {
00071             $nodeIDList[] = $parentNodeID;
00072         }
00073     }
00074 
00075     /*!
00076      \static
00077      Appends nodes ids from \a $nodeList list to \a $nodeIDList
00078      \param[out] $nodeIDList Array with node IDs
00079     */
00080     static function appendNodeIDs( $nodeList, &$nodeIDList )
00081     {
00082         foreach ( $nodeList as $node )
00083         {
00084             $nodeIDList[] = $node->attribute( 'node_id' );
00085         }
00086     }
00087 
00088     /*!
00089      \static
00090      Goes through all content nodes in \a $nodeList and extracts the \c 'path_string'.
00091      \return An array with \c 'path_string' information.
00092     */
00093     static function fetchNodePathString( $nodeList )
00094     {
00095         $pathList = array();
00096         foreach ( $nodeList as $node )
00097         {
00098             $pathList[] = $node->attribute( 'path_string' );
00099         }
00100         return $pathList;
00101     }
00102 
00103     /*!
00104      \static
00105      Find all content objects that relates \a $object and appends
00106      their node IDs to \a $nodeIDList.
00107      \param[out] $nodeIDList Array with node IDs
00108     */
00109     static function appendRelatingNodeIDs( $object, &$nodeIDList )
00110     {
00111         $viewCacheIni = eZINI::instance( 'viewcache.ini' );
00112         if ( $viewCacheIni->hasVariable( 'ViewCacheSettings', 'ClearRelationTypes' ) )
00113         {
00114             $relTypes = $viewCacheIni->variable( 'ViewCacheSettings', 'ClearRelationTypes' );
00115 
00116             if ( !count( $relTypes ) )
00117                 return;
00118 
00119             $relatedObjects = array();
00120 
00121             $relationsMask = 0;
00122             if ( in_array( 'object', $relTypes ) )
00123                 $relationsMask |= eZContentObject::RELATION_COMMON | eZContentObject::RELATION_EMBED;
00124 
00125             if ( in_array( 'common', $relTypes ) )
00126                 $relationsMask |= eZContentObject::RELATION_COMMON;
00127 
00128             if ( in_array( 'embedded', $relTypes ) )
00129                 $relationsMask |= eZContentObject::RELATION_EMBED;
00130 
00131             if ( in_array( 'linked', $relTypes ) )
00132                 $relationsMask |= eZContentObject::RELATION_LINK;
00133 
00134             if ( in_array( 'attribute', $relTypes ) )
00135                 $relationsMask |= eZContentObject::RELATION_ATTRIBUTE;
00136 
00137             if ( $relationsMask )
00138             {
00139                 $objects = $object->relatedContentObjectList( false, false, false, false,
00140                                                               array( 'AllRelations' => $relationsMask ) );
00141                 $previousVersionObjects = array();
00142                 $previousVersion = $object->previousVersion();
00143                 if ( $previousVersion )
00144                 {
00145                     $previousVersionObjects = $object->relatedContentObjectList( $previousVersion, false, false, false,
00146                                                               array( 'AllRelations' => $relationsMask ) );
00147                 }
00148                 $relatedObjects = array_merge( $relatedObjects, $objects, $previousVersionObjects );
00149             }
00150 
00151             $relationsMask = 0;
00152             if ( in_array( 'reverse_object', $relTypes ) )
00153                 $relationsMask |= eZContentObject::RELATION_COMMON | eZContentObject::RELATION_EMBED;
00154 
00155             if ( in_array( 'reverse_common', $relTypes ) )
00156                 $relationsMask |= eZContentObject::RELATION_COMMON;
00157 
00158             if ( in_array( 'reverse_embedded', $relTypes ) )
00159                 $relationsMask |= eZContentObject::RELATION_EMBED;
00160 
00161             if ( in_array( 'reverse_linked', $relTypes ) )
00162                 $relationsMask |= eZContentObject::RELATION_LINK;
00163 
00164             if ( in_array( 'reverse_attribute', $relTypes ) )
00165                 $relationsMask |= eZContentObject::RELATION_ATTRIBUTE;
00166 
00167             if ( $relationsMask )
00168             {
00169                 $objects = $object->reverseRelatedObjectList( false, false, false,
00170                                                               array( 'AllRelations' => $relationsMask ) );
00171                 $previousVersionObjects = array();
00172                 $previousVersion = $object->previousVersion();
00173                 if ( $previousVersion )
00174                 {
00175                     $previousVersionObjects = $object->relatedContentObjectList( $previousVersion, false, false, false,
00176                                                               array( 'AllRelations' => $relationsMask ) );
00177                 }
00178                 $relatedObjects = array_merge( $relatedObjects, $objects, $previousVersionObjects );
00179             }
00180         }
00181         else
00182         {
00183             $normalRelated = $object->relatedContentObjectArray();
00184             $reversedRelated = $object->contentObjectListRelatingThis();
00185 
00186             $relatedObjects = array_merge( $normalRelated, $reversedRelated );
00187         }
00188 
00189         foreach ( $relatedObjects as $relatedObject )
00190         {
00191             $assignedNodes = $relatedObject->assignedNodes( false );
00192             foreach ( $assignedNodes as $assignedNode )
00193             {
00194                 $nodeIDList[] = $assignedNode['node_id'];
00195             }
00196         }
00197         $nodeIDList = array_unique( $nodeIDList );
00198     }
00199 
00200     /*!
00201      \static
00202      Appends node ids of objects with the same keyword(s) as \a $object to \a $nodeIDList array.
00203      \param $versionNum The version of the object to use or \c true for current version
00204      \param[out] $nodeIDList Array with node IDs
00205     */
00206     static function appendKeywordNodeIDs( $object, $versionNum, &$nodeIDList, $limit = null )
00207     {
00208         if ( $limit === 0 )
00209             return;
00210         if ( $versionNum === true )
00211             $versionNum = false;
00212         $keywordArray = array();
00213         $attributes = $object->contentObjectAttributes( true, $versionNum );
00214         foreach ( array_keys( $attributes ) as $key )  // Looking for ezkeyword attributes
00215         {
00216             if ( $attributes[$key] instanceof eZContentObjectAttribute and
00217                  $attributes[$key]->attribute( 'data_type_string' ) == 'ezkeyword' )  // Found one
00218             {
00219                 $keywordObject = $attributes[$key]->content();
00220                 if ( $keywordObject instanceof eZKeyword )
00221                 {
00222                     foreach ( $keywordObject->attribute( 'keywords' ) as $keyword )
00223                     {
00224                         $keywordArray[] = $keyword;
00225                     }
00226                 }
00227             }
00228         }
00229 
00230         // Find all nodes that have the given keywords
00231         if ( count( $keywordArray ) > 0 )
00232         {
00233             $db = eZDB::instance();
00234             foreach( $keywordArray as $k => $keyword )
00235             {
00236                 $keywordArray[$k] = "'" . $db->escapeString( $keyword ) . "'";
00237             }
00238             $keywordString = implode( ', ', $keywordArray );
00239             $params = $limit ? array( 'offset' => 0, 'limit'  => $limit ) : array();
00240             $rows = $db->arrayQuery( "SELECT DISTINCT ezcontentobject_tree.node_id
00241                                        FROM
00242                                          ezcontentobject_tree,
00243                                          ezcontentobject_attribute,
00244                                          ezkeyword_attribute_link,
00245                                          ezkeyword
00246                                        WHERE
00247                                          ezcontentobject_tree.contentobject_id = ezcontentobject_attribute.contentobject_id AND
00248                                          ezcontentobject_attribute.id = ezkeyword_attribute_link.objectattribute_id AND
00249                                          ezkeyword_attribute_link.keyword_id = ezkeyword.id AND
00250                                          ezkeyword.keyword IN ( $keywordString )",
00251                                         $params );
00252 
00253             foreach ( $rows as $row )
00254             {
00255                 $nodeIDList[] = $row['node_id'];
00256             }
00257         }
00258     }
00259 
00260     /*
00261      \static
00262      For each node in \a $nodeList finds its sibling nodes and adds its ids to
00263      the \a $nodeIDList
00264     */
00265     static function appendSiblingsNodeIDs( &$nodeList, &$nodeIDList )
00266     {
00267         $params = array( 'Depth' => 1,
00268                          'AsObject' => false );
00269         foreach ( $nodeList as $node )
00270         {
00271             $siblingNodeList = eZContentObjectTreeNode::subTreeByNodeID( $params, $node->attribute( 'parent_node_id' ) );
00272             if ( count( $siblingNodeList ) > 0 )
00273             {
00274                 foreach ( array_keys( $siblingNodeList ) as $siblingKey )
00275                 {
00276                     $nodeIDList[] = $siblingNodeList[$siblingKey]['node_id'];
00277                 }
00278             }
00279         }
00280     }
00281 
00282     /*
00283      \static
00284      Reads 'viewcache.ini' file and determines relation between
00285      \a $classID and another class.
00286 
00287      \return An associative array with information on the class, containsL:
00288              - dependent_class_identifier - The class identifier of objects that depend on this class
00289              - additional_objects - Array of additional arbitrary object ids to clear
00290              - max_parents - The maxium number of parent nodes to check, or \c 0 for no limit
00291              - clear_cache_type - Bitfield of clear types, see nodeListForObject() for more details
00292              - object_filter - Array with object IDs, if there are entries only these objects should be checked.
00293     */
00294     static function dependencyInfo( $classID, $ignoreINISettings = false )
00295     {
00296         $ini = eZINI::instance( 'viewcache.ini' );
00297         $info = false;
00298 
00299         if ( $ignoreINISettings || $ini->variable( 'ViewCacheSettings', 'SmartCacheClear' ) !== 'disabled' )
00300         {
00301             if ( $ini->hasGroup( $classID ) )
00302             {
00303                 $info = array();
00304                 $info['clear_cache_exclusive'] = $ini->variable( 'ViewCacheSettings', 'SmartCacheClear' ) === 'exclusive';
00305 
00306                 if ( $ini->hasVariable( $classID, 'DependentClassIdentifier' ) )
00307                     $info['dependent_class_identifier'] = $ini->variable( $classID, 'DependentClassIdentifier' );
00308 
00309                 if ( $ini->hasVariable( $classID, 'MaxParents' ) )
00310                     $info['max_parents'] = $ini->variable( $classID, 'MaxParents' );
00311                 else
00312                     $info['max_parents'] = 0;
00313 
00314                 if ( $ini->hasVariable( $classID, 'AdditionalObjectIDs' ) )
00315                     $info['additional_objects'] = $ini->variable( $classID, 'AdditionalObjectIDs' );
00316 
00317                 $info['clear_cache_type'] = 0;
00318                 if ( $ini->hasVariable( $classID, 'ClearCacheMethod' ) )
00319                 {
00320                     $type = $ini->variable( $classID, 'ClearCacheMethod' );
00321 
00322                     if ( is_array( $type ) )
00323                     {
00324                         if ( in_array( 'none', $type ) )
00325                         {
00326                             $info['clear_cache_type'] = self::CLEAR_NO_CACHE;
00327                         }
00328                         elseif ( in_array( 'all', $type ) )
00329                         {
00330                             $info['clear_cache_type'] = self::CLEAR_ALL_CACHE;
00331                         }
00332                         else
00333                         {
00334                             if ( in_array( 'object', $type ) )
00335                                 $info['clear_cache_type'] |= self::CLEAR_NODE_CACHE;
00336 
00337                             if ( in_array( 'parent', $type ) )
00338                                 $info['clear_cache_type'] |= self::CLEAR_PARENT_CACHE;
00339 
00340                             if ( in_array( 'relating', $type ) )
00341                                 $info['clear_cache_type'] |= self::CLEAR_RELATING_CACHE;
00342 
00343                             if ( in_array( 'keyword', $type ) )
00344                                 $info['clear_cache_type'] |= self::CLEAR_KEYWORD_CACHE;
00345 
00346                             if ( in_array( 'siblings', $type ) )
00347                                 $info['clear_cache_type'] |= self::CLEAR_SIBLINGS_CACHE;
00348                         }
00349                     }
00350                     else
00351                     {
00352                         // deprecated
00353                         if ( $type == 'clear_all_caches' )
00354                         {
00355                             $info['clear_cache_type'] = self::CLEAR_ALL_CACHE;
00356                         }
00357                         else
00358                         {
00359                             if ( $type == 'clear_object_caches_only' ||
00360                                  $type == 'clear_object_and_parent_nodes_caches' ||
00361                                  $type == 'clear_object_and_relating_objects_caches' )
00362                             {
00363                                 $info['clear_cache_type'] |= self::CLEAR_NODE_CACHE;
00364                             }
00365 
00366                             if ( $type == 'clear_object_and_parent_nodes_caches' ||
00367                                  $type == 'clear_parent_nodes_caches_only' ||
00368                                  $type == 'clear_parent_nodes_and_relating_caches' )
00369                             {
00370                                 $info['clear_cache_type'] |= self::CLEAR_PARENT_CACHE;
00371                             }
00372 
00373                             if ( $type == 'clear_object_and_relating_objects_caches' ||
00374                                  $type == 'clear_parent_nodes_and_relating_caches' ||
00375                                  $type == 'clear_relating_caches_only' )
00376                             {
00377                                 $info['clear_cache_type'] |= self::CLEAR_RELATING_CACHE;
00378                             }
00379 
00380                             if ( $type == 'clear_keyword_caches_only' )
00381                             {
00382                                 $info['clear_cache_type'] |= self::CLEAR_KEYWORD_CACHE;
00383                             }
00384                         }
00385                     }
00386                 }
00387                 else
00388                 {
00389                     $info['clear_cache_type'] = self::CLEAR_DEFAULT;
00390                 }
00391 
00392                 $info['object_filter'] = array();
00393                 if ( $ini->hasVariable( $classID, 'ObjectFilter' ) )
00394                 {
00395                     $info['object_filter'] = $ini->variable( $classID, 'ObjectFilter' );
00396                 }
00397             }
00398         }
00399 
00400         return $info;
00401     }
00402 
00403     /*
00404      Can be used to debug the \a $handledObjectList parameter of nodeListForObject()
00405     */
00406     static function writeDebugBits( $handledObjectList, $highestBit )
00407     {
00408         $bitPadLength = (int)( pow( $highestBit, 0.5 ) + 1 );
00409         //$bitPadLength = strlen( decbin( $highestBit ) );
00410 
00411         $objectIDList = array_keys( $handledObjectList );
00412         $maxObjectID = max( $objectIDList );
00413         $padLength = strlen( $maxObjectID ) + 2;
00414 
00415         $msg = '';
00416         foreach ( $handledObjectList as $objectID => $clearCacheType )
00417         {
00418             $bitString = decbin( $clearCacheType );
00419             $msg .= str_pad( $objectID, $padLength, ' ', STR_PAD_RIGHT ) . str_pad( $bitString, $bitPadLength, '0', STR_PAD_LEFT );
00420             $msg .= "\r\n";
00421         }
00422 
00423         eZDebug::writeDebug( $msg, 'eZContentCacheManager::writeDebugBits()' );
00424     }
00425 
00426     /*!
00427      \static
00428      Use \a $clearCacheType to include different kind of nodes( parent, relating, etc ).
00429      If \a $versionNum is true, then current version will be used.
00430 
00431      \param $contentObject Current content object that is checked.
00432      \param $versionNum The version of the object to use or \c true for current version
00433      \param $clearCacheType Bit field which controls the the extra nodes to include,
00434                             use bitwise or with one of these defines:
00435                             - self::CLEAR_NODE_CACHE - Clear the nodes of the object
00436                             - self::CLEAR_PARENT_CACHE - Clear the parent nodes of the object
00437                             - self::CLEAR_RELATING_CACHE - Clear nodes of objects that relate this object
00438                             - self::CLEAR_KEYWORD_CACHE - Clear nodes of objects that have the same keyword as this object
00439                             - self::CLEAR_SIBLINGS_CACHE - Clear caches for siblings of the node.
00440                             - self::CLEAR_ALL_CACHE - Enables all of the above
00441                             - self::CLEAR_NO_CACHE - Do not clear cache for current object.
00442      \param[out] $nodeList An array with node IDs that are affected by the current object change.
00443      \param[out] $handledObjectList An associative array with object IDs and the cache types that were handled for these objects already.
00444                                     Used to avoid infinite recursion.
00445 
00446      \note This function is recursive.
00447     */
00448     static function nodeListForObject( $contentObject, $versionNum, $clearCacheType, &$nodeList, &$handledObjectList )
00449     {
00450         $contentObjectID = $contentObject->attribute( 'id' );
00451 
00452         if ( isset( $handledObjectList[$contentObjectID] ) )
00453         {
00454             $handledObjectList[$contentObjectID] |= $clearCacheType;
00455         }
00456         else
00457         {
00458             $handledObjectList[$contentObjectID] = $clearCacheType;
00459         }
00460         //self::writeDebugBits( $handledObjectList, self::CLEAR_SIBLINGS_CACHE );
00461 
00462         $assignedNodes = $contentObject->assignedNodes();
00463 
00464         // determine if $contentObject has dependent objects for which cache should be cleared too.
00465         $objectClassIdentifier = $contentObject->attribute( 'class_identifier' );
00466         $dependentClassInfo = eZContentCacheManager::dependencyInfo( $objectClassIdentifier );
00467 
00468         if ( $dependentClassInfo['clear_cache_type'] === self::CLEAR_NO_CACHE )
00469         {
00470             // BC: Allow smart cache clear setting to specify no caching setting
00471             $clearCacheType = self::CLEAR_NO_CACHE;
00472         }
00473         else if ( $dependentClassInfo['clear_cache_exclusive'] === true )
00474         {
00475             // use class specific smart cache rules exclusivly
00476             $clearCacheType = $dependentClassInfo['clear_cache_type'];
00477         }
00478 
00479         if ( $clearCacheType === self::CLEAR_NO_CACHE )
00480         {
00481             // when recursing we will never have to handle this object again for other cache types
00482             // because types of caches to clear will always be set to none
00483             $handledObjectList[$contentObjectID] = self::CLEAR_ALL_CACHE;
00484         }
00485 
00486         if ( $clearCacheType & self::CLEAR_NODE_CACHE )
00487         {
00488             eZContentCacheManager::appendNodeIDs( $assignedNodes, $nodeList );
00489         }
00490 
00491         if ( $clearCacheType & self::CLEAR_PARENT_CACHE )
00492         {
00493             eZContentCacheManager::appendParentNodeIDs( $contentObject, $versionNum, $nodeList );
00494         }
00495 
00496         if ( $clearCacheType & self::CLEAR_RELATING_CACHE )
00497         {
00498             eZContentCacheManager::appendRelatingNodeIDs( $contentObject, $nodeList );
00499         }
00500 
00501         if ( $clearCacheType & self::CLEAR_KEYWORD_CACHE )
00502         {
00503             $keywordClearLimit = null;
00504             $viewcacheini = eZINI::instance( 'viewcache.ini' );
00505             if ( is_numeric( $viewcacheini->variable( 'ViewCacheSettings', 'KeywordNodesCacheClearLimit' ) ) )
00506                 $keywordClearLimit = (int) $viewcacheini->variable( 'ViewCacheSettings', 'KeywordNodesCacheClearLimit' );
00507 
00508             eZContentCacheManager::appendKeywordNodeIDs( $contentObject, $versionNum, $nodeList, $keywordClearLimit );
00509         }
00510 
00511         if ( $clearCacheType & self::CLEAR_SIBLINGS_CACHE )
00512         {
00513             eZContentCacheManager::appendSiblingsNodeIDs( $assignedNodes, $nodeList );
00514         }
00515 
00516         if ( $dependentClassInfo['clear_cache_type'] & self::CLEAR_SIBLINGS_CACHE )
00517         {
00518             if ( !( $clearCacheType & self::CLEAR_SIBLINGS_CACHE ) )
00519             {
00520                 eZContentCacheManager::appendSiblingsNodeIDs( $assignedNodes, $nodeList );
00521                 $handledObjectList[$contentObjectID] |= self::CLEAR_SIBLINGS_CACHE;
00522             }
00523 
00524             // drop 'siblings' bit and process parent nodes.
00525             // since 'sibling' mode is affected to the current object
00526             $dependentClassInfo['clear_cache_type'] &= ~self::CLEAR_SIBLINGS_CACHE;
00527         }
00528 
00529         if ( isset( $dependentClassInfo['additional_objects'] ) )
00530         {
00531             foreach( $dependentClassInfo['additional_objects'] as $objectID )
00532             {
00533                 // skip if cache type is already handled for this object
00534                 if ( isset( $handledObjectList[$objectID] ) && $handledObjectList[$objectID] & self::CLEAR_NODE_CACHE )
00535                 {
00536                     continue;
00537                 }
00538 
00539                 $object = eZContentObject::fetch( $objectID );
00540                 if ( $object )
00541                 {
00542                     //eZDebug::writeDebug( 'adding additional object ' . $objectID, 'eZContentCacheManager::nodeListForObject() for object ' . $contentObjectID );
00543                     eZContentCacheManager::nodeListForObject( $object, true, self::CLEAR_NODE_CACHE, $nodeList, $handledObjectList );
00544                 }
00545             }
00546         }
00547 
00548         if ( isset( $dependentClassInfo['dependent_class_identifier'] ) )
00549         {
00550             $maxParents = $dependentClassInfo['max_parents'];
00551             $dependentClassIdentifiers = $dependentClassInfo['dependent_class_identifier'];
00552             $smartClearType = $dependentClassInfo['clear_cache_type'];
00553 
00554             // getting 'path_string's for all locations.
00555             $nodePathList = eZContentCacheManager::fetchNodePathString( $assignedNodes );
00556 
00557             foreach ( $nodePathList as $nodePath )
00558             {
00559                 $step = 0;
00560 
00561                 // getting class identifier and node ID for each node in the $nodePath, up to $maxParents
00562                 $nodeInfoList = eZContentObjectTreeNode::fetchClassIdentifierListByPathString( $nodePath, false, $maxParents );
00563 
00564                 // for each node in $nodeInfoList determine if this node belongs to $dependentClassIdentifiers. If
00565                 // so then clear cache for this node.
00566                 foreach ( $nodeInfoList as $item )
00567                 {
00568                     if ( in_array( $item['class_identifier'], $dependentClassIdentifiers ) )
00569                     {
00570                         $object = eZContentObject::fetchByNodeID( $item['node_id'] );
00571                         if ( !$object instanceof eZContentObject )
00572                         {
00573                             continue;
00574                         }
00575                         $objectID = $object->attribute( 'id' );
00576 
00577                         if ( isset( $handledObjectList[$objectID] ) )
00578                         {
00579                             // remove cache types that were already handled
00580                             $smartClearType &= ~$handledObjectList[$objectID];
00581 
00582                             // if there are no cache types remaining, then skip
00583                             if ( $smartClearType == self::CLEAR_NO_CACHE )
00584                             {
00585                                 continue;
00586                             }
00587                         }
00588 
00589                         if ( count( $dependentClassInfo['object_filter'] ) > 0 )
00590                         {
00591                             if ( in_array( $objectID, $dependentClassInfo['object_filter'] ) )
00592                             {
00593                                 //eZDebug::writeDebug( 'adding parent ' . $objectID, 'eZContentCacheManager::nodeListForObject() for object ' . $contentObjectID );
00594                                 eZContentCacheManager::nodeListForObject( $object, true, $smartClearType, $nodeList, $handledObjectList );
00595                             }
00596                         }
00597                         else
00598                         {
00599                             //eZDebug::writeDebug( 'adding parent ' . $objectID, 'eZContentCacheManager::nodeListForObject() for object ' . $contentObjectID );
00600                             eZContentCacheManager::nodeListForObject( $object, true, $smartClearType, $nodeList, $handledObjectList );
00601                         }
00602                     }
00603                 }
00604             }
00605         }
00606 
00607         //self::writeDebugBits( $handledObjectList, self::CLEAR_SIBLINGS_CACHE );
00608     }
00609 
00610     /*!
00611      \static
00612      Figures out all nodes that are affected by the change of object \a $objectID.
00613      This involves finding all nodes, parent nodes and nodes of objects
00614      that relate this object.
00615      The 'viewcache.ini' file is also checked to see if some special content classes
00616      has dependencies to the current object, if this is true extra nodes might be
00617      included.
00618 
00619      \param $versionNum The version of the object to use or \c true for current version
00620      \param $additionalNodeList An array with node IDs to add to clear list,
00621                                 or \c false for no additional nodes.
00622      \return An array with node IDs that must have their viewcaches cleared.
00623     */
00624     static function nodeList( $objectID, $versionNum )
00625     {
00626         $nodeList = array();
00627 
00628         $object = eZContentObject::fetch( $objectID );
00629         if ( !$object )
00630         {
00631             return false;
00632         }
00633 
00634         eZContentCacheManager::nodeListForObject( $object, $versionNum, self::CLEAR_DEFAULT, $nodeList, $handledObjectList );
00635 
00636         return $nodeList;
00637     }
00638 
00639     /*!
00640      \static
00641      Depreciated. Use 'clearObjectViewCache' instead
00642     */
00643     static function clearViewCache( $objectID, $versionNum = true , $additionalNodeList = false )
00644     {
00645         eZDebug::writeWarning( "'clearViewCache' function was depreciated. Use 'clearObjectViewCache' instead", 'eZContentCacheManager::clearViewCache' );
00646         eZContentCacheManager::clearObjectViewCache( $objectID, $versionNum, $additionalNodeList );
00647     }
00648 
00649     /*!
00650      \static
00651      Clears view caches of nodes, parent nodes and relating nodes
00652      of content objects with id \a $objectID.
00653      It will use 'viewcache.ini' to determine additional nodes.
00654 
00655      \param $versionNum The version of the object to use or \c true for current version
00656      \param $additionalNodeList An array with node IDs to add to clear list,
00657                                 or \c false for no additional nodes.
00658     */
00659     static function clearObjectViewCache( $objectID, $versionNum = true, $additionalNodeList = false )
00660     {
00661         eZDebug::accumulatorStart( 'node_cleanup_list', '', 'Node cleanup list' );
00662 
00663         $nodeList = eZContentCacheManager::nodeList( $objectID, $versionNum );
00664 
00665         if ( $nodeList === false and !is_array( $additionalNodeList ) )
00666             return false;
00667 
00668         if ( $nodeList === false )
00669         {
00670             $nodeList = array();
00671         }
00672 
00673         if ( is_array( $additionalNodeList ) )
00674         {
00675             array_splice( $nodeList, count( $nodeList ), 0, $additionalNodeList );
00676         }
00677 
00678         if ( count( $nodeList ) == 0 )
00679         {
00680             return false;
00681         }
00682 
00683         $nodeList = array_unique( $nodeList );
00684 
00685         eZDebug::accumulatorStop( 'node_cleanup_list' );
00686 
00687         eZDebugSetting::writeDebug( 'kernel-content-edit', count( $nodeList ), "count in nodeList" );
00688 
00689         $ini = eZINI::instance();
00690         if ( $ini->variable( 'ContentSettings', 'StaticCache' ) == 'enabled' )
00691         {
00692             $staticCache = new eZStaticCache();
00693             $staticCache->generateAlwaysUpdatedCache();
00694             $staticCache->generateNodeListCache( $nodeList );
00695         }
00696 
00697         eZDebug::accumulatorStart( 'node_cleanup', '', 'Node cleanup' );
00698 
00699         eZContentObject::expireComplexViewModeCache();
00700         $cleanupValue = eZContentCache::calculateCleanupValue( count( $nodeList ) );
00701 
00702         if ( eZContentCache::inCleanupThresholdRange( $cleanupValue ) )
00703             eZContentCache::cleanup( $nodeList );
00704         else
00705             eZContentObject::expireAllViewCache();
00706 
00707         eZDebug::accumulatorStop( 'node_cleanup' );
00708         return true;
00709     }
00710 
00711     /*!
00712      \static
00713      Clears view cache for specified object.
00714      Checks 'ViewCaching' ini setting to determine whether cache is enabled or not.
00715     */
00716     static function clearObjectViewCacheIfNeeded( $objectID, $versionNum = true, $additionalNodeList = false )
00717     {
00718         $ini = eZINI::instance();
00719         if ( $ini->variable( 'ContentSettings', 'ViewCaching' ) === 'enabled' )
00720             eZContentCacheManager::clearObjectViewCache( $objectID, $versionNum, $additionalNodeList );
00721     }
00722 
00723     /*!
00724      \static
00725      Clears template-block cache and template-block with subtree_expiry parameter caches for specified object.
00726      Checks 'TemplateCache' ini setting to determine whether cache is enabled or not.
00727      If $objectID is \c false all template block caches will be cleared.
00728     */
00729     static function clearTemplateBlockCacheIfNeeded( $objectID )
00730     {
00731         $ini = eZINI::instance();
00732         if ( $ini->variable( 'TemplateSettings', 'TemplateCache' ) === 'enabled' )
00733             eZContentCacheManager::clearTemplateBlockCache( $objectID );
00734     }
00735 
00736     /*!
00737      \static
00738      Clears template-block cache and template-block with subtree_expiry parameter caches for specified object
00739      without checking 'TemplateCache' ini setting. If $objectID is \c false all template block caches will be cleared.
00740     */
00741     static function clearTemplateBlockCache( $objectID )
00742     {
00743         // ordinary template block cache
00744         eZContentObject::expireTemplateBlockCache();
00745 
00746         // subtree template block cache
00747         $nodeList = false;
00748         $object = false;
00749         if ( $objectID )
00750             $object = eZContentObject::fetch( $objectID );
00751         if ( $object )
00752             $nodeList = $object->assignedNodes();
00753 
00754         eZSubtreeCache::cleanup( $nodeList );
00755     }
00756 
00757     /*!
00758      \static
00759      Generates the related viewcaches (PreGeneration) for the content object.
00760      It will only do this if [ContentSettings]/PreViewCache in site.ini is enabled.
00761 
00762      \param $objectID The ID of the content object to generate caches for.
00763     */
00764     static function generateObjectViewCache( $objectID )
00765     {
00766         // Generate the view cache
00767         $ini = eZINI::instance();
00768         $object = eZContentObject::fetch( $objectID );
00769         $user = eZUser::currentUser();
00770 
00771         eZDebug::accumulatorStart( 'generate_cache', '', 'Generating view cache' );
00772         if ( $ini->variable( 'ContentSettings', 'PreViewCache' ) == 'enabled' )
00773         {
00774             $preCacheSiteaccessArray = $ini->variable( 'ContentSettings', 'PreCacheSiteaccessArray' );
00775 
00776             $currentSiteAccess = $GLOBALS['eZCurrentAccess']['name'];
00777 
00778             // This is the default view parameters for content/view
00779             $viewParameters = array( 'offset' => 0,
00780                                      'year' => false,
00781                                      'month' => false,
00782                                      'day' => false,
00783                                      'namefilter' => false );
00784             if ( is_array( $preCacheSiteaccessArray ) && count( $preCacheSiteaccessArray ) > 0 )
00785             {
00786                 foreach ( $preCacheSiteaccessArray as $changeToSiteAccess )
00787                 {
00788                     $GLOBALS['eZCurrentAccess']['name'] = $changeToSiteAccess;
00789     
00790                     if ( $GLOBALS['eZCurrentAccess']['type'] == EZ_ACCESS_TYPE_URI )
00791                     {
00792                         eZSys::clearAccessPath();
00793                         eZSys::addAccessPath( $changeToSiteAccess );
00794                     }
00795     
00796                     require_once( 'kernel/common/template.php' );
00797                     $tpl = templateInit();
00798                     $res = eZTemplateDesignResource::instance();
00799     
00800                     // Get the sitedesign and cached view preferences for this siteaccess
00801                     $siteini = eZINI::instance( 'site.ini', 'settings', null, null, false );
00802                     $siteini->prependOverrideDir( "siteaccess/$changeToSiteAccess", false, 'siteaccess' );
00803                     $siteini->loadCache();
00804                     $designSetting = $siteini->variable( "DesignSettings", "SiteDesign" );
00805                     $cachedViewPreferences = $siteini->variable( 'ContentSettings', 'CachedViewPreferences' );
00806                     $res->setDesignSetting( $designSetting, 'site' );
00807     
00808                     $res->setOverrideAccess( $changeToSiteAccess );
00809     
00810                     $language = false; // Needs to be specified if you want to generate the cache for a specific language
00811                     $viewMode = 'full';
00812     
00813                     $assignedNodes = $object->assignedNodes();
00814                     foreach ( $assignedNodes as $node )
00815                     {
00816                         // We want to generate the cache for the specified user
00817                         $previewCacheUsers = $ini->variable( 'ContentSettings', 'PreviewCacheUsers' );
00818                         foreach ( $previewCacheUsers as $previewCacheUserID )
00819                         {
00820                             // If the text is 'anon' we need to fetch the Anonymous user ID.
00821                             if ( $previewCacheUserID === 'anonymous' )
00822                             {
00823                                 $previewCacheUserID = $siteini->variable( "UserSettings", "AnonymousUserID" );
00824                                 $previewCacheUser = eZUser::fetch( $previewCacheUserID  );
00825                             }
00826                             else if ( $previewCacheUserID === 'current' )
00827                             {
00828                                 $previewCacheUser = $user;
00829                             }
00830                             else
00831                             {
00832                                 $previewCacheUser = eZUser::fetch( $previewCacheUserID  );
00833                             }
00834                             if ( !$previewCacheUser )
00835                                 continue;
00836     
00837                             // Before we generate the view cache we must change the currently logged in user to $previewCacheUser
00838                             // If not the templates might read in wrong personalized data (preferences etc.)
00839                             $previewCacheUser->setCurrentlyLoggedInUser( $previewCacheUser, $previewCacheUser->attribute( 'contentobject_id' ) );
00840     
00841                             // Cache the current node
00842                             $cacheFileArray = eZNodeviewfunctions::generateViewCacheFile( $previewCacheUser, $node->attribute( 'node_id' ), 0, false, $language, $viewMode, $viewParameters, $cachedViewPreferences );
00843                             $tmpRes = eZNodeviewfunctions::generateNodeView( $tpl, $node, $node->attribute( 'object' ), $language, $viewMode, 0, $cacheFileArray['cache_dir'], $cacheFileArray['cache_path'], true, $viewParameters );
00844     
00845                             // Cache the parent node
00846                             $parentNode = $node->attribute( 'parent' );
00847                             $objectID = $parentNode->attribute( 'contentobject_id' );
00848                             // if parent objectID is null or is 0 we should not create cache.
00849                             if ( $objectID )
00850                             {
00851                                 $cacheFileArray = eZNodeviewfunctions::generateViewCacheFile( $previewCacheUser, $parentNode->attribute( 'node_id' ), 0, false, $language, $viewMode, $viewParameters, $cachedViewPreferences );
00852                                 $tmpRes = eZNodeviewfunctions::generateNodeView( $tpl, $parentNode, $parentNode->attribute( 'object' ), $language, $viewMode, 0, $cacheFileArray['cache_dir'], $cacheFileArray['cache_path'], true, $viewParameters );
00853                             }
00854                         }
00855                     }
00856                 }
00857                 // Restore the old user as the current one
00858                 $user->setCurrentlyLoggedInUser( $user, $user->attribute( 'contentobject_id' ) );
00859     
00860                 $GLOBALS['eZCurrentAccess']['name'] = $currentSiteAccess;
00861                 $res->setDesignSetting( $currentSiteAccess, 'site' );
00862                 $res->setOverrideAccess( false );
00863     
00864                 if ( $GLOBALS['eZCurrentAccess']['type'] == EZ_ACCESS_TYPE_URI )
00865                 {
00866                     eZSys::clearAccessPath();
00867                     eZSys::addAccessPath( $currentSiteAccess );
00868                 }
00869             }
00870         }
00871 
00872         if ( $ini->variable( 'ContentSettings', 'StaticCache' ) == 'enabled' )
00873         {
00874             $nodes = array();
00875             $ini = eZINI::instance();
00876             $staticCache = new eZStaticCache();
00877             $useURLAlias =& $GLOBALS['eZContentObjectTreeNodeUseURLAlias'];
00878             $pathPrefix = $ini->variable( 'SiteAccessSettings', 'PathPrefix' );
00879 
00880             if ( !isset( $useURLAlias ) )
00881             {
00882                 $useURLAlias = $ini->variable( 'URLTranslator', 'Translation' ) == 'enabled';
00883             }
00884 
00885             eZContentCacheManager::nodeListForObject( $object, true, self::CLEAR_DEFAULT, $nodes, $handledObjectList );
00886 
00887             // If no nodes returns it means that ClearCacheMethod = self::CLEAR_NO_CACHE
00888             if ( count( $nodes ) )
00889             {
00890                 foreach ( $nodes as $nodeID )
00891                 {
00892                     if ( $useURLAlias )
00893                     {
00894                         $oNode = eZContentObjectTreeNode::fetch( $nodeID, false, true );
00895                         if ( !isset( $oNode ) )
00896                             continue;
00897 
00898                         $urlAlias = $oNode->urlAlias();
00899                         if ( $pathPrefix != '' )
00900                         {
00901                             $tempAlias = substr( $pathPrefix, strlen( $pathPrefix ) -1 ) == '/'
00902                                             ? $urlAlias . '/'
00903                                             : $urlAlias;
00904                             if ( strncmp( $tempAlias, $pathPrefix, strlen( $tempAlias) ) == 0 )
00905                                 $urlAlias = substr( $tempAlias, strlen( $pathPrefix ) );
00906                         }
00907                     }
00908                     else
00909                     {
00910                         $urlAlias = 'content/view/full/' . $nodeID;
00911                     }
00912                     $staticCache->cacheURL( '/' . $urlAlias, $nodeID );
00913                 }
00914                 $staticCache->generateAlwaysUpdatedCache();
00915             }
00916         }
00917         eZDebug::accumulatorStop( 'generate_cache' );
00918     }
00919 
00920     /*!
00921      \static
00922      Clears content cache if needed by \a $sectionID
00923     */
00924     static function clearContentCacheIfNeededBySectionID( $sectionID )
00925     {
00926         // fetch all objects of this section
00927         $objectList = eZContentObject::fetchList( false, array( 'section_id' => "$sectionID" ) );
00928         // Clear cache
00929         foreach ( $objectList as $object )
00930         {
00931             eZContentCacheManager::clearContentCacheIfNeeded( $object['id'] );
00932         }
00933         return true;
00934     }
00935 
00936     /*!
00937      \static
00938      Clears content cache for specified object: view cache, template-block cache, template-block with subtree_expiry parameter cache.
00939      Checks appropriate ini settings to determine whether caches are enabled or not.
00940     */
00941     static function clearContentCacheIfNeeded( $objectID, $versionNum = true, $additionalNodeList = false )
00942     {
00943         eZDebug::accumulatorStart( 'check_cache', '', 'Check cache' );
00944 
00945         eZContentCacheManager::clearObjectViewCacheIfNeeded( $objectID, $versionNum, $additionalNodeList );
00946         eZContentCacheManager::clearTemplateBlockCacheIfNeeded( $objectID );
00947 
00948         // Clear cached path strings of content SSL zones.
00949         eZSSLZone::clearCacheIfNeeded();
00950 
00951         eZDebug::accumulatorStop( 'check_cache' );
00952         return true;
00953     }
00954 
00955     /*!
00956      \static
00957      Clears content cache for specified object: view cache, template-block cache, template-block with subtree_expiry parameter cache
00958      without checking of ini settings.
00959     */
00960     static function clearContentCache( $objectID, $versionNum = true, $additionalNodeList = false )
00961     {
00962         eZDebug::accumulatorStart( 'check_cache', '', 'Check cache' );
00963 
00964         eZContentCacheManager::clearObjectViewCache( $objectID, $versionNum, $additionalNodeList );
00965         eZContentCacheManager::clearTemplateBlockCache( $objectID );
00966 
00967         // Clear cached path strings of content SSL zones.
00968         eZSSLZone::clearCache();
00969 
00970         eZDebug::accumulatorStop( 'check_cache' );
00971         return true;
00972     }
00973 
00974     /*!
00975      \static
00976      Clears all content cache: view cache, template-block cache, template-block with subtree_expiry parameter cache.
00977     */
00978     static function clearAllContentCache( $ignoreINISettings = false )
00979     {
00980         if ( !$ignoreINISettings )
00981         {
00982             $ini = eZINI::instance();
00983             $viewCacheEnabled = ( $ini->variable( 'ContentSettings', 'ViewCaching' ) === 'enabled' );
00984             $templateCacheEnabled = ( $ini->variable( 'TemplateSettings', 'TemplateCache' ) === 'enabled' );
00985         }
00986         else
00987         {
00988             $viewCacheEnabled = true;
00989             $templateCacheEnabled = true;
00990         }
00991 
00992         if ( $viewCacheEnabled || $templateCacheEnabled )
00993         {
00994             // view cache and/or ordinary template block cache
00995             eZContentObject::expireAllCache();
00996 
00997             // subtree template block caches
00998             if ( $templateCacheEnabled )
00999             {
01000                 eZSubtreeCache::cleanupAll();
01001             }
01002         }
01003     }
01004 }
01005 
01006 ?>