xref: /template/strap/ComboStrap/CacheManager.php (revision 4cadd4f8c541149bdda95f080e38a6d4e3a640ca)
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