Bug #20566 » 11265_v2.diff
t3lib/config_default.php (Arbeitskopie) | ||
---|---|---|
'options' => array(
|
||
'cacheTable' => 'cache_pagesection'
|
||
)
|
||
),
|
||
'cache_treelist' => array(
|
||
'backend' => 't3lib_cache_backend_DbBackend',
|
||
'options' => array(
|
||
'cacheTable' => 'cache_treelist'
|
||
)
|
||
)
|
||
/*
|
||
For memcached, use:
|
t3lib/class.t3lib_cache.php (Arbeitskopie) | ||
---|---|---|
// do nothing, a cache_hash cache already exists
|
||
}
|
||
}
|
||
/**
|
||
* initializes the cache_treelist cache
|
||
*
|
||
* @return void
|
||
*/
|
||
public static function initTreeListCache() {
|
||
try {
|
||
$GLOBALS['typo3CacheFactory']->create(
|
||
'cache_treelist',
|
||
't3lib_cache_frontend_VariableFrontend',
|
||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_treelist']['backend'],
|
||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_treelist']['options']
|
||
);
|
||
} catch(t3lib_cache_exception_DuplicateIdentifier $e) {
|
||
// do nothing, a cache_hash cache already exists
|
||
}
|
||
}
|
||
}
|
||
t3lib/class.t3lib_tcemain.php (Arbeitskopie) | ||
---|---|---|
// clear all caches that use the t3lib_cache framework
|
||
$GLOBALS['typo3CacheManager']->flushCaches();
|
||
if (t3lib_extMgm::isLoaded('cms')) {
|
||
$GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_treelist', '');
|
||
}
|
||
// Clearing additional cache tables:
|
||
if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'])) {
|
||
foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'] as $tableName) {
|
typo3/init.php (Arbeitskopie) | ||
---|---|---|
t3lib_cache::initPageCache();
|
||
t3lib_cache::initPageSectionCache();
|
||
t3lib_cache::initContentHashCache();
|
||
t3lib_cache::initTreeListCache();
|
||
unset($cacheFactoryClass);
|
||
// *************************
|
typo3/sysext/cms/ext_tables.sql (Arbeitskopie) | ||
---|---|---|
# Table structure for table 'cache_treelist'
|
||
#
|
||
CREATE TABLE cache_treelist (
|
||
md5hash char(32) DEFAULT '' NOT NULL,
|
||
pid int(11) DEFAULT '0' NOT NULL,
|
||
treelist text,
|
||
tstamp int(11) DEFAULT '0' NOT NULL,
|
||
expires int(11) unsigned DEFAULT '0' NOT NULL,
|
||
PRIMARY KEY (md5hash)
|
||
identifier varchar(250) DEFAULT '' NOT NULL,
|
||
crdate int(11) unsigned DEFAULT '0' NOT NULL,
|
||
content mediumtext,
|
||
tags text,
|
||
lifetime int(11) unsigned DEFAULT '0' NOT NULL,
|
||
PRIMARY KEY (identifier)
|
||
) ENGINE=InnoDB;
|
||
typo3/sysext/cms/tslib/class.tslib_fe.php (Arbeitskopie) | ||
---|---|---|
t3lib_cache::initPageSectionCache();
|
||
t3lib_cache::initContentHashCache();
|
||
t3lib_cache::initTreeListCache();
|
||
$GLOBALS['TT']->pull();
|
||
}
|
typo3/sysext/cms/tslib/hooks/class.tx_cms_treelistcacheupdate.php (Arbeitskopie) | ||
---|---|---|
* @param t3lib_TCEmain TCEmain parent object
|
||
*/
|
||
public function processDatamap_afterDatabaseOperations($status, $table, $recordId, array $updatedFields, t3lib_TCEmain $tceMain) {
|
||
if ($table == 'pages' && $this->requiresUpdate($updatedFields)) {
|
||
$affectedPagePid = 0;
|
||
$affectedPageUid = 0;
|
||
if ($status == 'new') {
|
||
// detect new pages
|
||
// resolve the uid
|
||
$affectedPageUid = $tceMain->substNEWwithIDs[$recordId];
|
||
$affectedPagePid = $updatedFields['pid'];
|
||
} elseif ($status == 'update') {
|
||
// detect updated pages
|
||
$affectedPageUid = $recordId;
|
||
/*
|
||
detect updated pages
|
||
when updating a page the pid is not directly available so we
|
||
need to retrieve it ourselves.
|
||
*/
|
||
... | ... | |
);
|
||
$this->processClearCacheActions(
|
||
$affectedPageUid,
|
||
$affectedPagePid,
|
||
$updatedFields,
|
||
$clearCacheActions
|
||
);
|
||
}
|
||
... | ... | |
false
|
||
);
|
||
$affectedPageUid = $deletedRecord['uid'];
|
||
$affectedPagePid = $deletedRecord['pid'];
|
||
// faking the updated fields
|
||
$updatedFields = array('deleted' => 1);
|
||
... | ... | |
);
|
||
$this->processClearCacheActions(
|
||
$affectedPageUid,
|
||
$affectedPagePid,
|
||
$updatedFields,
|
||
$clearCacheActions
|
||
);
|
||
}
|
||
... | ... | |
if ($table == 'pages' && $this->requiresUpdate($updatedFields)) {
|
||
$affectedPageUid = $recordId;
|
||
$affectedPageOldPid = $movedRecord['pid'];
|
||
$affectedPageNewPid = $updatedFields['pid'];
|
||
... | ... | |
// clear treelist entries for old parent page
|
||
$this->processClearCacheActions(
|
||
$affectedPageUid,
|
||
$affectedPageOldPid,
|
||
$updatedFields,
|
||
$clearCacheActions
|
||
);
|
||
// clear treelist entries for new parent page
|
||
$this->processClearCacheActions(
|
||
$affectedPageUid,
|
||
$affectedPageNewPid,
|
||
$updatedFields,
|
||
$clearCacheActions
|
||
);
|
||
}
|
||
... | ... | |
if ($table == 'pages' && $this->requiresUpdate($updatedFields)) {
|
||
$affectedPageUid = $recordId;
|
||
$affectedPageOldPid = $movedRecord['pid'];
|
||
$affectedPageNewPid = $updatedFields['pid'];
|
||
... | ... | |
// clear treelist entries for old parent page
|
||
$this->processClearCacheActions(
|
||
$affectedPageUid,
|
||
$affectedPageOldPid,
|
||
$updatedFields,
|
||
$clearCacheActions
|
||
);
|
||
// clear treelist entries for new parent page
|
||
$this->processClearCacheActions(
|
||
$affectedPageUid,
|
||
$affectedPageNewPid,
|
||
$updatedFields,
|
||
$clearCacheActions
|
||
);
|
||
}
|
||
... | ... | |
/**
|
||
* calls the cache maintainance functions according to the determined actions
|
||
*
|
||
* @param integer uid of the affected page
|
||
* @param integer parent uid of the affected page
|
||
* @param array array of updated fields and their new values
|
||
* @param array array of actions to carry out
|
||
*/
|
||
protected function processClearCacheActions($affectedPage, $affectedParentPage, $updatedFields, array $actions) {
|
||
protected function processClearCacheActions($affectedParentPage, array $actions) {
|
||
$actionNames = array_keys($actions);
|
||
foreach ($actionNames as $actionName) {
|
||
switch ($actionName) {
|
||
case 'allParents':
|
||
$this->clearCacheForAllParents($affectedParentPage);
|
||
break;
|
||
case 'setExpiration':
|
||
// only used when setting an end time for a page
|
||
$expirationTime = $updatedFields['endtime'];
|
||
$this->setCacheExpiration($affectedPage, $expirationTime);
|
||
case 'flush':
|
||
$this->clearTreeListCache();
|
||
break;
|
||
case 'uidInTreelist':
|
||
$this->clearCacheWhereUidInTreelist($affectedPage);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
// from time to time clean the cache from expired entries
|
||
// (theoretically every 1000 calls)
|
||
$randomNumber = rand(1, 1000);
|
||
if ($randomNumber == 500) {
|
||
$this->removeExpiredCacheEntries();
|
||
}
|
||
/**
|
||
* clears the treelist cache.
|
||
*
|
||
*/
|
||
protected function clearTreeListCache() {
|
||
$GLOBALS['typo3CacheManager']->getCache('cache_treelist')->flush();
|
||
}
|
||
/**
|
||
... | ... | |
protected function clearCacheForAllParents($affectedParentPage) {
|
||
$rootline = t3lib_BEfunc::BEgetRootLine($affectedParentPage);
|
||
$rootlineIds = array();
|
||
$tags = array();
|
||
foreach ($rootline as $page) {
|
||
if($page['uid'] != 0) {
|
||
$rootlineIds[] = $page['uid'];
|
||
$tags[] = 'treeListID_'.$page['uid'];
|
||
}
|
||
}
|
||
if (!empty($rootlineIds)) {
|
||
$rootlineIdsImploded = implode(',', $rootlineIds);
|
||
$GLOBALS['TYPO3_DB']->exec_DELETEquery(
|
||
'cache_treelist',
|
||
'pid IN(' . $rootlineIdsImploded . ')'
|
||
);
|
||
if (!empty($tags)) {
|
||
$GLOBALS['typo3CacheManager']->getCache('cache_treelist')->flushByTags($tags);
|
||
}
|
||
}
|
||
/**
|
||
* clears the treelist cache for all pages where the affected page is found
|
||
* in the treelist
|
||
*
|
||
* @param integer Id of the changed page
|
||
*/
|
||
protected function clearCacheWhereUidInTreelist($affectedPage) {
|
||
$GLOBALS['TYPO3_DB']->exec_DELETEquery(
|
||
'cache_treelist',
|
||
$GLOBALS['TYPO3_DB']->listQuery(
|
||
'treelist',
|
||
$affectedPage,
|
||
'cache_treelist'
|
||
)
|
||
);
|
||
}
|
||
/**
|
||
* sets an expiration time for all cache entries having the changed page in
|
||
* the treelist.
|
||
*
|
||
* @param integer uid of the changed page
|
||
*/
|
||
protected function setCacheExpiration($affectedPage, $expirationTime) {
|
||
$GLOBALS['TYPO3_DB']->exec_UPDATEquery(
|
||
'cache_treelist',
|
||
$GLOBALS['TYPO3_DB']->listQuery(
|
||
'treelist',
|
||
$affectedPage,
|
||
'cache_treelist'
|
||
),
|
||
array(
|
||
'expires' => $expirationTime
|
||
)
|
||
);
|
||
}
|
||
/**
|
||
* removes all expired treelist cache entries
|
||
*
|
||
*/
|
||
protected function removeExpiredCacheEntries() {
|
||
$GLOBALS['TYPO3_DB']->exec_DELETEquery(
|
||
'cache_treelist',
|
||
'expires <= ' . time()
|
||
);
|
||
}
|
||
/**
|
||
* determines what happened to the page record, this is necessary to clear
|
||
* as less cache entries as needed later
|
||
*
|
||
... | ... | |
$actions['allParents'] = true;
|
||
} elseif ($status == 'update') {
|
||
$updatedFieldNames = array_keys($updatedFields);
|
||
foreach ($updatedFieldNames as $updatedFieldName) {
|
||
switch ($updatedFieldName) {
|
||
case 'pid':
|
||
// page moved
|
||
$actions['allParents'] = true;
|
||
$actions['uidInTreelist'] = true;
|
||
break;
|
||
case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['disabled']:
|
||
case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['fe_group']:
|
||
case $GLOBALS['TCA']['pages']['ctrl']['delete']:
|
||
case 'extendToSubpages':
|
||
case 'php_tree_stop':
|
||
// page hidden / unhidden / deleted / extendToSubpages set
|
||
// php_tree_stop and/or FE groups set
|
||
$actions['uidInTreelist'] = true;
|
||
break;
|
||
case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['starttime']:
|
||
/*
|
||
start time set/unset
|
||
Doesn't matter whether it was set or unset, in both
|
||
cases the cache needs to be cleared. When setting a
|
||
start time the page must be removed from the
|
||
treelist. When unsetting the start time it must
|
||
become listed in the tree list again.
|
||
*/
|
||
$actions['uidInTreelist'] = true;
|
||
break;
|
||
case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['endtime']:
|
||
/*
|
||
end time set/unset
|
||
When setting an end time the cache entry needs an
|
||
expiration time. When unsetting the end time the
|
||
page must become listed in the treelist again.
|
||
*/
|
||
if($updatedFields['endtime'] > 0) {
|
||
$actions['setExpiration'] = true;
|
||
} else {
|
||
$actions['uidInTreelist'] = true;
|
||
}
|
||
break;
|
||
default:
|
||
if (in_array($updatedFieldName, $this->updateRequiringFields)) {
|
||
$actions['uidInTreelist'] = true;
|
||
}
|
||
}
|
||
if (count(array_intersect($this->updateRequiringFields,$updatedFieldNames))) {
|
||
$actions['flush'] = true;
|
||
}
|
||
}
|
||
return $actions;
|
||
}
|
||
typo3/sysext/cms/tslib/class.tslib_content.php (Arbeitskopie) | ||
---|---|---|
$id = intval($id);
|
||
$theList = '';
|
||
$addId = 0;
|
||
$requestHash = '';
|
||
if ($id) {
|
||
... | ... | |
$moreWhereClauses,
|
||
$prevId_array
|
||
);
|
||
$requestHash = md5(serialize($parameters));
|
||
$cacheEntry = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
|
||
'treelist',
|
||
'cache_treelist',
|
||
'md5hash = \'' . $requestHash . '\' AND ( expires > ' . time() . ' OR expires = 0 )'
|
||
);
|
||
$identifier = md5(serialize($parameters));
|
||
$theList = $GLOBALS['typo3CacheManager']->getCache('cache_treelist')->get($identifier);
|
||
if (!empty($cacheEntry[0]['treelist'])) {
|
||
if (!empty($theList)) {
|
||
// cache hit
|
||
t3lib_div::devLog('Cache Treelist: HIT', 'tslib_cObj');
|
||
return $cacheEntry[0]['treelist'];
|
||
} else {
|
||
// cache miss
|
||
t3lib_div::devLog('Cache Treelist: MISS', 'tslib_cObj');
|
||
return $theList;
|
||
}
|
||
// If Id less than zero it means we should add the real id to list:
|
||
... | ... | |
}
|
||
}
|
||
$GLOBALS['TYPO3_DB']->exec_INSERTquery(
|
||
'cache_treelist',
|
||
array(
|
||
'md5hash' => $requestHash,
|
||
'pid' => $id,
|
||
'treelist' => $theList,
|
||
'tstamp' => time()
|
||
)
|
||
);
|
||
$GLOBALS['typo3CacheManager']->getCache('cache_treelist')->set($identifier, $theList, array('treeListID_'.$id), 0);
|
||
}
|
||
// Return list:
|
||
return $theList;
|