1<?php 2 3 4namespace ComboStrap; 5 6 7use DateTime; 8 9/** 10 * Class CacheManager 11 * @package ComboStrap 12 * 13 * The cache manager is public static object 14 * that can be used by plugin to report cache dependency {@link CacheManager::addDependencyForCurrentSlot()} 15 * reports and influence the cache 16 * of all slot for a requested page 17 */ 18class CacheManager 19{ 20 21 22 const CACHE_DELETION = "deletion"; 23 const CACHE_CREATION = "creation"; 24 25 26 /** 27 * @var CacheManager 28 */ 29 private static $cacheManager; 30 31 32 /** 33 * The list of cache runtimes dependencies by slot {@link CacheDependencies} 34 */ 35 private $slotCacheDependencies; 36 /** 37 * The list of cache results slot {@link CacheResults} 38 */ 39 private $slotCacheResults; 40 41 /** 42 * @var array hold the result for slot cache expiration 43 */ 44 private $slotsExpiration; 45 46 47 /** 48 * @return CacheManager 49 */ 50 public static function getOrCreate(): CacheManager 51 { 52 try { 53 $page = Page::createPageFromRequestedPage(); 54 $cacheKey = $page->getDokuwikiId(); 55 } catch (ExceptionCombo $e) { 56 /** 57 * In test, we may generate html from snippet without 58 * request. No error in this case 59 */ 60 if (!PluginUtility::isTest()) { 61 LogUtility::msg("The cache manager cannot find the requested page. Cache Errors may occurs. Error: {$e->getMessage()}"); 62 } 63 $cacheKey = PluginUtility::getRequestId(); 64 } 65 $cacheManager = self::$cacheManager[$cacheKey]; 66 if ($cacheManager === null) { 67 // new run, delete all old cache managers 68 self::$cacheManager = []; 69 // create 70 $cacheManager = new CacheManager(); 71 self::$cacheManager[$cacheKey] = $cacheManager; 72 } 73 return $cacheManager; 74 } 75 76 77 public static function resetAndGet(): CacheManager 78 { 79 self::reset(); 80 return self::getOrCreate(); 81 } 82 83 /** 84 * @param $id 85 * @return CacheDependencies 86 */ 87 public function getCacheDependenciesForSlot($id): CacheDependencies 88 { 89 90 $cacheRuntimeDependencies = $this->slotCacheDependencies[$id]; 91 if ($cacheRuntimeDependencies === null) { 92 $cacheRuntimeDependencies = new CacheDependencies($id); 93 $this->slotCacheDependencies[$id] = $cacheRuntimeDependencies; 94 } 95 return $cacheRuntimeDependencies; 96 97 } 98 99 /** 100 * In test, we may run more than once 101 * This function delete the cache manager 102 * and is called 103 * when a new request is created {@link \TestUtility::createTestRequest()} 104 */ 105 public static function reset() 106 { 107 108 self::$cacheManager = null; 109 110 } 111 112 113 public function isCacheResultPresentForSlot($slotId, $mode): bool 114 { 115 $cacheReporter = $this->getCacheResultsForSlot($slotId); 116 return $cacheReporter->hasResultForMode($mode); 117 } 118 119 120 public function hasNoCacheResult(): bool 121 { 122 if($this->slotCacheResults===null){ 123 return true; 124 } 125 return sizeof($this->slotCacheResults) === 0; 126 } 127 128 /** 129 * @param string $dependencyName 130 * @return CacheManager 131 */ 132 public function addDependencyForCurrentSlot(string $dependencyName): CacheManager 133 { 134 $ID = PluginUtility::getCurrentSlotId(); 135 $cacheDependencies = $this->getCacheDependenciesForSlot($ID); 136 $cacheDependencies->addDependency($dependencyName); 137 return $this; 138 139 } 140 141 142 public function getCacheResultsForSlot(string $id): CacheResults 143 { 144 $cacheManagerForSlot = $this->slotCacheResults[$id]; 145 if ($cacheManagerForSlot === null) { 146 $cacheManagerForSlot = new CacheResults($id); 147 $this->slotCacheResults[$id] = $cacheManagerForSlot; 148 } 149 return $cacheManagerForSlot; 150 } 151 152 /** 153 * @return null|CacheResults[] - null if the page does not exists 154 */ 155 public function getCacheResults(): ?array 156 { 157 return $this->slotCacheResults; 158 } 159 160 /** 161 * @throws ExceptionCombo 162 */ 163 public function shouldSlotExpire($pageId): bool 164 { 165 166 /** 167 * Because of the recursive nature of rendering 168 * inside dokuwiki, we just return a result for 169 * the first call to the function 170 * 171 * We use the cache manager as scope element 172 * (ie it's {@link CacheManager::reset()} for each request 173 */ 174 if (isset($this->slotsExpiration[$pageId])) { 175 return false; 176 } 177 178 $page = Page::createPageFromId($pageId); 179 $cacheExpirationFrequency = CacheExpirationFrequency::createForPage($page) 180 ->getValue(); 181 if ($cacheExpirationFrequency === null) { 182 $this->slotsExpiration[$pageId] = false; 183 return false; 184 } 185 186 $cacheExpirationDateMeta = CacheExpirationDate::createForPage($page); 187 $expirationDate = $cacheExpirationDateMeta->getValue(); 188 189 if ($expirationDate === null) { 190 191 $expirationDate = Cron::getDate($cacheExpirationFrequency); 192 $cacheExpirationDateMeta->setValue($expirationDate); 193 194 } 195 196 197 $actualDate = new DateTime(); 198 if ($expirationDate > $actualDate) { 199 $this->slotsExpiration[$pageId] = false; 200 return false; 201 } 202 203 $this->slotsExpiration[$pageId] = true; 204 return true; 205 206 } 207 208} 209