1e1d9dcc8SAndreas Gohr<?php 2*d4f83172SAndreas Gohr 3091ad7bdSAndreas Gohr// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps 4e1d9dcc8SAndreas Gohr 5e1d9dcc8SAndreas Gohrnamespace dokuwiki\Extension; 6e1d9dcc8SAndreas Gohr 70ecde6ceSAndreas Gohruse dokuwiki\Logger; 80ecde6ceSAndreas Gohr 9e1d9dcc8SAndreas Gohr/** 10e1d9dcc8SAndreas Gohr * The Action plugin event 11e1d9dcc8SAndreas Gohr */ 12e1d9dcc8SAndreas Gohrclass Event 13e1d9dcc8SAndreas Gohr{ 14091ad7bdSAndreas Gohr /** @var string READONLY event name, objects must register against this name to see the event */ 15091ad7bdSAndreas Gohr public $name = ''; 16091ad7bdSAndreas Gohr /** @var mixed|null READWRITE data relevant to the event, no standardised format, refer to event docs */ 171490c177SAndreas Gohr public $data; 18091ad7bdSAndreas Gohr /** 19091ad7bdSAndreas Gohr * @var mixed|null READWRITE the results of the event action, only relevant in "_AFTER" advise 20091ad7bdSAndreas Gohr * event handlers may modify this if they are preventing the default action 21091ad7bdSAndreas Gohr * to provide the after event handlers with event results 22091ad7bdSAndreas Gohr */ 231490c177SAndreas Gohr public $result; 24091ad7bdSAndreas Gohr /** @var bool READONLY if true, event handlers can prevent the events default action */ 25091ad7bdSAndreas Gohr public $canPreventDefault = true; 26e1d9dcc8SAndreas Gohr 27091ad7bdSAndreas Gohr /** @var bool whether or not to carry out the default action associated with the event */ 28091ad7bdSAndreas Gohr protected $runDefault = true; 29091ad7bdSAndreas Gohr /** @var bool whether or not to continue propagating the event to other handlers */ 30091ad7bdSAndreas Gohr protected $mayContinue = true; 31e1d9dcc8SAndreas Gohr 32e1d9dcc8SAndreas Gohr /** 33e1d9dcc8SAndreas Gohr * event constructor 34e1d9dcc8SAndreas Gohr * 35e1d9dcc8SAndreas Gohr * @param string $name 36e1d9dcc8SAndreas Gohr * @param mixed $data 37e1d9dcc8SAndreas Gohr */ 38e1d9dcc8SAndreas Gohr public function __construct($name, &$data) 39e1d9dcc8SAndreas Gohr { 40e1d9dcc8SAndreas Gohr 41e1d9dcc8SAndreas Gohr $this->name = $name; 42e1d9dcc8SAndreas Gohr $this->data =& $data; 43e1d9dcc8SAndreas Gohr } 44e1d9dcc8SAndreas Gohr 45e1d9dcc8SAndreas Gohr /** 46e1d9dcc8SAndreas Gohr * @return string 47e1d9dcc8SAndreas Gohr */ 48e1d9dcc8SAndreas Gohr public function __toString() 49e1d9dcc8SAndreas Gohr { 50e1d9dcc8SAndreas Gohr return $this->name; 51e1d9dcc8SAndreas Gohr } 52e1d9dcc8SAndreas Gohr 53e1d9dcc8SAndreas Gohr /** 54091ad7bdSAndreas Gohr * advise all registered BEFORE handlers of this event 55e1d9dcc8SAndreas Gohr * 56e1d9dcc8SAndreas Gohr * if these methods are used by functions outside of this object, they must 57e1d9dcc8SAndreas Gohr * properly handle correct processing of any default action and issue an 58e1d9dcc8SAndreas Gohr * advise_after() signal. e.g. 59e1d9dcc8SAndreas Gohr * $evt = new dokuwiki\Plugin\Doku_Event(name, data); 60e1d9dcc8SAndreas Gohr * if ($evt->advise_before(canPreventDefault) { 61e1d9dcc8SAndreas Gohr * // default action code block 62e1d9dcc8SAndreas Gohr * } 63e1d9dcc8SAndreas Gohr * $evt->advise_after(); 64e1d9dcc8SAndreas Gohr * unset($evt); 65e1d9dcc8SAndreas Gohr * 66e1d9dcc8SAndreas Gohr * @param bool $enablePreventDefault 67091ad7bdSAndreas Gohr * @return bool results of processing the event, usually $this->runDefault 68e1d9dcc8SAndreas Gohr */ 69e1d9dcc8SAndreas Gohr public function advise_before($enablePreventDefault = true) 70e1d9dcc8SAndreas Gohr { 71e1d9dcc8SAndreas Gohr global $EVENT_HANDLER; 72e1d9dcc8SAndreas Gohr 73e1d9dcc8SAndreas Gohr $this->canPreventDefault = $enablePreventDefault; 7489614c82SAndreas Gohr if ($EVENT_HANDLER !== null) { 75e1d9dcc8SAndreas Gohr $EVENT_HANDLER->process_event($this, 'BEFORE'); 7689614c82SAndreas Gohr } else { 770ecde6ceSAndreas Gohr Logger::getInstance(Logger::LOG_DEBUG) 780ecde6ceSAndreas Gohr ->log($this->name . ':BEFORE event triggered before event system was initialized'); 7989614c82SAndreas Gohr } 80e1d9dcc8SAndreas Gohr 81091ad7bdSAndreas Gohr return (!$enablePreventDefault || $this->runDefault); 82e1d9dcc8SAndreas Gohr } 83e1d9dcc8SAndreas Gohr 84091ad7bdSAndreas Gohr /** 85091ad7bdSAndreas Gohr * advise all registered AFTER handlers of this event 86091ad7bdSAndreas Gohr * 87091ad7bdSAndreas Gohr * @param bool $enablePreventDefault 88091ad7bdSAndreas Gohr * @see advise_before() for details 89091ad7bdSAndreas Gohr */ 90e1d9dcc8SAndreas Gohr public function advise_after() 91e1d9dcc8SAndreas Gohr { 92e1d9dcc8SAndreas Gohr global $EVENT_HANDLER; 93e1d9dcc8SAndreas Gohr 94091ad7bdSAndreas Gohr $this->mayContinue = true; 9589614c82SAndreas Gohr 9689614c82SAndreas Gohr if ($EVENT_HANDLER !== null) { 97e1d9dcc8SAndreas Gohr $EVENT_HANDLER->process_event($this, 'AFTER'); 9889614c82SAndreas Gohr } else { 990ecde6ceSAndreas Gohr Logger::getInstance(Logger::LOG_DEBUG)-> 1000ecde6ceSAndreas Gohr log($this->name . ':AFTER event triggered before event system was initialized'); 10189614c82SAndreas Gohr } 102e1d9dcc8SAndreas Gohr } 103e1d9dcc8SAndreas Gohr 104e1d9dcc8SAndreas Gohr /** 105e1d9dcc8SAndreas Gohr * trigger 106e1d9dcc8SAndreas Gohr * 107e1d9dcc8SAndreas Gohr * - advise all registered (<event>_BEFORE) handlers that this event is about to take place 108e1d9dcc8SAndreas Gohr * - carry out the default action using $this->data based on $enablePrevent and 109e1d9dcc8SAndreas Gohr * $this->_default, all of which may have been modified by the event handlers. 110e1d9dcc8SAndreas Gohr * - advise all registered (<event>_AFTER) handlers that the event has taken place 111e1d9dcc8SAndreas Gohr * 112e1d9dcc8SAndreas Gohr * @param null|callable $action 113e1d9dcc8SAndreas Gohr * @param bool $enablePrevent 114e1d9dcc8SAndreas Gohr * @return mixed $event->results 115e1d9dcc8SAndreas Gohr * the value set by any <event>_before or <event> handlers if the default action is prevented 116e1d9dcc8SAndreas Gohr * or the results of the default action (as modified by <event>_after handlers) 117e1d9dcc8SAndreas Gohr * or NULL no action took place and no handler modified the value 118e1d9dcc8SAndreas Gohr */ 119e1d9dcc8SAndreas Gohr public function trigger($action = null, $enablePrevent = true) 120e1d9dcc8SAndreas Gohr { 121e1d9dcc8SAndreas Gohr 122e1d9dcc8SAndreas Gohr if (!is_callable($action)) { 123e1d9dcc8SAndreas Gohr $enablePrevent = false; 124091ad7bdSAndreas Gohr if ($action !== null) { 125e1d9dcc8SAndreas Gohr trigger_error( 126e1d9dcc8SAndreas Gohr 'The default action of ' . $this . 127e1d9dcc8SAndreas Gohr ' is not null but also not callable. Maybe the method is not public?', 128e1d9dcc8SAndreas Gohr E_USER_WARNING 129e1d9dcc8SAndreas Gohr ); 130e1d9dcc8SAndreas Gohr } 131e1d9dcc8SAndreas Gohr } 132e1d9dcc8SAndreas Gohr 133e1d9dcc8SAndreas Gohr if ($this->advise_before($enablePrevent) && is_callable($action)) { 1344352f974SAndreas Gohr $this->result = call_user_func_array($action, [&$this->data]); 135e1d9dcc8SAndreas Gohr } 136e1d9dcc8SAndreas Gohr 137e1d9dcc8SAndreas Gohr $this->advise_after(); 138e1d9dcc8SAndreas Gohr 139e1d9dcc8SAndreas Gohr return $this->result; 140e1d9dcc8SAndreas Gohr } 141e1d9dcc8SAndreas Gohr 142e1d9dcc8SAndreas Gohr /** 143e1d9dcc8SAndreas Gohr * stopPropagation 144e1d9dcc8SAndreas Gohr * 145e1d9dcc8SAndreas Gohr * stop any further processing of the event by event handlers 146e1d9dcc8SAndreas Gohr * this function does not prevent the default action taking place 147e1d9dcc8SAndreas Gohr */ 148e1d9dcc8SAndreas Gohr public function stopPropagation() 149e1d9dcc8SAndreas Gohr { 150091ad7bdSAndreas Gohr $this->mayContinue = false; 151e1d9dcc8SAndreas Gohr } 152e1d9dcc8SAndreas Gohr 153e1d9dcc8SAndreas Gohr /** 154e1d9dcc8SAndreas Gohr * may the event propagate to the next handler? 155e1d9dcc8SAndreas Gohr * 156e1d9dcc8SAndreas Gohr * @return bool 157e1d9dcc8SAndreas Gohr */ 158e1d9dcc8SAndreas Gohr public function mayPropagate() 159e1d9dcc8SAndreas Gohr { 160091ad7bdSAndreas Gohr return $this->mayContinue; 161e1d9dcc8SAndreas Gohr } 162e1d9dcc8SAndreas Gohr 163e1d9dcc8SAndreas Gohr /** 164e1d9dcc8SAndreas Gohr * preventDefault 165e1d9dcc8SAndreas Gohr * 166e1d9dcc8SAndreas Gohr * prevent the default action taking place 167e1d9dcc8SAndreas Gohr */ 168e1d9dcc8SAndreas Gohr public function preventDefault() 169e1d9dcc8SAndreas Gohr { 170091ad7bdSAndreas Gohr $this->runDefault = false; 171e1d9dcc8SAndreas Gohr } 172e1d9dcc8SAndreas Gohr 173e1d9dcc8SAndreas Gohr /** 174e1d9dcc8SAndreas Gohr * should the default action be executed? 175e1d9dcc8SAndreas Gohr * 176e1d9dcc8SAndreas Gohr * @return bool 177e1d9dcc8SAndreas Gohr */ 178e1d9dcc8SAndreas Gohr public function mayRunDefault() 179e1d9dcc8SAndreas Gohr { 180091ad7bdSAndreas Gohr return $this->runDefault; 181e1d9dcc8SAndreas Gohr } 182cbb44eabSAndreas Gohr 183cbb44eabSAndreas Gohr /** 184cbb44eabSAndreas Gohr * Convenience method to trigger an event 185cbb44eabSAndreas Gohr * 186cbb44eabSAndreas Gohr * Creates, triggers and destroys an event in one go 187cbb44eabSAndreas Gohr * 188cbb44eabSAndreas Gohr * @param string $name name for the event 189cbb44eabSAndreas Gohr * @param mixed $data event data 190cbb44eabSAndreas Gohr * @param callable $action (optional, default=NULL) default action, a php callback function 191cbb44eabSAndreas Gohr * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action 192cbb44eabSAndreas Gohr * 193cbb44eabSAndreas Gohr * @return mixed the event results value after all event processing is complete 194cbb44eabSAndreas Gohr * by default this is the return value of the default action however 195cbb44eabSAndreas Gohr * it can be set or modified by event handler hooks 196cbb44eabSAndreas Gohr */ 197fe15e2c0SAndreas Gohr public static function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true) 198091ad7bdSAndreas Gohr { 199cbb44eabSAndreas Gohr $evt = new Event($name, $data); 200cbb44eabSAndreas Gohr return $evt->trigger($action, $canPreventDefault); 201cbb44eabSAndreas Gohr } 202e1d9dcc8SAndreas Gohr} 203