xref: /plugin/combo/ComboStrap/CacheManager.php (revision c3437056399326d621a01da73b649707fbb0ae69)
1<?php
2
3
4namespace ComboStrap;
5
6
7use dokuwiki\Cache\CacheParser;
8
9class CacheManager
10{
11
12    const RESULT_STATUS = 'result';
13    const DATE_MODIFIED = 'ftime';
14    public const APPLICATION_COMBO_CACHE_JSON = "application/combo+cache+json";
15
16    /**
17     * @var CacheManager
18     */
19    private static $cacheManager;
20
21    /**
22     * Just an utility variable to tracks the cache result of each slot
23     * @var array the processed slot by:
24     *   * requested page id, (to avoid inconsistency  on multiple page run in one test)
25     *   * slot id
26     */
27    private $cacheResults = array();
28
29
30    /**
31     * @return CacheManager
32     */
33    public static function getOrCreate(): CacheManager
34    {
35        if (self::$cacheManager === null) {
36            self::$cacheManager = new CacheManager();
37        }
38        return self::$cacheManager;
39    }
40
41
42    /**
43     * In test, we may run more than once
44     * This function delete the cache manager
45     * and is called when Dokuwiki close (ie {@link \action_plugin_combo_cache::close()})
46     */
47    public static function reset()
48    {
49
50        self::$cacheManager = null;
51
52    }
53
54    /**
55     * Keep track of the parsed slot (ie page in page)
56     * @param $slotId
57     * @param $result
58     * @param CacheParser $cacheParser
59     */
60    public function addSlotForRequestedPage($slotId, $result, CacheParser $cacheParser)
61    {
62
63        $requestedPageSlotResults = &$this->getCacheSlotResultsForRequestedPage();
64
65
66        if (!isset($requestedPageSlotResults[$slotId])) {
67            $requestedPageSlotResults[$slotId] = [];
68        }
69
70        /**
71         * Metadata and other rendering may occurs
72         * recursively in one request
73         *
74         * We record only the first one because the second call one will use the first
75         * one
76         */
77        if (!isset($requestedPageSlotResults[$slotId][$cacheParser->mode])) {
78            $date = null;
79            if (file_exists($cacheParser->cache)) {
80                $date = Iso8601Date::createFromTimestamp(filemtime($cacheParser->cache))->getDateTime();
81            }
82            $requestedPageSlotResults[$slotId][$cacheParser->mode] = [
83                self::RESULT_STATUS => $result,
84                self::DATE_MODIFIED => $date
85            ];
86        }
87
88    }
89
90    public function getXhtmlCacheSlotResultsForRequestedPage(): array
91    {
92        $cacheSlotResultsForRequestedPage = $this->getCacheSlotResultsForRequestedPage();
93        if ($cacheSlotResultsForRequestedPage === null) {
94            return [];
95        }
96        $xhtmlRenderResult = [];
97        foreach ($cacheSlotResultsForRequestedPage as $slotId => $modes) {
98            foreach ($modes as $mode => $values) {
99                if ($mode === "xhtml") {
100                    $xhtmlRenderResult[$slotId] = $values[self::RESULT_STATUS];
101                }
102            }
103        }
104        return $xhtmlRenderResult;
105    }
106
107    private function &getCacheSlotResultsForRequestedPage(): ?array
108    {
109        $requestedPage = $this->getRequestedPage();
110        $requestedPageSlotResults = &$this->cacheResults[$requestedPage];
111        if (!isset($requestedPageSlotResults)) {
112            $requestedPageSlotResults = [];
113        }
114        return $requestedPageSlotResults;
115    }
116
117    public function isCacheLogPresentForSlot($slotId, $mode): bool
118    {
119        $cacheSlotResultsForRequestedPage = $this->getCacheSlotResultsForRequestedPage();
120        return isset($cacheSlotResultsForRequestedPage[$slotId][$mode]);
121    }
122
123
124    /**
125     * @return array - a array that will be transformed as json HTML data block
126     * to be included in a HTML page
127     */
128    public function getCacheSlotResultsAsHtmlDataBlockArray(): array
129    {
130        $htmlDataBlock = [];
131        $cacheSlotResultsForRequestedPage = $this->getCacheSlotResultsForRequestedPage();
132        if ($cacheSlotResultsForRequestedPage === null) {
133            LogUtility::msg("No page slot results were found");
134            return [];
135        }
136        foreach ($cacheSlotResultsForRequestedPage as $pageId => $resultByFormat) {
137            foreach ($resultByFormat as $format => $result) {
138                $modifiedDate = $result[self::DATE_MODIFIED];
139                if ($modifiedDate !== null) {
140                    $modifiedDate = Iso8601Date::createFromDateTime($modifiedDate)->toString();
141                }
142                $htmlDataBlock[$pageId][$format] = [
143                    self::RESULT_STATUS => $result[self::RESULT_STATUS],
144                    "mtime" => $modifiedDate
145                ];
146            }
147
148        }
149        return $htmlDataBlock;
150    }
151
152    private function getRequestedPage()
153    {
154        global $_REQUEST;
155        $requestedPage = $_REQUEST[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE];
156
157        if ($requestedPage !== null) {
158            return $requestedPage;
159        }
160
161        /**
162         * We are not on a HTTP request
163         * but may be on a {@link Page::renderMetadataAndFlush() metadata rendering request}
164         */
165        global $ID;
166        if ($ID !== null) {
167            return $ID;
168        }
169
170        if(PluginUtility::isTest()) {
171            /**
172             * {@link p_get_metadata()} check the cache and is used
173             * also in several place such as {@link feed.php}
174             * where we don't have any influence
175             */
176            LogUtility::msg("The requested page should be known to register a page cache result");
177        }
178        return "unknown";
179    }
180
181    public function isEmpty(): bool
182    {
183        return sizeof($this->cacheResults) === 0;
184    }
185
186
187}
188