TYPO3 CMS  TYPO3_6-2
TreelistCacheUpdateHooks.php
Go to the documentation of this file.
1 <?php
3 
18 
26 
27  // Should not be manipulated from others except through the
28  // configuration provided @see __construct()
29  private $updateRequiringFields = array(
30  'pid',
31  'php_tree_stop',
32  'extendToSubpages'
33  );
34 
38  public function __construct() {
39  // As enableFields can be set dynamically we add them here
40  $pagesEnableFields = $GLOBALS['TCA']['pages']['ctrl']['enablecolumns'];
41  foreach ($pagesEnableFields as $pagesEnableField) {
42  $this->updateRequiringFields[] = $pagesEnableField;
43  }
44  $this->updateRequiringFields[] = $GLOBALS['TCA']['pages']['ctrl']['delete'];
45  // Extension can add fields to the pages table that require an
46  // update of the treelist cache, too; so we also add those
47  // example: $TYPO3_CONF_VARS['BE']['additionalTreelistUpdateFields'] .= ',my_field';
48  if (!empty($GLOBALS['TYPO3_CONF_VARS']['BE']['additionalTreelistUpdateFields'])) {
49  $additionalTreelistUpdateFields = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['BE']['additionalTreelistUpdateFields'], TRUE);
50  $this->updateRequiringFields = array_merge($this->updateRequiringFields, $additionalTreelistUpdateFields);
51  }
52  }
53 
65  public function processDatamap_afterDatabaseOperations($status, $table, $recordId, array $updatedFields, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain) {
66  if ($table == 'pages' && $this->requiresUpdate($updatedFields)) {
67  $affectedPagePid = 0;
68  $affectedPageUid = 0;
69  if ($status == 'new') {
70  // Detect new pages
71  // Resolve the uid
72  $affectedPageUid = $tceMain->substNEWwithIDs[$recordId];
73  $affectedPagePid = $updatedFields['pid'];
74  } elseif ($status == 'update') {
75  // Detect updated pages
76  $affectedPageUid = $recordId;
77  // When updating a page the pid is not directly available so we
78  // need to retrieve it ourselves.
79  $fullPageRecord = BackendUtility::getRecord($table, $recordId);
80  $affectedPagePid = $fullPageRecord['pid'];
81  }
82  $clearCacheActions = $this->determineClearCacheActions($status, $updatedFields);
83  $this->processClearCacheActions($affectedPageUid, $affectedPagePid, $updatedFields, $clearCacheActions);
84  }
85  }
86 
98  public function processCmdmap_postProcess($command, $table, $recordId, $commandValue, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain) {
99  $action = (is_array($commandValue) && isset($commandValue['action'])) ? (string)$commandValue['action'] : '';
100  if ($table === 'pages' && ($command === 'delete' || ($command === 'version' && $action === 'swap'))) {
101 
102  $affectedRecord = BackendUtility::getRecord($table, $recordId, '*', '', FALSE);
103  $affectedPageUid = $affectedRecord['uid'];
104  $affectedPagePid = $affectedRecord['pid'];
105 
106  // Faking the updated fields
107  $updatedFields = array();
108  if ($command === 'delete') {
109  $updatedFields['deleted'] = 1;
110  } else {
111  // page was published to live (swapped)
112  $updatedFields['t3ver_wsid'] = 0;
113  }
114  $clearCacheActions = $this->determineClearCacheActions(
115  'update',
116  $updatedFields
117  );
118 
119  $this->processClearCacheActions($affectedPageUid, $affectedPagePid, $updatedFields, $clearCacheActions);
120  }
121  }
122 
135  public function moveRecord_firstElementPostProcess($table, $recordId, $destinationPid, array $movedRecord, array $updatedFields, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain) {
136  if ($table == 'pages' && $this->requiresUpdate($updatedFields)) {
137  $affectedPageUid = $recordId;
138  $affectedPageOldPid = $movedRecord['pid'];
139  $affectedPageNewPid = $updatedFields['pid'];
140  $clearCacheActions = $this->determineClearCacheActions('update', $updatedFields);
141  // Clear treelist entries for old parent page
142  $this->processClearCacheActions($affectedPageUid, $affectedPageOldPid, $updatedFields, $clearCacheActions);
143  // Clear treelist entries for new parent page
144  $this->processClearCacheActions($affectedPageUid, $affectedPageNewPid, $updatedFields, $clearCacheActions);
145  }
146  }
147 
161  public function moveRecord_afterAnotherElementPostProcess($table, $recordId, $destinationPid, $originalDestinationPid, array $movedRecord, array $updatedFields, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain) {
162  if ($table == 'pages' && $this->requiresUpdate($updatedFields)) {
163  $affectedPageUid = $recordId;
164  $affectedPageOldPid = $movedRecord['pid'];
165  $affectedPageNewPid = $updatedFields['pid'];
166  $clearCacheActions = $this->determineClearCacheActions('update', $updatedFields);
167  // Clear treelist entries for old parent page
168  $this->processClearCacheActions($affectedPageUid, $affectedPageOldPid, $updatedFields, $clearCacheActions);
169  // Clear treelist entries for new parent page
170  $this->processClearCacheActions($affectedPageUid, $affectedPageNewPid, $updatedFields, $clearCacheActions);
171  }
172  }
173 
180  protected function requiresUpdate(array $updatedFields) {
181  $requiresUpdate = FALSE;
182  $updatedFieldNames = array_keys($updatedFields);
183  foreach ($updatedFieldNames as $updatedFieldName) {
184  if (in_array($updatedFieldName, $this->updateRequiringFields)) {
185  $requiresUpdate = TRUE;
186  break;
187  }
188  }
189  return $requiresUpdate;
190  }
191 
201  protected function processClearCacheActions($affectedPage, $affectedParentPage, $updatedFields, array $actions) {
202  $actionNames = array_keys($actions);
203  foreach ($actionNames as $actionName) {
204  switch ($actionName) {
205  case 'allParents':
206  $this->clearCacheForAllParents($affectedParentPage);
207  break;
208  case 'setExpiration':
209  // Only used when setting an end time for a page
210  $expirationTime = $updatedFields['endtime'];
211  $this->setCacheExpiration($affectedPage, $expirationTime);
212  break;
213  case 'uidInTreelist':
214  $this->clearCacheWhereUidInTreelist($affectedPage);
215  break;
216  }
217  }
218  // From time to time clean the cache from expired entries
219  // (theoretically every 1000 calls)
220  $randomNumber = rand(1, 1000);
221  if ($randomNumber == 500) {
222  $this->removeExpiredCacheEntries();
223  }
224  }
225 
233  protected function clearCacheForAllParents($affectedParentPage) {
234  $rootline = BackendUtility::BEgetRootLine($affectedParentPage);
235  $rootlineIds = array();
236  foreach ($rootline as $page) {
237  if ($page['uid'] != 0) {
238  $rootlineIds[] = $page['uid'];
239  }
240  }
241  if (!empty($rootlineIds)) {
242  $rootlineIdsImploded = implode(',', $rootlineIds);
243  $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_treelist', 'pid IN(' . $rootlineIdsImploded . ')');
244  }
245  }
246 
254  protected function clearCacheWhereUidInTreelist($affectedPage) {
255  $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_treelist', $GLOBALS['TYPO3_DB']->listQuery('treelist', $affectedPage, 'cache_treelist'));
256  }
257 
266  protected function setCacheExpiration($affectedPage, $expirationTime) {
267  $GLOBALS['TYPO3_DB']->exec_UPDATEquery('cache_treelist', $GLOBALS['TYPO3_DB']->listQuery('treelist', $affectedPage, 'cache_treelist'), array(
268  'expires' => $expirationTime
269  ));
270  }
271 
277  protected function removeExpiredCacheEntries() {
278  $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_treelist', 'expires <= ' . $GLOBALS['EXEC_TIME']);
279  }
280 
289  protected function determineClearCacheActions($status, $updatedFields) {
290  $actions = array();
291  if ($status == 'new') {
292  // New page
293  $actions['allParents'] = TRUE;
294  } elseif ($status == 'update') {
295  $updatedFieldNames = array_keys($updatedFields);
296  foreach ($updatedFieldNames as $updatedFieldName) {
297  switch ($updatedFieldName) {
298  case 'pid':
299 
300  case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['disabled']:
301 
302  case $GLOBALS['TCA']['pages']['ctrl']['delete']:
303 
304  case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['starttime']:
305 
306  case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['fe_group']:
307 
308  case 'extendToSubpages':
309 
310  case 't3ver_wsid':
311 
312  case 'php_tree_stop':
313  // php_tree_stop
314  $actions['allParents'] = TRUE;
315  $actions['uidInTreelist'] = TRUE;
316  break;
317  case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['endtime']:
318  // end time set/unset
319  // When setting an end time the cache entry needs an
320  // expiration time. When unsetting the end time the
321  // page must become listed in the treelist again.
322  if ($updatedFields['endtime'] > 0) {
323  $actions['setExpiration'] = TRUE;
324  } else {
325  $actions['uidInTreelist'] = TRUE;
326  }
327  break;
328  default:
329  if (in_array($updatedFieldName, $this->updateRequiringFields)) {
330  $actions['uidInTreelist'] = TRUE;
331  }
332  }
333  }
334  }
335  return $actions;
336  }
337 
338 }
moveRecord_afterAnotherElementPostProcess($table, $recordId, $destinationPid, $originalDestinationPid, array $movedRecord, array $updatedFields, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain)
processCmdmap_postProcess($command, $table, $recordId, $commandValue, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain)
static BEgetRootLine($uid, $clause='', $workspaceOL=FALSE)
processDatamap_afterDatabaseOperations($status, $table, $recordId, array $updatedFields, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
moveRecord_firstElementPostProcess($table, $recordId, $destinationPid, array $movedRecord, array $updatedFields, \TYPO3\CMS\Core\DataHandling\DataHandler $tceMain)
processClearCacheActions($affectedPage, $affectedParentPage, $updatedFields, array $actions)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]