xref: /template/strap/action/cacheexpiration.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
14cadd4f8SNickeau<?php
24cadd4f8SNickeau
34cadd4f8SNickeauuse ComboStrap\CacheExpirationDate;
44cadd4f8SNickeauuse ComboStrap\CacheExpirationFrequency;
54cadd4f8SNickeauuse ComboStrap\CacheLog;
64cadd4f8SNickeauuse ComboStrap\Cron;
74cadd4f8SNickeauuse ComboStrap\Event;
8*04fd306cSNickeauuse ComboStrap\ExceptionCompile;
9*04fd306cSNickeauuse ComboStrap\ExceptionNotFound;
10*04fd306cSNickeauuse ComboStrap\ExecutionContext;
114cadd4f8SNickeauuse ComboStrap\Iso8601Date;
124cadd4f8SNickeauuse ComboStrap\LogUtility;
13*04fd306cSNickeauuse ComboStrap\MarkupCacheDependencies;
14*04fd306cSNickeauuse ComboStrap\MarkupPath;
154cadd4f8SNickeauuse ComboStrap\PagePath;
164cadd4f8SNickeauuse dokuwiki\Cache\CacheRenderer;
174cadd4f8SNickeau
18*04fd306cSNickeaurequire_once(__DIR__ . '/../vendor/autoload.php');
194cadd4f8SNickeau
204cadd4f8SNickeau/**
214cadd4f8SNickeau * Can we use the parser cache
224cadd4f8SNickeau *
234cadd4f8SNickeau *
244cadd4f8SNickeau *
254cadd4f8SNickeau */
264cadd4f8SNickeauclass action_plugin_combo_cacheexpiration extends DokuWiki_Action_Plugin
274cadd4f8SNickeau{
284cadd4f8SNickeau
294cadd4f8SNickeau
304cadd4f8SNickeau    const CANONICAL = CacheExpirationFrequency::CANONICAL;
314cadd4f8SNickeau    const SLOT_CACHE_EXPIRATION_EVENT = "slot-cache-expiration";
324cadd4f8SNickeau    const REQUESTED_ID = "requested-id";
334cadd4f8SNickeau
344cadd4f8SNickeau
354cadd4f8SNickeau    /**
364cadd4f8SNickeau     * @param Doku_Event_Handler $controller
374cadd4f8SNickeau     */
384cadd4f8SNickeau    function register(Doku_Event_Handler $controller)
394cadd4f8SNickeau    {
404cadd4f8SNickeau
414cadd4f8SNickeau
424cadd4f8SNickeau        /**
434cadd4f8SNickeau         * Page expiration feature
444cadd4f8SNickeau         */
454cadd4f8SNickeau        $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'slotCreateCacheExpiration', array());
464cadd4f8SNickeau
474cadd4f8SNickeau
484cadd4f8SNickeau        /**
49*04fd306cSNickeau         * Process the Async event
504cadd4f8SNickeau         */
514cadd4f8SNickeau        $controller->register_hook(self::SLOT_CACHE_EXPIRATION_EVENT, 'AFTER', $this, 'handleSlotCacheExpiration');
524cadd4f8SNickeau
534cadd4f8SNickeau    }
544cadd4f8SNickeau
554cadd4f8SNickeau
564cadd4f8SNickeau    /**
574cadd4f8SNickeau     *
584cadd4f8SNickeau     * Purge the cache if needed
594cadd4f8SNickeau     * @param Doku_Event $event
604cadd4f8SNickeau     * @param $params
614cadd4f8SNickeau     */
624cadd4f8SNickeau    function slotCreateCacheExpiration(Doku_Event $event, $params)
634cadd4f8SNickeau    {
644cadd4f8SNickeau
654cadd4f8SNickeau        /**
664cadd4f8SNickeau         * No cache for all mode
674cadd4f8SNickeau         * (ie xhtml, instruction)
684cadd4f8SNickeau         */
694cadd4f8SNickeau        $data = &$event->data;
704cadd4f8SNickeau        $pageId = $data->page;
714cadd4f8SNickeau
724cadd4f8SNickeau        /**
734cadd4f8SNickeau         * For whatever reason, the cache file of XHTML
744cadd4f8SNickeau         * may be empty - No error found on the web server or the log.
754cadd4f8SNickeau         *
764cadd4f8SNickeau         * We just delete it then.
774cadd4f8SNickeau         *
784cadd4f8SNickeau         * It has been seen after the creation of a new page or a `move` of the page.
794cadd4f8SNickeau         */
804cadd4f8SNickeau        if ($data instanceof CacheRenderer) {
814cadd4f8SNickeau            if ($data->mode === "xhtml") {
824cadd4f8SNickeau                if (file_exists($data->cache)) {
834cadd4f8SNickeau                    if (filesize($data->cache) === 0) {
844cadd4f8SNickeau                        $data->depends["purge"] = true;
854cadd4f8SNickeau                        return;
864cadd4f8SNickeau                    }
874cadd4f8SNickeau                }
884cadd4f8SNickeau            }
894cadd4f8SNickeau        }
904cadd4f8SNickeau
91*04fd306cSNickeau        $executionContext = ExecutionContext::getActualOrCreateFromEnv();
92*04fd306cSNickeau        $cacheManager = $executionContext->getCacheManager();
934cadd4f8SNickeau        $shouldSlotExpire = $cacheManager->shouldSlotExpire($pageId);
944cadd4f8SNickeau        if ($shouldSlotExpire) {
95*04fd306cSNickeau            try {
96*04fd306cSNickeau                $requestedWikiId = $executionContext->getRequestedPath()->getWikiId();
97*04fd306cSNickeau            } catch (ExceptionNotFound $e) {
98*04fd306cSNickeau                LogUtility::internalError("Cache expiration: The requested path could not be determined, default context path was set instead.");
99*04fd306cSNickeau                $requestedWikiId = $executionContext->getContextPath()->getWikiId();
100*04fd306cSNickeau            }
1014cadd4f8SNickeau            Event::createEvent(
1024cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
1034cadd4f8SNickeau                [
1044cadd4f8SNickeau                    PagePath::getPersistentName() => $pageId,
105*04fd306cSNickeau                    self::REQUESTED_ID => $requestedWikiId
1064cadd4f8SNickeau                ]
1074cadd4f8SNickeau            );
1084cadd4f8SNickeau        }
1094cadd4f8SNickeau
1104cadd4f8SNickeau
1114cadd4f8SNickeau    }
1124cadd4f8SNickeau
1134cadd4f8SNickeau    public function handleSlotCacheExpiration($event)
1144cadd4f8SNickeau    {
1154cadd4f8SNickeau        $data = $event->data;
1164cadd4f8SNickeau        $slotPath = $data[PagePath::getPersistentName()];
1174cadd4f8SNickeau        $requestedId = $data[self::REQUESTED_ID];
1184cadd4f8SNickeau
1194cadd4f8SNickeau        /**
1204cadd4f8SNickeau         * The cache file may be dependent on the requested id
121*04fd306cSNickeau         * ie (@link MarkupCacheDependencies::OUTPUT_DEPENDENCIES}
1224cadd4f8SNickeau         */
1234cadd4f8SNickeau        global $ID;
1244cadd4f8SNickeau        $keep = $ID;
1254cadd4f8SNickeau        try {
1264cadd4f8SNickeau            $ID = $requestedId;
127*04fd306cSNickeau            $slot = MarkupPath::createPageFromAbsoluteId($slotPath);
1284cadd4f8SNickeau
1294cadd4f8SNickeau            /**
1304cadd4f8SNickeau             * Calculate a new expiration date
1314cadd4f8SNickeau             * And set it here because setting a new metadata
1324cadd4f8SNickeau             * will make the cache unusable
1334cadd4f8SNickeau             */
1344cadd4f8SNickeau            $cacheExpirationDateMeta = CacheExpirationDate::createForPage($slot);
1354cadd4f8SNickeau            $actualDate = $cacheExpirationDateMeta->getValue();
1364cadd4f8SNickeau            $cacheExpirationFrequency = CacheExpirationFrequency::createForPage($slot)
1374cadd4f8SNickeau                ->getValue();
1384cadd4f8SNickeau            try {
1394cadd4f8SNickeau                $newDate = Cron::getDate($cacheExpirationFrequency);
140*04fd306cSNickeau            } catch (ExceptionCompile $e) {
1414cadd4f8SNickeau                LogUtility::msg("Error while calculating the new expiration date. Error: {$e->getMessage()}");
1424cadd4f8SNickeau                return;
1434cadd4f8SNickeau            }
1444cadd4f8SNickeau            if ($newDate < $actualDate) {
1454cadd4f8SNickeau                LogUtility::msg("The new calculated date cache expiration frequency ({$newDate->format(Iso8601Date::getFormat())}) is lower than the current date ({$actualDate->format(Iso8601Date::getFormat())})");
1464cadd4f8SNickeau            }
1474cadd4f8SNickeau            try {
1484cadd4f8SNickeau                $cacheExpirationDateMeta
1494cadd4f8SNickeau                    ->setValue($newDate)
1504cadd4f8SNickeau                    ->persist();
151*04fd306cSNickeau            } catch (ExceptionCompile $e) {
1524cadd4f8SNickeau                LogUtility::msg("Error while persisting the new expiration date. Error:{$e->getMessage()}");
1534cadd4f8SNickeau                return;
1544cadd4f8SNickeau            }
1554cadd4f8SNickeau
1564cadd4f8SNickeau            /**
1574cadd4f8SNickeau             * Cache deletion
1584cadd4f8SNickeau             */
1594cadd4f8SNickeau            $message = "Expiration Date has expired";
160*04fd306cSNickeau            $outputDocument = $slot->getInstructionsDocument();
1614cadd4f8SNickeau            CacheLog::deleteCacheIfExistsAndLog(
162*04fd306cSNickeau                $outputDocument,
1634cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
1644cadd4f8SNickeau                $message);
165*04fd306cSNickeau            $fetcher = $slot->createHtmlFetcherWithItselfAsContextPath();
1664cadd4f8SNickeau            CacheLog::deleteCacheIfExistsAndLog(
167*04fd306cSNickeau                $fetcher,
1684cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
1694cadd4f8SNickeau                $message);
1704cadd4f8SNickeau
1714cadd4f8SNickeau            /**
1724cadd4f8SNickeau             * Re-render
1734cadd4f8SNickeau             */
174*04fd306cSNickeau            $fetcher2 = $slot->createHtmlFetcherWithItselfAsContextPath();
1754cadd4f8SNickeau            CacheLog::renderCacheAndLog(
176*04fd306cSNickeau                $fetcher2,
1774cadd4f8SNickeau                self::SLOT_CACHE_EXPIRATION_EVENT,
1784cadd4f8SNickeau                $message);
1794cadd4f8SNickeau
180*04fd306cSNickeau
1814cadd4f8SNickeau        } finally {
1824cadd4f8SNickeau            $ID = $keep;
1834cadd4f8SNickeau        }
1844cadd4f8SNickeau
1854cadd4f8SNickeau    }
1864cadd4f8SNickeau
1874cadd4f8SNickeau
1884cadd4f8SNickeau}
189