1<?php 2 3use ComboStrap\CacheDependencies; 4use ComboStrap\CacheExpirationDate; 5use ComboStrap\CacheExpirationFrequency; 6use ComboStrap\CacheLog; 7use ComboStrap\CacheManager; 8use ComboStrap\CacheMedia; 9use ComboStrap\CacheMenuItem; 10use ComboStrap\CacheReportHtmlDataBlockArray; 11use ComboStrap\Cron; 12use ComboStrap\Event; 13use ComboStrap\ExceptionCombo; 14use ComboStrap\FileSystems; 15use ComboStrap\Http; 16use ComboStrap\Iso8601Date; 17use ComboStrap\LogUtility; 18use ComboStrap\Page; 19use ComboStrap\PagePath; 20use ComboStrap\PluginUtility; 21use dokuwiki\Cache\CacheRenderer; 22 23require_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 24 25/** 26 * Can we use the parser cache 27 * 28 * 29 * 30 */ 31class action_plugin_combo_cacheexpiration extends DokuWiki_Action_Plugin 32{ 33 34 35 const CANONICAL = CacheExpirationFrequency::CANONICAL; 36 const SLOT_CACHE_EXPIRATION_EVENT = "slot-cache-expiration"; 37 const REQUESTED_ID = "requested-id"; 38 39 40 /** 41 * @param Doku_Event_Handler $controller 42 */ 43 function register(Doku_Event_Handler $controller) 44 { 45 46 47 /** 48 * Page expiration feature 49 */ 50 $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'slotCreateCacheExpiration', array()); 51 52 53 /** 54 * process the Async event 55 */ 56 $controller->register_hook(self::SLOT_CACHE_EXPIRATION_EVENT, 'AFTER', $this, 'handleSlotCacheExpiration'); 57 58 } 59 60 61 /** 62 * 63 * Purge the cache if needed 64 * @param Doku_Event $event 65 * @param $params 66 */ 67 function slotCreateCacheExpiration(Doku_Event $event, $params) 68 { 69 70 /** 71 * No cache for all mode 72 * (ie xhtml, instruction) 73 */ 74 $data = &$event->data; 75 $pageId = $data->page; 76 77 /** 78 * For whatever reason, the cache file of XHTML 79 * may be empty - No error found on the web server or the log. 80 * 81 * We just delete it then. 82 * 83 * It has been seen after the creation of a new page or a `move` of the page. 84 */ 85 if ($data instanceof CacheRenderer) { 86 if ($data->mode === "xhtml") { 87 if (file_exists($data->cache)) { 88 if (filesize($data->cache) === 0) { 89 $data->depends["purge"] = true; 90 return; 91 } 92 } 93 } 94 } 95 96 $cacheManager = PluginUtility::getCacheManager(); 97 try { 98 $shouldSlotExpire = $cacheManager->shouldSlotExpire($pageId); 99 } catch (ExceptionCombo $e) { 100 LogUtility::msg("Error while trying to check if the slot ($pageId) should expired. Error: {$e->getMessage()}", self::CANONICAL); 101 return; 102 } 103 if ($shouldSlotExpire) { 104 Event::createEvent( 105 self::SLOT_CACHE_EXPIRATION_EVENT, 106 [ 107 PagePath::getPersistentName() => $pageId, 108 self::REQUESTED_ID => PluginUtility::getRequestedWikiId() 109 ] 110 ); 111 } 112 113 114 } 115 116 public function handleSlotCacheExpiration($event) 117 { 118 $data = $event->data; 119 $slotPath = $data[PagePath::getPersistentName()]; 120 $requestedId = $data[self::REQUESTED_ID]; 121 122 /** 123 * The cache file may be dependent on the requested id 124 * ie (@link CacheDependencies::OUTPUT_DEPENDENCIES} 125 */ 126 global $ID; 127 $keep = $ID; 128 try { 129 $ID = $requestedId; 130 $slot = Page::createPageFromQualifiedPath($slotPath); 131 132 /** 133 * Calculate a new expiration date 134 * And set it here because setting a new metadata 135 * will make the cache unusable 136 */ 137 $cacheExpirationDateMeta = CacheExpirationDate::createForPage($slot); 138 $actualDate = $cacheExpirationDateMeta->getValue(); 139 $cacheExpirationFrequency = CacheExpirationFrequency::createForPage($slot) 140 ->getValue(); 141 try { 142 $newDate = Cron::getDate($cacheExpirationFrequency); 143 } catch (ExceptionCombo $e) { 144 LogUtility::msg("Error while calculating the new expiration date. Error: {$e->getMessage()}"); 145 return; 146 } 147 if ($newDate < $actualDate) { 148 LogUtility::msg("The new calculated date cache expiration frequency ({$newDate->format(Iso8601Date::getFormat())}) is lower than the current date ({$actualDate->format(Iso8601Date::getFormat())})"); 149 } 150 try { 151 $cacheExpirationDateMeta 152 ->setValue($newDate) 153 ->persist(); 154 } catch (ExceptionCombo $e) { 155 LogUtility::msg("Error while persisting the new expiration date. Error:{$e->getMessage()}"); 156 return; 157 } 158 159 /** 160 * Cache deletion 161 */ 162 $message = "Expiration Date has expired"; 163 CacheLog::deleteCacheIfExistsAndLog( 164 $slot->getInstructionsDocument(), 165 self::SLOT_CACHE_EXPIRATION_EVENT, 166 $message); 167 CacheLog::deleteCacheIfExistsAndLog( 168 $slot->getHtmlDocument(), 169 self::SLOT_CACHE_EXPIRATION_EVENT, 170 $message); 171 172 /** 173 * Re-render 174 */ 175 CacheLog::renderCacheAndLog( 176 $slot->getHtmlDocument(), 177 self::SLOT_CACHE_EXPIRATION_EVENT, 178 $message); 179 180 } finally { 181 $ID = $keep; 182 } 183 184 } 185 186 187} 188