1<?php 2 3// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps 4 5namespace dokuwiki\Extension; 6 7use dokuwiki\Logger; 8 9/** 10 * The Action plugin event 11 */ 12class Event 13{ 14 /** @var string READONLY event name, objects must register against this name to see the event */ 15 public $name = ''; 16 /** @var mixed|null READWRITE data relevant to the event, no standardised format, refer to event docs */ 17 public $data; 18 /** 19 * @var mixed|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 */ 23 public $result; 24 /** @var bool READONLY if true, event handlers can prevent the events default action */ 25 public $canPreventDefault = true; 26 27 /** @var bool whether or not to carry out the default action associated with the event */ 28 protected $runDefault = true; 29 /** @var bool whether or not to continue propagating the event to other handlers */ 30 protected $mayContinue = true; 31 32 /** 33 * event constructor 34 * 35 * @param string $name 36 * @param mixed $data 37 */ 38 public function __construct($name, &$data) 39 { 40 41 $this->name = $name; 42 $this->data =& $data; 43 } 44 45 /** 46 * @return string 47 */ 48 public function __toString() 49 { 50 return $this->name; 51 } 52 53 /** 54 * advise all registered BEFORE handlers of this event 55 * 56 * if these methods are used by functions outside of this object, they must 57 * properly handle correct processing of any default action and issue an 58 * advise_after() signal. e.g. 59 * $evt = new dokuwiki\Plugin\Doku_Event(name, data); 60 * if ($evt->advise_before(canPreventDefault) { 61 * // default action code block 62 * } 63 * $evt->advise_after(); 64 * unset($evt); 65 * 66 * @param bool $enablePreventDefault 67 * @return bool results of processing the event, usually $this->runDefault 68 */ 69 public function advise_before($enablePreventDefault = true) 70 { 71 global $EVENT_HANDLER; 72 73 $this->canPreventDefault = $enablePreventDefault; 74 if ($EVENT_HANDLER !== null) { 75 $EVENT_HANDLER->process_event($this, 'BEFORE'); 76 } else { 77 Logger::getInstance(Logger::LOG_DEBUG) 78 ->log($this->name . ':BEFORE event triggered before event system was initialized'); 79 } 80 81 return (!$enablePreventDefault || $this->runDefault); 82 } 83 84 /** 85 * advise all registered AFTER handlers of this event 86 * 87 * @param bool $enablePreventDefault 88 * @see advise_before() for details 89 */ 90 public function advise_after() 91 { 92 global $EVENT_HANDLER; 93 94 $this->mayContinue = true; 95 96 if ($EVENT_HANDLER !== null) { 97 $EVENT_HANDLER->process_event($this, 'AFTER'); 98 } else { 99 Logger::getInstance(Logger::LOG_DEBUG)-> 100 log($this->name . ':AFTER event triggered before event system was initialized'); 101 } 102 } 103 104 /** 105 * trigger 106 * 107 * - advise all registered (<event>_BEFORE) handlers that this event is about to take place 108 * - carry out the default action using $this->data based on $enablePrevent and 109 * $this->_default, all of which may have been modified by the event handlers. 110 * - advise all registered (<event>_AFTER) handlers that the event has taken place 111 * 112 * @param null|callable $action 113 * @param bool $enablePrevent 114 * @return mixed $event->results 115 * the value set by any <event>_before or <event> handlers if the default action is prevented 116 * or the results of the default action (as modified by <event>_after handlers) 117 * or NULL no action took place and no handler modified the value 118 */ 119 public function trigger($action = null, $enablePrevent = true) 120 { 121 122 if (!is_callable($action)) { 123 $enablePrevent = false; 124 if ($action !== null) { 125 trigger_error( 126 'The default action of ' . $this . 127 ' is not null but also not callable. Maybe the method is not public?', 128 E_USER_WARNING 129 ); 130 } 131 } 132 133 if ($this->advise_before($enablePrevent) && is_callable($action)) { 134 $this->result = call_user_func_array($action, [&$this->data]); 135 } 136 137 $this->advise_after(); 138 139 return $this->result; 140 } 141 142 /** 143 * stopPropagation 144 * 145 * stop any further processing of the event by event handlers 146 * this function does not prevent the default action taking place 147 */ 148 public function stopPropagation() 149 { 150 $this->mayContinue = false; 151 } 152 153 /** 154 * may the event propagate to the next handler? 155 * 156 * @return bool 157 */ 158 public function mayPropagate() 159 { 160 return $this->mayContinue; 161 } 162 163 /** 164 * preventDefault 165 * 166 * prevent the default action taking place 167 */ 168 public function preventDefault() 169 { 170 $this->runDefault = false; 171 } 172 173 /** 174 * should the default action be executed? 175 * 176 * @return bool 177 */ 178 public function mayRunDefault() 179 { 180 return $this->runDefault; 181 } 182 183 /** 184 * Convenience method to trigger an event 185 * 186 * Creates, triggers and destroys an event in one go 187 * 188 * @param string $name name for the event 189 * @param mixed $data event data 190 * @param callable $action (optional, default=NULL) default action, a php callback function 191 * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action 192 * 193 * @return mixed the event results value after all event processing is complete 194 * by default this is the return value of the default action however 195 * it can be set or modified by event handler hooks 196 */ 197 public static function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true) 198 { 199 $evt = new Event($name, $data); 200 return $evt->trigger($action, $canPreventDefault); 201 } 202} 203