137748cd8SNickeau<?php 237748cd8SNickeau 337748cd8SNickeau 437748cd8SNickeaunamespace ComboStrap; 537748cd8SNickeau 637748cd8SNickeau 7*4cadd4f8SNickeauuse DateTime; 837748cd8SNickeau 9*4cadd4f8SNickeau/** 10*4cadd4f8SNickeau * Class CacheManager 11*4cadd4f8SNickeau * @package ComboStrap 12*4cadd4f8SNickeau * 13*4cadd4f8SNickeau * The cache manager is public static object 14*4cadd4f8SNickeau * that can be used by plugin to report cache dependency {@link CacheManager::addDependencyForCurrentSlot()} 15*4cadd4f8SNickeau * reports and influence the cache 16*4cadd4f8SNickeau * of all slot for a requested page 17*4cadd4f8SNickeau */ 1837748cd8SNickeauclass CacheManager 1937748cd8SNickeau{ 2037748cd8SNickeau 21*4cadd4f8SNickeau 22*4cadd4f8SNickeau const CACHE_DELETION = "deletion"; 23*4cadd4f8SNickeau const CACHE_CREATION = "creation"; 24*4cadd4f8SNickeau 2537748cd8SNickeau 2637748cd8SNickeau /** 27c3437056SNickeau * @var CacheManager 2837748cd8SNickeau */ 29c3437056SNickeau private static $cacheManager; 30c3437056SNickeau 31*4cadd4f8SNickeau 32c3437056SNickeau /** 33*4cadd4f8SNickeau * The list of cache runtimes dependencies by slot {@link CacheDependencies} 34c3437056SNickeau */ 35*4cadd4f8SNickeau private $slotCacheDependencies; 36*4cadd4f8SNickeau /** 37*4cadd4f8SNickeau * The list of cache results slot {@link CacheResults} 38*4cadd4f8SNickeau */ 39*4cadd4f8SNickeau private $slotCacheResults; 40*4cadd4f8SNickeau 41*4cadd4f8SNickeau /** 42*4cadd4f8SNickeau * @var array hold the result for slot cache expiration 43*4cadd4f8SNickeau */ 44*4cadd4f8SNickeau private $slotsExpiration; 4537748cd8SNickeau 4637748cd8SNickeau 4737748cd8SNickeau /** 4837748cd8SNickeau * @return CacheManager 4937748cd8SNickeau */ 50c3437056SNickeau public static function getOrCreate(): CacheManager 5137748cd8SNickeau { 52*4cadd4f8SNickeau try { 53*4cadd4f8SNickeau $page = Page::createPageFromRequestedPage(); 54*4cadd4f8SNickeau $cacheKey = $page->getDokuwikiId(); 55*4cadd4f8SNickeau } catch (ExceptionCombo $e) { 56*4cadd4f8SNickeau /** 57*4cadd4f8SNickeau * In test, we may generate html from snippet without 58*4cadd4f8SNickeau * request. No error in this case 59*4cadd4f8SNickeau */ 60*4cadd4f8SNickeau if (!PluginUtility::isTest()) { 61*4cadd4f8SNickeau LogUtility::msg("The cache manager cannot find the requested page. Cache Errors may occurs. Error: {$e->getMessage()}"); 6237748cd8SNickeau } 63*4cadd4f8SNickeau $cacheKey = PluginUtility::getRequestId(); 64*4cadd4f8SNickeau } 65*4cadd4f8SNickeau $cacheManager = self::$cacheManager[$cacheKey]; 66*4cadd4f8SNickeau if ($cacheManager === null) { 67*4cadd4f8SNickeau // new run, delete all old cache managers 68*4cadd4f8SNickeau self::$cacheManager = []; 69*4cadd4f8SNickeau // create 70*4cadd4f8SNickeau $cacheManager = new CacheManager(); 71*4cadd4f8SNickeau self::$cacheManager[$cacheKey] = $cacheManager; 72*4cadd4f8SNickeau } 73*4cadd4f8SNickeau return $cacheManager; 7437748cd8SNickeau } 7537748cd8SNickeau 7637748cd8SNickeau 77*4cadd4f8SNickeau public static function resetAndGet(): CacheManager 78*4cadd4f8SNickeau { 79*4cadd4f8SNickeau self::reset(); 80*4cadd4f8SNickeau return self::getOrCreate(); 81*4cadd4f8SNickeau } 82*4cadd4f8SNickeau 83*4cadd4f8SNickeau /** 84*4cadd4f8SNickeau * @param $id 85*4cadd4f8SNickeau * @return CacheDependencies 86*4cadd4f8SNickeau */ 87*4cadd4f8SNickeau public function getCacheDependenciesForSlot($id): CacheDependencies 88*4cadd4f8SNickeau { 89*4cadd4f8SNickeau 90*4cadd4f8SNickeau $cacheRuntimeDependencies = $this->slotCacheDependencies[$id]; 91*4cadd4f8SNickeau if ($cacheRuntimeDependencies === null) { 92*4cadd4f8SNickeau $cacheRuntimeDependencies = new CacheDependencies($id); 93*4cadd4f8SNickeau $this->slotCacheDependencies[$id] = $cacheRuntimeDependencies; 94*4cadd4f8SNickeau } 95*4cadd4f8SNickeau return $cacheRuntimeDependencies; 96*4cadd4f8SNickeau 97*4cadd4f8SNickeau } 98*4cadd4f8SNickeau 9937748cd8SNickeau /** 10037748cd8SNickeau * In test, we may run more than once 10137748cd8SNickeau * This function delete the cache manager 102*4cadd4f8SNickeau * and is called 103*4cadd4f8SNickeau * when a new request is created {@link \TestUtility::createTestRequest()} 10437748cd8SNickeau */ 105c3437056SNickeau public static function reset() 10637748cd8SNickeau { 10737748cd8SNickeau 108c3437056SNickeau self::$cacheManager = null; 10937748cd8SNickeau 11037748cd8SNickeau } 11137748cd8SNickeau 112*4cadd4f8SNickeau 113*4cadd4f8SNickeau public function isCacheResultPresentForSlot($slotId, $mode): bool 11437748cd8SNickeau { 115*4cadd4f8SNickeau $cacheReporter = $this->getCacheResultsForSlot($slotId); 116*4cadd4f8SNickeau return $cacheReporter->hasResultForMode($mode); 117*4cadd4f8SNickeau } 118c3437056SNickeau 119c3437056SNickeau 120*4cadd4f8SNickeau public function hasNoCacheResult(): bool 121*4cadd4f8SNickeau { 122*4cadd4f8SNickeau if($this->slotCacheResults===null){ 123*4cadd4f8SNickeau return true; 124*4cadd4f8SNickeau } 125*4cadd4f8SNickeau return sizeof($this->slotCacheResults) === 0; 12637748cd8SNickeau } 127c3437056SNickeau 12837748cd8SNickeau /** 129*4cadd4f8SNickeau * @param string $dependencyName 130*4cadd4f8SNickeau * @return CacheManager 131*4cadd4f8SNickeau */ 132*4cadd4f8SNickeau public function addDependencyForCurrentSlot(string $dependencyName): CacheManager 133*4cadd4f8SNickeau { 134*4cadd4f8SNickeau $ID = PluginUtility::getCurrentSlotId(); 135*4cadd4f8SNickeau $cacheDependencies = $this->getCacheDependenciesForSlot($ID); 136*4cadd4f8SNickeau $cacheDependencies->addDependency($dependencyName); 137*4cadd4f8SNickeau return $this; 138*4cadd4f8SNickeau 139*4cadd4f8SNickeau } 140*4cadd4f8SNickeau 141*4cadd4f8SNickeau 142*4cadd4f8SNickeau public function getCacheResultsForSlot(string $id): CacheResults 143*4cadd4f8SNickeau { 144*4cadd4f8SNickeau $cacheManagerForSlot = $this->slotCacheResults[$id]; 145*4cadd4f8SNickeau if ($cacheManagerForSlot === null) { 146*4cadd4f8SNickeau $cacheManagerForSlot = new CacheResults($id); 147*4cadd4f8SNickeau $this->slotCacheResults[$id] = $cacheManagerForSlot; 148*4cadd4f8SNickeau } 149*4cadd4f8SNickeau return $cacheManagerForSlot; 150*4cadd4f8SNickeau } 151*4cadd4f8SNickeau 152*4cadd4f8SNickeau /** 153*4cadd4f8SNickeau * @return null|CacheResults[] - null if the page does not exists 154*4cadd4f8SNickeau */ 155*4cadd4f8SNickeau public function getCacheResults(): ?array 156*4cadd4f8SNickeau { 157*4cadd4f8SNickeau return $this->slotCacheResults; 158*4cadd4f8SNickeau } 159*4cadd4f8SNickeau 160*4cadd4f8SNickeau /** 161*4cadd4f8SNickeau * @throws ExceptionCombo 162*4cadd4f8SNickeau */ 163*4cadd4f8SNickeau public function shouldSlotExpire($pageId): bool 164*4cadd4f8SNickeau { 165*4cadd4f8SNickeau 166*4cadd4f8SNickeau /** 167*4cadd4f8SNickeau * Because of the recursive nature of rendering 168*4cadd4f8SNickeau * inside dokuwiki, we just return a result for 169*4cadd4f8SNickeau * the first call to the function 17037748cd8SNickeau * 171*4cadd4f8SNickeau * We use the cache manager as scope element 172*4cadd4f8SNickeau * (ie it's {@link CacheManager::reset()} for each request 17337748cd8SNickeau */ 174*4cadd4f8SNickeau if (isset($this->slotsExpiration[$pageId])) { 175*4cadd4f8SNickeau return false; 17637748cd8SNickeau } 177*4cadd4f8SNickeau 178*4cadd4f8SNickeau $page = Page::createPageFromId($pageId); 179*4cadd4f8SNickeau $cacheExpirationFrequency = CacheExpirationFrequency::createForPage($page) 180*4cadd4f8SNickeau ->getValue(); 181*4cadd4f8SNickeau if ($cacheExpirationFrequency === null) { 182*4cadd4f8SNickeau $this->slotsExpiration[$pageId] = false; 183*4cadd4f8SNickeau return false; 18437748cd8SNickeau } 18537748cd8SNickeau 186*4cadd4f8SNickeau $cacheExpirationDateMeta = CacheExpirationDate::createForPage($page); 187*4cadd4f8SNickeau $expirationDate = $cacheExpirationDateMeta->getValue(); 188*4cadd4f8SNickeau 189*4cadd4f8SNickeau if ($expirationDate === null) { 190*4cadd4f8SNickeau 191*4cadd4f8SNickeau $expirationDate = Cron::getDate($cacheExpirationFrequency); 192*4cadd4f8SNickeau $cacheExpirationDateMeta->setValue($expirationDate); 193*4cadd4f8SNickeau 19437748cd8SNickeau } 19537748cd8SNickeau 196*4cadd4f8SNickeau 197*4cadd4f8SNickeau $actualDate = new DateTime(); 198*4cadd4f8SNickeau if ($expirationDate > $actualDate) { 199*4cadd4f8SNickeau $this->slotsExpiration[$pageId] = false; 200*4cadd4f8SNickeau return false; 20137748cd8SNickeau } 20237748cd8SNickeau 203*4cadd4f8SNickeau $this->slotsExpiration[$pageId] = true; 204*4cadd4f8SNickeau return true; 205c3437056SNickeau 206c3437056SNickeau } 20737748cd8SNickeau 20837748cd8SNickeau} 209