xref: /plugin/struct/action/cache.php (revision 4fc1424af829d05c69a00a0c2ae33facc7342115)
1<?php
2
3use dokuwiki\plugin\struct\meta\Assignments;
4use dokuwiki\plugin\struct\meta\SearchConfig;
5use dokuwiki\plugin\struct\meta\SearchConfigParameters;
6
7/**
8 * Handle caching of pages containing struct aggregations
9 */
10class action_plugin_struct_cache extends DokuWiki_Action_Plugin
11{
12    /**
13     * Registers a callback function for a given event
14     *
15     * @param Doku_Event_Handler $controller DokuWiki's event controller object
16     * @return void
17     */
18    public function register(Doku_Event_Handler $controller)
19    {
20        $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'handleCacheSchemachange');
21        $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'handleCacheAggregation');
22        $controller->register_hook('PARSER_CACHE_USE', 'AFTER', $this, 'handleCacheDynamic');
23    }
24
25    /**
26     * @return string the refresh file
27     */
28    public static function getSchemaRefreshFile()
29    {
30        global $conf;
31        return $conf['cachedir'] . '/struct.schemarefresh';
32    }
33
34    /**
35     * For pages potentially containing schema data, refresh the cache when schema data has been
36     * updated
37     *
38     * @param Doku_Event $event event object by reference
39     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
40     *                           handler was registered]
41     * @return bool
42     */
43    public function handleCacheSchemachange(Doku_Event $event, $param)
44    {
45        /** @var \cache_parser $cache */
46        $cache = $event->data;
47        if ($cache->mode != 'xhtml') return true;
48        if (!$cache->page) return true; // not a page cache
49
50        $assignments = Assignments::getInstance();
51        if (!$assignments->getPageAssignments($cache->page)) return true; // no struct here
52
53        $cache->depends['files'][] = self::getSchemaRefreshFile();
54        return true;
55    }
56
57    /**
58     * For pages containing an aggregation, add the last modified date of the database itself
59     * to the cache dependencies
60     *
61     * @param Doku_Event $event event object by reference
62     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
63     *                           handler was registered]
64     * @return bool
65     */
66    public function handleCacheAggregation(Doku_Event $event, $param)
67    {
68        global $INPUT;
69
70        /** @var \cache_parser $cache */
71        $cache = $event->data;
72        if ($cache->mode != 'xhtml') return true;
73        if (!$cache->page) return true; // not a page cache
74
75        $meta = p_get_metadata($cache->page, 'plugin struct');
76        if (isset($meta['hasaggregation'])) {
77            /** @var helper_plugin_struct_db $db */
78            $db = plugin_load('helper', 'struct_db');
79            // cache depends on last database save
80            $sqlite = $db->getDB(false);
81            if ($sqlite) {
82                $cache->depends['files'][] = $sqlite->getDbFile();
83            }
84
85            // dynamic renders should never overwrite the default page cache
86            // we need this in additon to handle_cache_dynamic() below because we can only
87            // influence if a cache is used, not that it will be written
88            if (
89                $INPUT->has(SearchConfigParameters::$PARAM_FILTER) ||
90                $INPUT->has(SearchConfigParameters::$PARAM_OFFSET) ||
91                $INPUT->has(SearchConfigParameters::$PARAM_SORT)
92            ) {
93                $cache->key .= 'dynamic';
94            }
95
96            // cache depends on today's date
97            if ($meta['hasaggregation'] & SearchConfig::$CACHE_DATE) {
98                $oldage = $cache->depends['age'];
99                $newage = time() - mktime(0, 0, 1); // time since first second today
100                $cache->depends['age'] = min($oldage, $newage);
101            }
102
103            // cache depends on current user
104            if ($meta['hasaggregation'] & SearchConfig::$CACHE_USER) {
105                $cache->key .= ';' . $INPUT->server->str('REMOTE_USER');
106            }
107
108            // rebuild cachename
109            $cache->cache = getCacheName($cache->key, $cache->ext);
110        }
111
112        return true;
113    }
114
115    /**
116     * Disable cache when dymanic parameters are present
117     *
118     * @param Doku_Event $event event object by reference
119     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
120     *                           handler was registered]
121     * @return bool
122     */
123    public function handleCacheDynamic(Doku_Event $event, $param)
124    {
125        /** @var \cache_parser $cache */
126        $cache = $event->data;
127        if ($cache->mode != 'xhtml') return true;
128        if (!$cache->page) return true; // not a page cache
129        global $INPUT;
130
131        // disable cache use when one of these parameters is present
132        foreach (
133            array(
134                     SearchConfigParameters::$PARAM_FILTER,
135                     SearchConfigParameters::$PARAM_OFFSET,
136                     SearchConfigParameters::$PARAM_SORT
137                 ) as $key
138        ) {
139            if ($INPUT->has($key)) {
140                $event->result = false;
141                return true;
142            }
143        }
144
145        return true;
146    }
147}
148