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