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