|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2008-2011 Ingo Renner (ingo@typo3.org) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 00028 00029 /** 00030 * Class that hooks into TCEmain and listens for updates to pages to update the 00031 * treelist cache 00032 * 00033 * @author Ingo Renner <ingo@typo3.org> 00034 * @package TYPO3 00035 * @subpackage tslib 00036 */ 00037 class tx_cms_treelistCacheUpdate { 00038 00039 // should not be manipulated from others except through the 00040 // configuration provided @see __construct() 00041 private $updateRequiringFields = array( 00042 'pid', 00043 'php_tree_stop', 00044 'extendToSubpages' 00045 ); 00046 00047 /** 00048 * constructor, adds update requiring fields to the default ones 00049 * 00050 */ 00051 public function __construct() { 00052 00053 // as enableFields can be set dynamically we add them here 00054 $pagesEnableFields = $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']; 00055 foreach ($pagesEnableFields as $pagesEnableField) { 00056 $this->updateRequiringFields[] = $pagesEnableField; 00057 } 00058 $this->updateRequiringFields[] = $GLOBALS['TCA']['pages']['ctrl']['delete']; 00059 00060 // extension can add fields to the pages table that require an 00061 // update of the treelist cache, too; so we also add those 00062 // example: $TYPO3_CONF_VARS['BE']['additionalTreelistUpdateFields'] .= ',my_field'; 00063 if (!empty($GLOBALS['TYPO3_CONF_VARS']['BE']['additionalTreelistUpdateFields'])) { 00064 $additionalTreelistUpdateFields = t3lib_div::trimExplode( 00065 ',', 00066 $GLOBALS['TYPO3_CONF_VARS']['BE']['additionalTreelistUpdateFields'], 00067 true 00068 ); 00069 00070 $this->updateRequiringFields += $additionalTreelistUpdateFields; 00071 } 00072 00073 } 00074 00075 /** 00076 * waits for TCEmain commands and looks for changed pages, if found further 00077 * changes take place to determine whether the cache needs to be updated 00078 * 00079 * @param string TCEmain operation status, either 'new' or 'update' 00080 * @param string the DB table the operation was carried out on 00081 * @param mixed the record's uid for update records, a string to look the record's uid up after it has been created 00082 * @param array array of changed fiels and their new values 00083 * @param t3lib_TCEmain TCEmain parent object 00084 */ 00085 public function processDatamap_afterDatabaseOperations($status, $table, $recordId, array $updatedFields, t3lib_TCEmain $tceMain) { 00086 00087 if ($table == 'pages' && $this->requiresUpdate($updatedFields)) { 00088 $affectedPagePid = 0; 00089 $affectedPageUid = 0; 00090 00091 if ($status == 'new') { 00092 // detect new pages 00093 00094 // resolve the uid 00095 $affectedPageUid = $tceMain->substNEWwithIDs[$recordId]; 00096 $affectedPagePid = $updatedFields['pid']; 00097 } elseif ($status == 'update') { 00098 // detect updated pages 00099 00100 $affectedPageUid = $recordId; 00101 00102 /* 00103 when updating a page the pid is not directly available so we 00104 need to retrieve it ourselves. 00105 */ 00106 $fullPageRecord = t3lib_BEfunc::getRecord($table, $recordId); 00107 $affectedPagePid = $fullPageRecord['pid']; 00108 } 00109 00110 $clearCacheActions = $this->determineClearCacheActions( 00111 $status, 00112 $updatedFields 00113 ); 00114 00115 $this->processClearCacheActions( 00116 $affectedPageUid, 00117 $affectedPagePid, 00118 $updatedFields, 00119 $clearCacheActions 00120 ); 00121 } 00122 } 00123 00124 /** 00125 * waits for TCEmain commands and looks for deleted pages, if found further 00126 * changes take place to determine whether the cache needs to be updated 00127 * 00128 * @param string the TCE command 00129 * @param string the record's table 00130 * @param integer the record's uid 00131 * @param array the commands value, typically an array with more detailed command information 00132 * @param t3lib_TCEmain the TCEmain parent object 00133 */ 00134 public function processCmdmap_postProcess($command, $table, $recordId, $commandValue, t3lib_TCEmain $tceMain) { 00135 00136 if ($table == 'pages' && $command == 'delete') { 00137 00138 $deletedRecord = t3lib_BEfunc::getRecord( 00139 $table, 00140 $recordId, 00141 '*', 00142 '', 00143 false 00144 ); 00145 00146 $affectedPageUid = $deletedRecord['uid']; 00147 $affectedPagePid = $deletedRecord['pid']; 00148 // faking the updated fields 00149 $updatedFields = array('deleted' => 1); 00150 00151 $clearCacheActions = $this->determineClearCacheActions( 00152 'update', 00153 $updatedFields 00154 ); 00155 00156 $this->processClearCacheActions( 00157 $affectedPageUid, 00158 $affectedPagePid, 00159 $updatedFields, 00160 $clearCacheActions 00161 ); 00162 } 00163 } 00164 00165 /** 00166 * waits for TCEmain commands and looks for moved pages, if found further 00167 * changes take place to determine whether the cache needs to be updated 00168 * 00169 * @param string table name of the moved record 00170 * @param integer the record's uid 00171 * @param integer the record's destination page id 00172 * @param array the record that moved 00173 * @param array array of changed fields 00174 * @param t3lib_TCEmain TCEmain parent object 00175 */ 00176 public function moveRecord_firstElementPostProcess($table, $recordId, $destinationPid, array $movedRecord, array $updatedFields, t3lib_TCEmain $tceMain) { 00177 00178 if ($table == 'pages' && $this->requiresUpdate($updatedFields)) { 00179 00180 $affectedPageUid = $recordId; 00181 $affectedPageOldPid = $movedRecord['pid']; 00182 $affectedPageNewPid = $updatedFields['pid']; 00183 00184 $clearCacheActions = $this->determineClearCacheActions( 00185 'update', 00186 $updatedFields 00187 ); 00188 00189 // clear treelist entries for old parent page 00190 $this->processClearCacheActions( 00191 $affectedPageUid, 00192 $affectedPageOldPid, 00193 $updatedFields, 00194 $clearCacheActions 00195 ); 00196 // clear treelist entries for new parent page 00197 $this->processClearCacheActions( 00198 $affectedPageUid, 00199 $affectedPageNewPid, 00200 $updatedFields, 00201 $clearCacheActions 00202 ); 00203 } 00204 } 00205 00206 /** 00207 * waits for TCEmain commands and looks for moved pages, if found further 00208 * changes take place to determine whether the cache needs to be updated 00209 * 00210 * @param string table name of the moved record 00211 * @param integer the record's uid 00212 * @param integer the record's destination page id 00213 * @param integer (negative) page id th page has been moved after 00214 * @param array the record that moved 00215 * @param array array of changed fields 00216 * @param t3lib_TCEmain TCEmain parent object 00217 */ 00218 public function moveRecord_afterAnotherElementPostProcess($table, $recordId, $destinationPid, $originalDestinationPid, array $movedRecord, array $updatedFields, t3lib_TCEmain $tceMain) { 00219 00220 if ($table == 'pages' && $this->requiresUpdate($updatedFields)) { 00221 00222 $affectedPageUid = $recordId; 00223 $affectedPageOldPid = $movedRecord['pid']; 00224 $affectedPageNewPid = $updatedFields['pid']; 00225 00226 $clearCacheActions = $this->determineClearCacheActions( 00227 'update', 00228 $updatedFields 00229 ); 00230 00231 // clear treelist entries for old parent page 00232 $this->processClearCacheActions( 00233 $affectedPageUid, 00234 $affectedPageOldPid, 00235 $updatedFields, 00236 $clearCacheActions 00237 ); 00238 // clear treelist entries for new parent page 00239 $this->processClearCacheActions( 00240 $affectedPageUid, 00241 $affectedPageNewPid, 00242 $updatedFields, 00243 $clearCacheActions 00244 ); 00245 } 00246 } 00247 00248 /** 00249 * checks whether the change requires an update of the treelist cache 00250 * 00251 * @param array array of changed fields 00252 * @return boolean true if the treelist cache needs to be updated, false if no update to the cache is required 00253 */ 00254 protected function requiresUpdate(array $updatedFields) { 00255 $requiresUpdate = false; 00256 00257 $updatedFieldNames = array_keys($updatedFields); 00258 foreach ($updatedFieldNames as $updatedFieldName) { 00259 if (in_array($updatedFieldName, $this->updateRequiringFields)) { 00260 $requiresUpdate = true; 00261 break; 00262 } 00263 } 00264 00265 return $requiresUpdate; 00266 } 00267 00268 /** 00269 * calls the cache maintainance functions according to the determined actions 00270 * 00271 * @param integer uid of the affected page 00272 * @param integer parent uid of the affected page 00273 * @param array array of updated fields and their new values 00274 * @param array array of actions to carry out 00275 */ 00276 protected function processClearCacheActions($affectedPage, $affectedParentPage, $updatedFields, array $actions) { 00277 $actionNames = array_keys($actions); 00278 foreach ($actionNames as $actionName) { 00279 switch ($actionName) { 00280 case 'allParents': 00281 $this->clearCacheForAllParents($affectedParentPage); 00282 break; 00283 case 'setExpiration': 00284 // only used when setting an end time for a page 00285 $expirationTime = $updatedFields['endtime']; 00286 $this->setCacheExpiration($affectedPage, $expirationTime); 00287 break; 00288 case 'uidInTreelist': 00289 $this->clearCacheWhereUidInTreelist($affectedPage); 00290 break; 00291 } 00292 } 00293 00294 // from time to time clean the cache from expired entries 00295 // (theoretically every 1000 calls) 00296 $randomNumber = rand(1, 1000); 00297 if ($randomNumber == 500) { 00298 $this->removeExpiredCacheEntries(); 00299 } 00300 } 00301 00302 /** 00303 * clears the treelist cache for all parents of a changed page. 00304 * gets called after creating a new page and after moving a page 00305 * 00306 * @param integer parent page id of the changed page, the page to start clearing from 00307 */ 00308 protected function clearCacheForAllParents($affectedParentPage) { 00309 $rootline = t3lib_BEfunc::BEgetRootLine($affectedParentPage); 00310 00311 $rootlineIds = array(); 00312 foreach ($rootline as $page) { 00313 if($page['uid'] != 0) { 00314 $rootlineIds[] = $page['uid']; 00315 } 00316 } 00317 00318 if (!empty($rootlineIds)) { 00319 $rootlineIdsImploded = implode(',', $rootlineIds); 00320 00321 $GLOBALS['TYPO3_DB']->exec_DELETEquery( 00322 'cache_treelist', 00323 'pid IN(' . $rootlineIdsImploded . ')' 00324 ); 00325 } 00326 } 00327 00328 /** 00329 * clears the treelist cache for all pages where the affected page is found 00330 * in the treelist 00331 * 00332 * @param integer Id of the changed page 00333 */ 00334 protected function clearCacheWhereUidInTreelist($affectedPage) { 00335 $GLOBALS['TYPO3_DB']->exec_DELETEquery( 00336 'cache_treelist', 00337 $GLOBALS['TYPO3_DB']->listQuery( 00338 'treelist', 00339 $affectedPage, 00340 'cache_treelist' 00341 ) 00342 ); 00343 } 00344 00345 /** 00346 * sets an expiration time for all cache entries having the changed page in 00347 * the treelist. 00348 * 00349 * @param integer uid of the changed page 00350 */ 00351 protected function setCacheExpiration($affectedPage, $expirationTime) { 00352 00353 $GLOBALS['TYPO3_DB']->exec_UPDATEquery( 00354 'cache_treelist', 00355 $GLOBALS['TYPO3_DB']->listQuery( 00356 'treelist', 00357 $affectedPage, 00358 'cache_treelist' 00359 ), 00360 array( 00361 'expires' => $expirationTime 00362 ) 00363 ); 00364 } 00365 00366 /** 00367 * removes all expired treelist cache entries 00368 * 00369 */ 00370 protected function removeExpiredCacheEntries() { 00371 $GLOBALS['TYPO3_DB']->exec_DELETEquery( 00372 'cache_treelist', 00373 'expires <= ' . $GLOBALS['EXEC_TIME'] 00374 ); 00375 } 00376 00377 /** 00378 * determines what happened to the page record, this is necessary to clear 00379 * as less cache entries as needed later 00380 * 00381 * @param string TCEmain operation status, either 'new' or 'update' 00382 * @param array array of updated fields 00383 * @return string list of actions that happened to the page record 00384 */ 00385 protected function determineClearCacheActions($status, $updatedFields) { 00386 $actions = array(); 00387 00388 if ($status == 'new') { 00389 // new page 00390 $actions['allParents'] = true; 00391 } elseif ($status == 'update') { 00392 $updatedFieldNames = array_keys($updatedFields); 00393 00394 foreach ($updatedFieldNames as $updatedFieldName) { 00395 switch ($updatedFieldName) { 00396 case 'pid': 00397 // page moved 00398 case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['disabled']: 00399 // page hidden / unhidden 00400 case $GLOBALS['TCA']['pages']['ctrl']['delete']: 00401 // page deleted / undeleted 00402 case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['starttime']: 00403 /* 00404 start time set/unset 00405 Doesn't matter whether it was set or unset, in both 00406 cases the cache needs to be cleared. When setting a 00407 start time the page must be removed from the 00408 treelist. When unsetting the start time it must 00409 become listed in the tree list again. 00410 */ 00411 case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['fe_group']: 00412 // changes to FE user group 00413 case 'extendToSubpages': 00414 // extendToSubpages set (apply FE access restrictions to subpages) 00415 case 'php_tree_stop': 00416 // php_tree_stop 00417 $actions['allParents'] = TRUE; 00418 $actions['uidInTreelist'] = true; 00419 break; 00420 case $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['endtime']: 00421 /* 00422 end time set/unset 00423 When setting an end time the cache entry needs an 00424 expiration time. When unsetting the end time the 00425 page must become listed in the treelist again. 00426 */ 00427 if($updatedFields['endtime'] > 0) { 00428 $actions['setExpiration'] = true; 00429 } else { 00430 $actions['uidInTreelist'] = true; 00431 } 00432 break; 00433 default: 00434 if (in_array($updatedFieldName, $this->updateRequiringFields)) { 00435 $actions['uidInTreelist'] = true; 00436 } 00437 } 00438 } 00439 } 00440 00441 return $actions; 00442 } 00443 00444 } 00445 00446 00447 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/hooks/class.tx_cms_treelistcacheupdate.php'])) { 00448 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/hooks/class.tx_cms_treelistcacheupdate.php']); 00449 } 00450 00451 ?>
1.8.0