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