xref: /dokuwiki/inc/Extension/Event.php (revision d4f83172d9533c4d84f450fe22ef630816b21d75)
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