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