xref: /template/strap/action/cacheexpiration.php (revision 4cadd4f8c541149bdda95f080e38a6d4e3a640ca)
1*4cadd4f8SNickeau<?php
2*4cadd4f8SNickeau
3*4cadd4f8SNickeauuse ComboStrap\CacheDependencies;
4*4cadd4f8SNickeauuse ComboStrap\CacheExpirationDate;
5*4cadd4f8SNickeauuse ComboStrap\CacheExpirationFrequency;
6*4cadd4f8SNickeauuse ComboStrap\CacheLog;
7*4cadd4f8SNickeauuse ComboStrap\CacheManager;
8*4cadd4f8SNickeauuse ComboStrap\CacheMedia;
9*4cadd4f8SNickeauuse ComboStrap\CacheMenuItem;
10*4cadd4f8SNickeauuse ComboStrap\CacheReportHtmlDataBlockArray;
11*4cadd4f8SNickeauuse ComboStrap\Cron;
12*4cadd4f8SNickeauuse ComboStrap\Event;
13*4cadd4f8SNickeauuse ComboStrap\ExceptionCombo;
14*4cadd4f8SNickeauuse ComboStrap\FileSystems;
15*4cadd4f8SNickeauuse ComboStrap\Http;
16*4cadd4f8SNickeauuse ComboStrap\Iso8601Date;
17*4cadd4f8SNickeauuse ComboStrap\LogUtility;
18*4cadd4f8SNickeauuse ComboStrap\Page;
19*4cadd4f8SNickeauuse ComboStrap\PagePath;
20*4cadd4f8SNickeauuse ComboStrap\PluginUtility;
21*4cadd4f8SNickeauuse dokuwiki\Cache\CacheRenderer;
22*4cadd4f8SNickeau
23*4cadd4f8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
24*4cadd4f8SNickeau
25*4cadd4f8SNickeau/**
26*4cadd4f8SNickeau * Can we use the parser cache
27*4cadd4f8SNickeau *
28*4cadd4f8SNickeau *
29*4cadd4f8SNickeau *
30*4cadd4f8SNickeau */
31*4cadd4f8SNickeauclass action_plugin_combo_cacheexpiration extends DokuWiki_Action_Plugin
32*4cadd4f8SNickeau{
33*4cadd4f8SNickeau
34*4cadd4f8SNickeau
35*4cadd4f8SNickeau    const CANONICAL = CacheExpirationFrequency::CANONICAL;
36*4cadd4f8SNickeau    const SLOT_CACHE_EXPIRATION_EVENT = "slot-cache-expiration";
37*4cadd4f8SNickeau    const REQUESTED_ID = "requested-id";
38*4cadd4f8SNickeau
39*4cadd4f8SNickeau
40*4cadd4f8SNickeau    /**
41*4cadd4f8SNickeau     * @param Doku_Event_Handler $controller
42*4cadd4f8SNickeau     */
43*4cadd4f8SNickeau    function register(Doku_Event_Handler $controller)
44*4cadd4f8SNickeau    {
45*4cadd4f8SNickeau
46*4cadd4f8SNickeau
47*4cadd4f8SNickeau        /**
48*4cadd4f8SNickeau         * Page expiration feature
49*4cadd4f8SNickeau         */
50*4cadd4f8SNickeau        $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'slotCreateCacheExpiration', array());
51*4cadd4f8SNickeau
52*4cadd4f8SNickeau
53*4cadd4f8SNickeau        /**
54*4cadd4f8SNickeau         * process the Async event
55*4cadd4f8SNickeau         */
56*4cadd4f8SNickeau        $controller->register_hook(self::SLOT_CACHE_EXPIRATION_EVENT, 'AFTER', $this, 'handleSlotCacheExpiration');
57*4cadd4f8SNickeau
58*4cadd4f8SNickeau    }
59*4cadd4f8SNickeau
60*4cadd4f8SNickeau
61*4cadd4f8SNickeau    /**
62*4cadd4f8SNickeau     *
63*4cadd4f8SNickeau     * Purge the cache if needed
64*4cadd4f8SNickeau     * @param Doku_Event $event
65*4cadd4f8SNickeau     * @param $params
66*4cadd4f8SNickeau     */
67*4cadd4f8SNickeau    function slotCreateCacheExpiration(Doku_Event $event, $params)
68*4cadd4f8SNickeau    {
69*4cadd4f8SNickeau
70*4cadd4f8SNickeau        /**
71*4cadd4f8SNickeau         * No cache for all mode
72*4cadd4f8SNickeau         * (ie xhtml, instruction)
73*4cadd4f8SNickeau         */
74*4cadd4f8SNickeau        $data = &$event->data;
75*4cadd4f8SNickeau        $pageId = $data->page;
76*4cadd4f8SNickeau
77*4cadd4f8SNickeau        /**
78*4cadd4f8SNickeau         * For whatever reason, the cache file of XHTML
79*4cadd4f8SNickeau         * may be empty - No error found on the web server or the log.
80*4cadd4f8SNickeau         *
81*4cadd4f8SNickeau         * We just delete it then.
82*4cadd4f8SNickeau         *
83*4cadd4f8SNickeau         * It has been seen after the creation of a new page or a `move` of the page.
84*4cadd4f8SNickeau         */
85*4cadd4f8SNickeau        if ($data instanceof CacheRenderer) {
86*4cadd4f8SNickeau            if ($data->mode === "xhtml") {
87*4cadd4f8SNickeau                if (file_exists($data->cache)) {
88*4cadd4f8SNickeau                    if (filesize($data->cache) === 0) {
89*4cadd4f8SNickeau                        $data->depends["purge"] = true;
90*4cadd4f8SNickeau                        return;
91*4cadd4f8SNickeau                    }
92*4cadd4f8SNickeau                }
93*4cadd4f8SNickeau            }
94*4cadd4f8SNickeau        }
95*4cadd4f8SNickeau
96*4cadd4f8SNickeau        $cacheManager = PluginUtility::getCacheManager();
97*4cadd4f8SNickeau        try {
98*4cadd4f8SNickeau            $shouldSlotExpire = $cacheManager->shouldSlotExpire($pageId);
99*4cadd4f8SNickeau        } catch (ExceptionCombo $e) {
100*4cadd4f8SNickeau            LogUtility::msg("Error while trying to check if the slot ($pageId) should expired. Error: {$e->getMessage()}", self::CANONICAL);
101*4cadd4f8SNickeau            return;
102*4cadd4f8SNickeau        }
103*4cadd4f8SNickeau        if ($shouldSlotExpire) {
104*4cadd4f8SNickeau            Event::createEvent(
105*4cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
106*4cadd4f8SNickeau                [
107*4cadd4f8SNickeau                    PagePath::getPersistentName() => $pageId,
108*4cadd4f8SNickeau                    self::REQUESTED_ID => PluginUtility::getRequestedWikiId()
109*4cadd4f8SNickeau                ]
110*4cadd4f8SNickeau            );
111*4cadd4f8SNickeau        }
112*4cadd4f8SNickeau
113*4cadd4f8SNickeau
114*4cadd4f8SNickeau    }
115*4cadd4f8SNickeau
116*4cadd4f8SNickeau    public function handleSlotCacheExpiration($event)
117*4cadd4f8SNickeau    {
118*4cadd4f8SNickeau        $data = $event->data;
119*4cadd4f8SNickeau        $slotPath = $data[PagePath::getPersistentName()];
120*4cadd4f8SNickeau        $requestedId = $data[self::REQUESTED_ID];
121*4cadd4f8SNickeau
122*4cadd4f8SNickeau        /**
123*4cadd4f8SNickeau         * The cache file may be dependent on the requested id
124*4cadd4f8SNickeau         * ie (@link CacheDependencies::OUTPUT_DEPENDENCIES}
125*4cadd4f8SNickeau         */
126*4cadd4f8SNickeau        global $ID;
127*4cadd4f8SNickeau        $keep = $ID;
128*4cadd4f8SNickeau        try {
129*4cadd4f8SNickeau            $ID = $requestedId;
130*4cadd4f8SNickeau            $slot = Page::createPageFromQualifiedPath($slotPath);
131*4cadd4f8SNickeau
132*4cadd4f8SNickeau            /**
133*4cadd4f8SNickeau             * Calculate a new expiration date
134*4cadd4f8SNickeau             * And set it here because setting a new metadata
135*4cadd4f8SNickeau             * will make the cache unusable
136*4cadd4f8SNickeau             */
137*4cadd4f8SNickeau            $cacheExpirationDateMeta = CacheExpirationDate::createForPage($slot);
138*4cadd4f8SNickeau            $actualDate = $cacheExpirationDateMeta->getValue();
139*4cadd4f8SNickeau            $cacheExpirationFrequency = CacheExpirationFrequency::createForPage($slot)
140*4cadd4f8SNickeau                ->getValue();
141*4cadd4f8SNickeau            try {
142*4cadd4f8SNickeau                $newDate = Cron::getDate($cacheExpirationFrequency);
143*4cadd4f8SNickeau            } catch (ExceptionCombo $e) {
144*4cadd4f8SNickeau                LogUtility::msg("Error while calculating the new expiration date. Error: {$e->getMessage()}");
145*4cadd4f8SNickeau                return;
146*4cadd4f8SNickeau            }
147*4cadd4f8SNickeau            if ($newDate < $actualDate) {
148*4cadd4f8SNickeau                LogUtility::msg("The new calculated date cache expiration frequency ({$newDate->format(Iso8601Date::getFormat())}) is lower than the current date ({$actualDate->format(Iso8601Date::getFormat())})");
149*4cadd4f8SNickeau            }
150*4cadd4f8SNickeau            try {
151*4cadd4f8SNickeau                $cacheExpirationDateMeta
152*4cadd4f8SNickeau                    ->setValue($newDate)
153*4cadd4f8SNickeau                    ->persist();
154*4cadd4f8SNickeau            } catch (ExceptionCombo $e) {
155*4cadd4f8SNickeau                LogUtility::msg("Error while persisting the new expiration date. Error:{$e->getMessage()}");
156*4cadd4f8SNickeau                return;
157*4cadd4f8SNickeau            }
158*4cadd4f8SNickeau
159*4cadd4f8SNickeau            /**
160*4cadd4f8SNickeau             * Cache deletion
161*4cadd4f8SNickeau             */
162*4cadd4f8SNickeau            $message = "Expiration Date has expired";
163*4cadd4f8SNickeau            CacheLog::deleteCacheIfExistsAndLog(
164*4cadd4f8SNickeau                $slot->getInstructionsDocument(),
165*4cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
166*4cadd4f8SNickeau                $message);
167*4cadd4f8SNickeau            CacheLog::deleteCacheIfExistsAndLog(
168*4cadd4f8SNickeau                $slot->getHtmlDocument(),
169*4cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
170*4cadd4f8SNickeau                $message);
171*4cadd4f8SNickeau
172*4cadd4f8SNickeau            /**
173*4cadd4f8SNickeau             * Re-render
174*4cadd4f8SNickeau             */
175*4cadd4f8SNickeau            CacheLog::renderCacheAndLog(
176*4cadd4f8SNickeau                $slot->getHtmlDocument(),
177*4cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
178*4cadd4f8SNickeau                $message);
179*4cadd4f8SNickeau
180*4cadd4f8SNickeau        } finally {
181*4cadd4f8SNickeau            $ID = $keep;
182*4cadd4f8SNickeau        }
183*4cadd4f8SNickeau
184*4cadd4f8SNickeau    }
185*4cadd4f8SNickeau
186*4cadd4f8SNickeau
187*4cadd4f8SNickeau}
188