1<?php 2/** 3 * DokuWiki Events 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Christopher Smith <chris@jalakai.co.uk> 7 */ 8 9if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/'); 10require_once(DOKU_INC.'inc/pluginutils.php'); 11 12class Doku_Event { 13 14 // public properties 15 var $name = ''; // READONLY event name, objects must register against this name to see the event 16 var $data = NULL; // READWRITE data relevant to the event, no standardised format (YET!) 17 var $result = NULL; // READWRITE the results of the event action, only relevant in "_AFTER" advise 18 // event handlers may modify this if they are preventing the default action 19 // to provide the after event handlers with event results 20 var $canPreventDefault = true; // READONLY if true, event handlers can prevent the events default action 21 22 // private properties, event handlers can effect these through the provided methods 23 var $_default = true; // whether or not to carry out the default action associated with the event 24 var $_continue = true; // whether or not to continue propagating the event to other handlers 25 26 /** 27 * event constructor 28 */ 29 function Doku_Event($name, &$data) { 30 31 $this->name = $name; 32 $this->data =& $data; 33 34 } 35 36 /** 37 * advise functions 38 * 39 * advise all registered handlers of this event 40 * 41 * if these methods are used by functions outside of this object, they must 42 * properly handle correct processing of any default action and issue an 43 * advise_after() signal. e.g. 44 * $evt = new Doku_Event(name, data); 45 * if ($evt->advise_before(canPreventDefault) { 46 * // default action code block 47 * } 48 * $evt->advise_after(); 49 * unset($evt); 50 * 51 * @return results of processing the event, usually $this->_default 52 */ 53 function advise_before($enablePreventDefault=true) { 54 global $EVENT_HANDLER; 55 56 $this->canPreventDefault = $enablePreventDefault; 57 $EVENT_HANDLER->process_event($this,'BEFORE'); 58 59 return (!$enablePreventDefault || $this->_default); 60 } 61 62 function advise_after() { 63 global $EVENT_HANDLER; 64 65 $this->_continue = true; 66 $EVENT_HANDLER->process_event($this,'AFTER'); 67 } 68 69 /** 70 * trigger 71 * 72 * - advise all registered (<event>_BEFORE) handlers that this event is about to take place 73 * - carry out the default action using $this->data based on $enablePrevent and 74 * $this->_default, all of which may have been modified by the event handlers. 75 * - advise all registered (<event>_AFTER) handlers that the event has taken place 76 * 77 * @return $event->results 78 * the value set by any <event>_before or <event> handlers if the default action is prevented 79 * or the results of the default action (as modified by <event>_after handlers) 80 * or NULL no action took place and no handler modified the value 81 */ 82 function trigger($action=NULL, $enablePrevent=true) { 83 84 if (!is_callable($action)) $enablePrevent = false; 85 86 if ($this->advise_before($enablePrevent) && is_callable($action)) { 87 if (is_array($action)) { 88 list($obj,$method) = $action; 89 $this->result = $obj->$method($this->data); 90 } else { 91 $this->result = $action($this->data); 92 } 93 } 94 95 $this->advise_after(); 96 97 return $this->result; 98 } 99 100 /** 101 * stopPropagation 102 * 103 * stop any further processing of the event by event handlers 104 * this function does not prevent the default action taking place 105 */ 106 function stopPropagation() { $this->_continue = false; } 107 108 /** 109 * preventDefault 110 * 111 * prevent the default action taking place 112 */ 113 function preventDefault() { $this->_default = false; } 114} 115 116class Doku_Event_Handler { 117 118 // public properties: none 119 120 // private properties 121 var $_hooks = array(); // array of events and their registered handlers 122 123 /** 124 * event_handler 125 * 126 * constructor, loads all action plugins and calls their register() method giving them 127 * an opportunity to register any hooks they require 128 */ 129 function Doku_Event_Handler() { 130 131 // load action plugins 132 $plugin = NULL; 133 $pluginlist = plugin_list('action'); 134 135 foreach ($pluginlist as $plugin_name) { 136 $plugin =& plugin_load('action',$plugin_name); 137 138 if ($plugin !== NULL) $plugin->register($this); 139 } 140 } 141 142 /** 143 * register_hook 144 * 145 * register a hook for an event 146 * 147 * @PARAM $event (string) name used by the event, (incl '_before' or '_after' for triggers) 148 * @PARAM $obj (obj) object in whose scope method is to be executed, 149 * if NULL, method is assumed to be a globally available function 150 * @PARAM $method (function) event handler function 151 * @PARAM $param (mixed) data passed to the event handler 152 */ 153 function register_hook($event, $advise, &$obj, $method, $param=NULL) { 154 $this->_hooks[$event.'_'.$advise][] = array(&$obj, $method, $param); 155 } 156 157 function process_event(&$event,$advise='') { 158 159 $evt_name = $event->name . ($advise ? '_'.$advise : '_BEFORE'); 160 161 if (!empty($this->_hooks[$evt_name])) { 162 $hook = reset($this->_hooks[$evt_name]); 163 do { 164// list($obj, $method, $param) = $hook; 165 $obj =& $hook[0]; 166 $method = $hook[1]; 167 $param = $hook[2]; 168 169 if (is_null($obj)) { 170 $method($event, $param); 171 } else { 172 $obj->$method($event, $param); 173 } 174 175 } while ($event->_continue && $hook = next($this->_hooks[$evt_name])); 176 } 177 } 178} 179 180/** 181 * trigger_event 182 * 183 * function wrapper to process (create, trigger and destroy) an event 184 * 185 * @PARAM $name (string) name for the event 186 * @PARAM $data (mixed) event data 187 * @PARAM $action (callback) (optional, default=NULL) default action, a php callback function 188 * @PARAM $canPreventDefault (bool) (optional, default=true) can hooks prevent the default action 189 * 190 * @RETURN (mixed) the event results value after all event processing is complete 191 * by default this is the return value of the default action however 192 * it can be set or modified by event handler hooks 193 */ 194function trigger_event($name, &$data, $action=NULL, $canPreventDefault=true) { 195 196 $evt = new Doku_Event($name, $data); 197 return $evt->trigger($action, $canPreventDefault); 198} 199 200// create the event handler 201global $EVENT_HANDLER; 202$EVENT_HANDLER = new Doku_Event_Handler(); 203