[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
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 9 if(!defined('DOKU_INC')) die('meh.'); 10 11 /** 12 * The event 13 */ 14 class Doku_Event { 15 16 // public properties 17 public $name = ''; // READONLY event name, objects must register against this name to see the event 18 public $data = null; // READWRITE data relevant to the event, no standardised format (YET!) 19 public $result = null; // READWRITE the results of the event action, only relevant in "_AFTER" advise 20 // event handlers may modify this if they are preventing the default action 21 // to provide the after event handlers with event results 22 public $canPreventDefault = true; // READONLY if true, event handlers can prevent the events default action 23 24 // private properties, event handlers can effect these through the provided methods 25 protected $_default = true; // whether or not to carry out the default action associated with the event 26 protected $_continue = true; // whether or not to continue propagating the event to other handlers 27 28 /** 29 * event constructor 30 * 31 * @param string $name 32 * @param mixed $data 33 */ 34 function __construct($name, &$data) { 35 36 $this->name = $name; 37 $this->data =& $data; 38 39 } 40 41 /** 42 * @return string 43 */ 44 function __toString() { 45 return $this->name; 46 } 47 48 /** 49 * advise functions 50 * 51 * advise all registered handlers of this event 52 * 53 * if these methods are used by functions outside of this object, they must 54 * properly handle correct processing of any default action and issue an 55 * advise_after() signal. e.g. 56 * $evt = new Doku_Event(name, data); 57 * if ($evt->advise_before(canPreventDefault) { 58 * // default action code block 59 * } 60 * $evt->advise_after(); 61 * unset($evt); 62 * 63 * @param bool $enablePreventDefault 64 * @return bool results of processing the event, usually $this->_default 65 */ 66 function advise_before($enablePreventDefault=true) { 67 global $EVENT_HANDLER; 68 69 $this->canPreventDefault = $enablePreventDefault; 70 $EVENT_HANDLER->process_event($this,'BEFORE'); 71 72 return (!$enablePreventDefault || $this->_default); 73 } 74 75 function advise_after() { 76 global $EVENT_HANDLER; 77 78 $this->_continue = true; 79 $EVENT_HANDLER->process_event($this,'AFTER'); 80 } 81 82 /** 83 * trigger 84 * 85 * - advise all registered (<event>_BEFORE) handlers that this event is about to take place 86 * - carry out the default action using $this->data based on $enablePrevent and 87 * $this->_default, all of which may have been modified by the event handlers. 88 * - advise all registered (<event>_AFTER) handlers that the event has taken place 89 * 90 * @param null|callable $action 91 * @param bool $enablePrevent 92 * @return mixed $event->results 93 * the value set by any <event>_before or <event> handlers if the default action is prevented 94 * or the results of the default action (as modified by <event>_after handlers) 95 * or NULL no action took place and no handler modified the value 96 */ 97 function trigger($action=null, $enablePrevent=true) { 98 99 if (!is_callable($action)) { 100 $enablePrevent = false; 101 if (!is_null($action)) { 102 trigger_error('The default action of '.$this.' is not null but also not callable. Maybe the method is not public?', E_USER_WARNING); 103 } 104 } 105 106 if ($this->advise_before($enablePrevent) && is_callable($action)) { 107 if (is_array($action)) { 108 list($obj,$method) = $action; 109 $this->result = $obj->$method($this->data); 110 } else { 111 $this->result = $action($this->data); 112 } 113 } 114 115 $this->advise_after(); 116 117 return $this->result; 118 } 119 120 /** 121 * stopPropagation 122 * 123 * stop any further processing of the event by event handlers 124 * this function does not prevent the default action taking place 125 */ 126 public function stopPropagation() { 127 $this->_continue = false; 128 } 129 130 /** 131 * may the event propagate to the next handler? 132 * 133 * @return bool 134 */ 135 public function mayPropagate() { 136 return $this->_continue; 137 } 138 139 /** 140 * preventDefault 141 * 142 * prevent the default action taking place 143 */ 144 public function preventDefault() { 145 $this->_default = false; 146 } 147 148 /** 149 * should the default action be executed? 150 * 151 * @return bool 152 */ 153 public function mayRunDefault() { 154 return $this->_default; 155 } 156 } 157 158 /** 159 * Controls the registration and execution of all events, 160 */ 161 class Doku_Event_Handler { 162 163 // public properties: none 164 165 // private properties 166 protected $_hooks = array(); // array of events and their registered handlers 167 168 /** 169 * event_handler 170 * 171 * constructor, loads all action plugins and calls their register() method giving them 172 * an opportunity to register any hooks they require 173 */ 174 function __construct() { 175 176 // load action plugins 177 /** @var DokuWiki_Action_Plugin $plugin */ 178 $plugin = null; 179 $pluginlist = plugin_list('action'); 180 181 foreach ($pluginlist as $plugin_name) { 182 $plugin = plugin_load('action',$plugin_name); 183 184 if ($plugin !== null) $plugin->register($this); 185 } 186 } 187 188 /** 189 * register_hook 190 * 191 * register a hook for an event 192 * 193 * @param string $event string name used by the event, (incl '_before' or '_after' for triggers) 194 * @param string $advise 195 * @param object $obj object in whose scope method is to be executed, 196 * if NULL, method is assumed to be a globally available function 197 * @param string $method event handler function 198 * @param mixed $param data passed to the event handler 199 * @param int $seq sequence number for ordering hook execution (ascending) 200 */ 201 function register_hook($event, $advise, $obj, $method, $param=null, $seq=0) { 202 $seq = (int)$seq; 203 $doSort = !isset($this->_hooks[$event.'_'.$advise][$seq]); 204 $this->_hooks[$event.'_'.$advise][$seq][] = array($obj, $method, $param); 205 206 if ($doSort) { 207 ksort($this->_hooks[$event.'_'.$advise]); 208 } 209 } 210 211 /** 212 * process the before/after event 213 * 214 * @param Doku_Event $event 215 * @param string $advise BEFORE or AFTER 216 */ 217 function process_event($event,$advise='') { 218 219 $evt_name = $event->name . ($advise ? '_'.$advise : '_BEFORE'); 220 221 if (!empty($this->_hooks[$evt_name])) { 222 foreach ($this->_hooks[$evt_name] as $sequenced_hooks) { 223 foreach ($sequenced_hooks as $hook) { 224 list($obj, $method, $param) = $hook; 225 226 if (is_null($obj)) { 227 $method($event, $param); 228 } else { 229 $obj->$method($event, $param); 230 } 231 232 if (!$event->mayPropagate()) return; 233 } 234 } 235 } 236 } 237 238 /** 239 * Check if an event has any registered handlers 240 * 241 * When $advise is empty, both BEFORE and AFTER events will be considered, 242 * otherwise only the given advisory is checked 243 * 244 * @param string $name Name of the event 245 * @param string $advise BEFORE, AFTER or empty 246 * @return bool 247 */ 248 public function hasHandlerForEvent($name, $advise = '') { 249 if($advise) { 250 return isset($this->_hooks[$name . '_' . $advise]); 251 } else { 252 return isset($this->_hooks[$name . '_BEFORE']) || isset($this->_hooks[$name . '_AFTER']); 253 } 254 } 255 } 256 257 /** 258 * trigger_event 259 * 260 * function wrapper to process (create, trigger and destroy) an event 261 * 262 * @param string $name name for the event 263 * @param mixed $data event data 264 * @param callback $action (optional, default=NULL) default action, a php callback function 265 * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action 266 * 267 * @return mixed the event results value after all event processing is complete 268 * by default this is the return value of the default action however 269 * it can be set or modified by event handler hooks 270 */ 271 function trigger_event($name, &$data, $action=null, $canPreventDefault=true) { 272 273 $evt = new Doku_Event($name, $data); 274 return $evt->trigger($action, $canPreventDefault); 275 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body