1c677cb9fSwikidesign<?php 2c677cb9fSwikidesign/** 3c677cb9fSwikidesign * Include Plugin: Display a wiki page within another wiki page 4c677cb9fSwikidesign * 5c677cb9fSwikidesign * Action plugin component, for cache validity determination 6c677cb9fSwikidesign * 7c677cb9fSwikidesign * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8c677cb9fSwikidesign * @author Christopher Smith <chris@jalakai.co.uk> 9c677cb9fSwikidesign */ 10c677cb9fSwikidesignif(!defined('DOKU_INC')) die(); // no Dokuwiki, no go 11c677cb9fSwikidesign 12c677cb9fSwikidesignif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13c677cb9fSwikidesignrequire_once(DOKU_PLUGIN.'action.php'); 14c677cb9fSwikidesign 15c677cb9fSwikidesign/** 16c677cb9fSwikidesign * All DokuWiki plugins to extend the parser/rendering mechanism 17c677cb9fSwikidesign * need to inherit from this class 18c677cb9fSwikidesign */ 19c677cb9fSwikidesignclass action_plugin_include extends DokuWiki_Action_Plugin { 20c677cb9fSwikidesign 21c677cb9fSwikidesign var $supportedModes = array('xhtml'); 22c677cb9fSwikidesign 23c677cb9fSwikidesign /** 24c677cb9fSwikidesign * return some info 25c677cb9fSwikidesign */ 26c677cb9fSwikidesign function getInfo() { 27c677cb9fSwikidesign return array( 28dbdadbd9SGina Haeussge 'author' => 'Gina Häußge, Michael Klier, Christopher Smith', 29dbdadbd9SGina Haeussge 'email' => 'dokuwiki@chimeric.de', 30*4052f233SGina Haeussge 'date' => @file_get_contents(DOKU_PLUGIN . 'blog/VERSION'), 31c677cb9fSwikidesign 'name' => 'Include Plugin', 32c677cb9fSwikidesign 'desc' => 'Improved cache handling for included pages', 33c677cb9fSwikidesign 'url' => 'http://wiki.splitbrain.org/plugin:include', 34c677cb9fSwikidesign ); 35c677cb9fSwikidesign } 36c677cb9fSwikidesign 37c677cb9fSwikidesign /** 38c677cb9fSwikidesign * plugin should use this method to register its handlers with the dokuwiki's event controller 39c677cb9fSwikidesign */ 40c677cb9fSwikidesign function register(&$controller) { 41c677cb9fSwikidesign $controller->register_hook('PARSER_CACHE_USE','BEFORE', $this, '_cache_prepare'); 42c677cb9fSwikidesign# $controller->register_hook('PARSER_CACHE_USE','AFTER', $this, '_cache_result'); // debugging only 43c677cb9fSwikidesign } 44c677cb9fSwikidesign 45c677cb9fSwikidesign /** 46c677cb9fSwikidesign * prepare the cache object for default _useCache action 47c677cb9fSwikidesign */ 48c677cb9fSwikidesign function _cache_prepare(&$event, $param) { 49c677cb9fSwikidesign $cache =& $event->data; 50c677cb9fSwikidesign 51c677cb9fSwikidesign // we're only interested in wiki pages and supported render modes 52c677cb9fSwikidesign if (!isset($cache->page)) return; 53c677cb9fSwikidesign if (!isset($cache->mode) || !in_array($cache->mode, $this->supportedModes)) return; 54c677cb9fSwikidesign 55c677cb9fSwikidesign $key = ''; 56c677cb9fSwikidesign $depends = array(); 57c677cb9fSwikidesign $expire = $this->_inclusion_check($cache->page, $key, $depends); 58c677cb9fSwikidesign 59c677cb9fSwikidesign# global $debug; 60c677cb9fSwikidesign# $debug[] = compact('key','expire','depends','cache'); 61c677cb9fSwikidesign 62c677cb9fSwikidesign // empty $key implies no includes, so nothing to do 63c677cb9fSwikidesign if (empty($key)) return; 64c677cb9fSwikidesign 65c677cb9fSwikidesign // mark the cache as being modified by the include plugin 66c677cb9fSwikidesign $cache->include = true; 67c677cb9fSwikidesign 68c677cb9fSwikidesign // set new cache key & cache name - now also dependent on included page ids and their ACL_READ status 69c677cb9fSwikidesign $cache->key .= $key; 70c677cb9fSwikidesign $cache->cache = getCacheName($cache->key, $cache->ext); 71c677cb9fSwikidesign 72c677cb9fSwikidesign // inclusion check was able to determine the cache must be invalid 73c677cb9fSwikidesign if ($expire) { 74c677cb9fSwikidesign $event->preventDefault(); 75c677cb9fSwikidesign $event->stopPropagation(); 76c677cb9fSwikidesign $event->result = false; 77c677cb9fSwikidesign return; 78c677cb9fSwikidesign } 79c677cb9fSwikidesign 80c677cb9fSwikidesign // update depends['files'] array to include all included files 81c677cb9fSwikidesign $cache->depends['files'] = !empty($cache->depends['files']) ? array_merge($cache->depends['files'], $depends) : $depends; 82c677cb9fSwikidesign } 83c677cb9fSwikidesign 84c677cb9fSwikidesign /** 85c677cb9fSwikidesign * carry out included page checks: 86c677cb9fSwikidesign * - to establish proper cache name, its dependent on the read status of included pages 87c677cb9fSwikidesign * - to establish file dependencies, the included raw wiki pages 88c677cb9fSwikidesign * 89c677cb9fSwikidesign * @param string $id wiki page name 90c677cb9fSwikidesign * @param string $key (reference) cache key 91c677cb9fSwikidesign * @param array $depends array of include file dependencies 92c677cb9fSwikidesign * 93c677cb9fSwikidesign * @return bool expire the cache 94c677cb9fSwikidesign */ 95c677cb9fSwikidesign function _inclusion_check($id, &$key, &$depends) { 96c677cb9fSwikidesign $hasPart = p_get_metadata($id, 'relation haspart'); 97c677cb9fSwikidesign if (empty($hasPart)) return false; 98c677cb9fSwikidesign 99c677cb9fSwikidesign $expire = false; 100c677cb9fSwikidesign foreach ($hasPart as $page => $exists) { 101c677cb9fSwikidesign // ensure its a wiki page 102c677cb9fSwikidesign if (strpos($page,'/') || cleanID($page) != $page) continue; 103c677cb9fSwikidesign 104c01ce462SGina Haeussge // recursive includes aren't allowed and there is no need to do the same page twice 105c677cb9fSwikidesign $file = wikiFN($page); 106c01ce462SGina Haeussge if (in_array($file, $depends)) continue; 107c677cb9fSwikidesign 108c677cb9fSwikidesign // file existence state is different from state recorded in metadata 109c677cb9fSwikidesign if (@file_exists($file) != $exists) { 110c677cb9fSwikidesign 111c677cb9fSwikidesign if (($acl = $this->_acl_read_check($page)) != 'NONE') { $expire = true; } 112c677cb9fSwikidesign 113c677cb9fSwikidesign } else if ($exists) { 114c677cb9fSwikidesign 115c677cb9fSwikidesign // carry out an inclusion check on the included page, that will update $key & $depends 116c677cb9fSwikidesign if ($this->_inclusion_check($page, $key, $depends)) { $expire = true; } 117c677cb9fSwikidesign if (($acl = $this->_acl_read_check($page)) != 'NONE') { $depends[] = $file; } 118c677cb9fSwikidesign 119c677cb9fSwikidesign } else { 120c677cb9fSwikidesign $acl = 'NONE'; 121c677cb9fSwikidesign } 122c677cb9fSwikidesign 123c677cb9fSwikidesign // add this page and acl status to the key 124c677cb9fSwikidesign $key .= '#'.$page.'|'.$acl; 125c677cb9fSwikidesign } 126c677cb9fSwikidesign 127c677cb9fSwikidesign return $expire; 128c677cb9fSwikidesign } 129c677cb9fSwikidesign 130c677cb9fSwikidesign function _acl_read_check($id) { 131c677cb9fSwikidesign return (AUTH_READ <= auth_quickaclcheck($id)) ? 'READ' : 'NONE'; 132c677cb9fSwikidesign } 133c677cb9fSwikidesign 134c677cb9fSwikidesign function _cache_result(&$event, $param) { 135c677cb9fSwikidesign $cache =& $event->data; 136c677cb9fSwikidesign if (empty($cache->include)) return; 137c677cb9fSwikidesign 138c677cb9fSwikidesign# global $debug; 139c677cb9fSwikidesign# $debug['cache_result'][] = $event->result ? 'true' : 'false'; 140c677cb9fSwikidesign } 141c677cb9fSwikidesign 142c677cb9fSwikidesign} 143df4e907bSMichael Klier//vim:ts=4:sw=4:et:enc=utf-8: 144