1<?php
2
3
4namespace ComboStrap;
5
6
7use DateTime;
8
9/**
10 * Class CacheManager
11 * @package ComboStrap
12 *
13 * The cache manager handles all things cache
14 * This is just another namespace extension of {@link ExecutionContext}
15 * to not have all function in the same place
16 *
17 * Except for the cache dependencies of a {@link FetcherMarkup::getOutputCacheDependencies() Markup}
18 */
19class CacheManager
20{
21
22
23    const CACHE_DELETION = "deletion";
24    const CACHE_CREATION = "creation";
25
26
27    /**
28     * The list of cache runtimes dependencies by slot {@link MarkupCacheDependencies}
29     */
30    private array $slotCacheDependencies = [];
31
32    /**
33     * The list of cache results slot {@link CacheResults}
34     */
35    private array $slotCacheResults = [];
36
37    /**
38     * @var array hold the result for slot cache expiration
39     */
40    private array $slotsExpiration = [];
41
42
43    private ExecutionContext $executionContext;
44
45    public function __construct(ExecutionContext $executionContext)
46    {
47        $this->executionContext = $executionContext;
48    }
49
50
51    /**
52     * @return CacheManager
53     * @deprecated use the {@link ExecutionContext::getCacheManager()} instead otherwise you may mix context run
54     */
55    public static function getFromContextExecution(): CacheManager
56    {
57
58        return ExecutionContext::getActualOrCreateFromEnv()->getCacheManager();
59
60    }
61
62
63
64    public function &getCacheResultsForSlot(string $id): CacheResults
65    {
66        $cacheManagerForSlot = &$this->slotCacheResults[$id];
67        if ($cacheManagerForSlot === null) {
68            $cacheManagerForSlot = new CacheResults($id);
69            $this->slotCacheResults[$id] = $cacheManagerForSlot;
70        }
71        return $cacheManagerForSlot;
72    }
73
74    /**
75     * @return CacheResults[] - null if the page does not exists
76     */
77    public function getCacheResults(): array
78    {
79        return $this->slotCacheResults;
80    }
81
82    /**
83     */
84    public function shouldSlotExpire($pageId): bool
85    {
86
87        /**
88         * Because of the recursive nature of rendering
89         * inside dokuwiki, we just return a result for
90         * the first call to the function
91         *
92         */
93        if (isset($this->slotsExpiration[$pageId])) {
94            return false;
95        }
96
97        $page = MarkupPath::createMarkupFromId($pageId);
98        try {
99            $cacheExpirationFrequency = CacheExpirationFrequency::createForPage($page)
100                ->getValue();
101        } catch (ExceptionNotFound $e) {
102            $this->slotsExpiration[$pageId] = false;
103            return false;
104        }
105
106        $cacheExpirationDateMeta = CacheExpirationDate::createForPage($page);
107        try {
108            $expirationDate = $cacheExpirationDateMeta->getValue();
109        } catch (ExceptionNotFound $e) {
110            try {
111                $expirationDate = Cron::getDate($cacheExpirationFrequency);
112            } catch (ExceptionBadSyntax $e) {
113                LogUtility::error("The cron expression ($cacheExpirationFrequency) of the page ($page) is not a valid cron expression");
114                return false;
115            }
116        }
117        $cacheExpirationDateMeta->setValue($expirationDate);
118
119        $actualDate = new DateTime();
120        if ($expirationDate > $actualDate) {
121            $this->slotsExpiration[$pageId] = false;
122            return false;
123        }
124
125        $this->slotsExpiration[$pageId] = true;
126        return true;
127
128    }
129
130}
131