xref: /dokuwiki/inc/Extension/Event.php (revision fe15e2c063a38f65804c55e581c72b96ac36edf7)
1e1d9dcc8SAndreas Gohr<?php
2091ad7bdSAndreas Gohr// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
3e1d9dcc8SAndreas Gohr
4e1d9dcc8SAndreas Gohrnamespace dokuwiki\Extension;
5e1d9dcc8SAndreas Gohr
60ecde6ceSAndreas Gohruse dokuwiki\Logger;
70ecde6ceSAndreas Gohr
8e1d9dcc8SAndreas Gohr/**
9e1d9dcc8SAndreas Gohr * The Action plugin event
10e1d9dcc8SAndreas Gohr */
11e1d9dcc8SAndreas Gohrclass Event
12e1d9dcc8SAndreas Gohr{
13091ad7bdSAndreas Gohr    /** @var string READONLY  event name, objects must register against this name to see the event */
14091ad7bdSAndreas Gohr    public $name = '';
15091ad7bdSAndreas Gohr    /** @var mixed|null READWRITE data relevant to the event, no standardised format, refer to event docs */
161490c177SAndreas Gohr    public $data;
17091ad7bdSAndreas Gohr    /**
18091ad7bdSAndreas Gohr     * @var mixed|null READWRITE the results of the event action, only relevant in "_AFTER" advise
19091ad7bdSAndreas Gohr     *                 event handlers may modify this if they are preventing the default action
20091ad7bdSAndreas Gohr     *                 to provide the after event handlers with event results
21091ad7bdSAndreas Gohr     */
221490c177SAndreas Gohr    public $result;
23091ad7bdSAndreas Gohr    /** @var bool READONLY  if true, event handlers can prevent the events default action */
24091ad7bdSAndreas Gohr    public $canPreventDefault = true;
25e1d9dcc8SAndreas Gohr
26091ad7bdSAndreas Gohr    /** @var bool whether or not to carry out the default action associated with the event */
27091ad7bdSAndreas Gohr    protected $runDefault = true;
28091ad7bdSAndreas Gohr    /** @var bool whether or not to continue propagating the event to other handlers */
29091ad7bdSAndreas Gohr    protected $mayContinue = true;
30e1d9dcc8SAndreas Gohr
31e1d9dcc8SAndreas Gohr    /**
32e1d9dcc8SAndreas Gohr     * event constructor
33e1d9dcc8SAndreas Gohr     *
34e1d9dcc8SAndreas Gohr     * @param string $name
35e1d9dcc8SAndreas Gohr     * @param mixed $data
36e1d9dcc8SAndreas Gohr     */
37e1d9dcc8SAndreas Gohr    public function __construct($name, &$data)
38e1d9dcc8SAndreas Gohr    {
39e1d9dcc8SAndreas Gohr
40e1d9dcc8SAndreas Gohr        $this->name = $name;
41e1d9dcc8SAndreas Gohr        $this->data =& $data;
42e1d9dcc8SAndreas Gohr    }
43e1d9dcc8SAndreas Gohr
44e1d9dcc8SAndreas Gohr    /**
45e1d9dcc8SAndreas Gohr     * @return string
46e1d9dcc8SAndreas Gohr     */
47e1d9dcc8SAndreas Gohr    public function __toString()
48e1d9dcc8SAndreas Gohr    {
49e1d9dcc8SAndreas Gohr        return $this->name;
50e1d9dcc8SAndreas Gohr    }
51e1d9dcc8SAndreas Gohr
52e1d9dcc8SAndreas Gohr    /**
53091ad7bdSAndreas Gohr     * advise all registered BEFORE handlers of this event
54e1d9dcc8SAndreas Gohr     *
55e1d9dcc8SAndreas Gohr     * if these methods are used by functions outside of this object, they must
56e1d9dcc8SAndreas Gohr     * properly handle correct processing of any default action and issue an
57e1d9dcc8SAndreas Gohr     * advise_after() signal. e.g.
58e1d9dcc8SAndreas Gohr     *    $evt = new dokuwiki\Plugin\Doku_Event(name, data);
59e1d9dcc8SAndreas Gohr     *    if ($evt->advise_before(canPreventDefault) {
60e1d9dcc8SAndreas Gohr     *      // default action code block
61e1d9dcc8SAndreas Gohr     *    }
62e1d9dcc8SAndreas Gohr     *    $evt->advise_after();
63e1d9dcc8SAndreas Gohr     *    unset($evt);
64e1d9dcc8SAndreas Gohr     *
65e1d9dcc8SAndreas Gohr     * @param bool $enablePreventDefault
66091ad7bdSAndreas Gohr     * @return bool results of processing the event, usually $this->runDefault
67e1d9dcc8SAndreas Gohr     */
68e1d9dcc8SAndreas Gohr    public function advise_before($enablePreventDefault = true)
69e1d9dcc8SAndreas Gohr    {
70e1d9dcc8SAndreas Gohr        global $EVENT_HANDLER;
71e1d9dcc8SAndreas Gohr
72e1d9dcc8SAndreas Gohr        $this->canPreventDefault = $enablePreventDefault;
7389614c82SAndreas Gohr        if ($EVENT_HANDLER !== null) {
74e1d9dcc8SAndreas Gohr            $EVENT_HANDLER->process_event($this, 'BEFORE');
7589614c82SAndreas Gohr        } else {
760ecde6ceSAndreas Gohr            Logger::getInstance(Logger::LOG_DEBUG)
770ecde6ceSAndreas Gohr                  ->log($this->name . ':BEFORE event triggered before event system was initialized');
7889614c82SAndreas Gohr        }
79e1d9dcc8SAndreas Gohr
80091ad7bdSAndreas Gohr        return (!$enablePreventDefault || $this->runDefault);
81e1d9dcc8SAndreas Gohr    }
82e1d9dcc8SAndreas Gohr
83091ad7bdSAndreas Gohr    /**
84091ad7bdSAndreas Gohr     * advise all registered AFTER handlers of this event
85091ad7bdSAndreas Gohr     *
86091ad7bdSAndreas Gohr     * @param bool $enablePreventDefault
87091ad7bdSAndreas Gohr     * @see advise_before() for details
88091ad7bdSAndreas Gohr     */
89e1d9dcc8SAndreas Gohr    public function advise_after()
90e1d9dcc8SAndreas Gohr    {
91e1d9dcc8SAndreas Gohr        global $EVENT_HANDLER;
92e1d9dcc8SAndreas Gohr
93091ad7bdSAndreas Gohr        $this->mayContinue = true;
9489614c82SAndreas Gohr
9589614c82SAndreas Gohr        if ($EVENT_HANDLER !== null) {
96e1d9dcc8SAndreas Gohr            $EVENT_HANDLER->process_event($this, 'AFTER');
9789614c82SAndreas Gohr        } else {
980ecde6ceSAndreas Gohr            Logger::getInstance(Logger::LOG_DEBUG)->
990ecde6ceSAndreas Gohr                log($this->name . ':AFTER event triggered before event system was initialized');
10089614c82SAndreas Gohr        }
101e1d9dcc8SAndreas Gohr    }
102e1d9dcc8SAndreas Gohr
103e1d9dcc8SAndreas Gohr    /**
104e1d9dcc8SAndreas Gohr     * trigger
105e1d9dcc8SAndreas Gohr     *
106e1d9dcc8SAndreas Gohr     * - advise all registered (<event>_BEFORE) handlers that this event is about to take place
107e1d9dcc8SAndreas Gohr     * - carry out the default action using $this->data based on $enablePrevent and
108e1d9dcc8SAndreas Gohr     *   $this->_default, all of which may have been modified by the event handlers.
109e1d9dcc8SAndreas Gohr     * - advise all registered (<event>_AFTER) handlers that the event has taken place
110e1d9dcc8SAndreas Gohr     *
111e1d9dcc8SAndreas Gohr     * @param null|callable $action
112e1d9dcc8SAndreas Gohr     * @param bool $enablePrevent
113e1d9dcc8SAndreas Gohr     * @return  mixed $event->results
114e1d9dcc8SAndreas Gohr     *          the value set by any <event>_before or <event> handlers if the default action is prevented
115e1d9dcc8SAndreas Gohr     *          or the results of the default action (as modified by <event>_after handlers)
116e1d9dcc8SAndreas Gohr     *          or NULL no action took place and no handler modified the value
117e1d9dcc8SAndreas Gohr     */
118e1d9dcc8SAndreas Gohr    public function trigger($action = null, $enablePrevent = true)
119e1d9dcc8SAndreas Gohr    {
120e1d9dcc8SAndreas Gohr
121e1d9dcc8SAndreas Gohr        if (!is_callable($action)) {
122e1d9dcc8SAndreas Gohr            $enablePrevent = false;
123091ad7bdSAndreas Gohr            if ($action !== null) {
124e1d9dcc8SAndreas Gohr                trigger_error(
125e1d9dcc8SAndreas Gohr                    'The default action of ' . $this .
126e1d9dcc8SAndreas Gohr                    ' is not null but also not callable. Maybe the method is not public?',
127e1d9dcc8SAndreas Gohr                    E_USER_WARNING
128e1d9dcc8SAndreas Gohr                );
129e1d9dcc8SAndreas Gohr            }
130e1d9dcc8SAndreas Gohr        }
131e1d9dcc8SAndreas Gohr
132e1d9dcc8SAndreas Gohr        if ($this->advise_before($enablePrevent) && is_callable($action)) {
1334352f974SAndreas Gohr            $this->result = call_user_func_array($action, [&$this->data]);
134e1d9dcc8SAndreas Gohr        }
135e1d9dcc8SAndreas Gohr
136e1d9dcc8SAndreas Gohr        $this->advise_after();
137e1d9dcc8SAndreas Gohr
138e1d9dcc8SAndreas Gohr        return $this->result;
139e1d9dcc8SAndreas Gohr    }
140e1d9dcc8SAndreas Gohr
141e1d9dcc8SAndreas Gohr    /**
142e1d9dcc8SAndreas Gohr     * stopPropagation
143e1d9dcc8SAndreas Gohr     *
144e1d9dcc8SAndreas Gohr     * stop any further processing of the event by event handlers
145e1d9dcc8SAndreas Gohr     * this function does not prevent the default action taking place
146e1d9dcc8SAndreas Gohr     */
147e1d9dcc8SAndreas Gohr    public function stopPropagation()
148e1d9dcc8SAndreas Gohr    {
149091ad7bdSAndreas Gohr        $this->mayContinue = false;
150e1d9dcc8SAndreas Gohr    }
151e1d9dcc8SAndreas Gohr
152e1d9dcc8SAndreas Gohr    /**
153e1d9dcc8SAndreas Gohr     * may the event propagate to the next handler?
154e1d9dcc8SAndreas Gohr     *
155e1d9dcc8SAndreas Gohr     * @return bool
156e1d9dcc8SAndreas Gohr     */
157e1d9dcc8SAndreas Gohr    public function mayPropagate()
158e1d9dcc8SAndreas Gohr    {
159091ad7bdSAndreas Gohr        return $this->mayContinue;
160e1d9dcc8SAndreas Gohr    }
161e1d9dcc8SAndreas Gohr
162e1d9dcc8SAndreas Gohr    /**
163e1d9dcc8SAndreas Gohr     * preventDefault
164e1d9dcc8SAndreas Gohr     *
165e1d9dcc8SAndreas Gohr     * prevent the default action taking place
166e1d9dcc8SAndreas Gohr     */
167e1d9dcc8SAndreas Gohr    public function preventDefault()
168e1d9dcc8SAndreas Gohr    {
169091ad7bdSAndreas Gohr        $this->runDefault = false;
170e1d9dcc8SAndreas Gohr    }
171e1d9dcc8SAndreas Gohr
172e1d9dcc8SAndreas Gohr    /**
173e1d9dcc8SAndreas Gohr     * should the default action be executed?
174e1d9dcc8SAndreas Gohr     *
175e1d9dcc8SAndreas Gohr     * @return bool
176e1d9dcc8SAndreas Gohr     */
177e1d9dcc8SAndreas Gohr    public function mayRunDefault()
178e1d9dcc8SAndreas Gohr    {
179091ad7bdSAndreas Gohr        return $this->runDefault;
180e1d9dcc8SAndreas Gohr    }
181cbb44eabSAndreas Gohr
182cbb44eabSAndreas Gohr    /**
183cbb44eabSAndreas Gohr     * Convenience method to trigger an event
184cbb44eabSAndreas Gohr     *
185cbb44eabSAndreas Gohr     * Creates, triggers and destroys an event in one go
186cbb44eabSAndreas Gohr     *
187cbb44eabSAndreas Gohr     * @param string $name name for the event
188cbb44eabSAndreas Gohr     * @param mixed $data event data
189cbb44eabSAndreas Gohr     * @param callable $action (optional, default=NULL) default action, a php callback function
190cbb44eabSAndreas Gohr     * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action
191cbb44eabSAndreas Gohr     *
192cbb44eabSAndreas Gohr     * @return mixed                        the event results value after all event processing is complete
193cbb44eabSAndreas Gohr     *                                      by default this is the return value of the default action however
194cbb44eabSAndreas Gohr     *                                      it can be set or modified by event handler hooks
195cbb44eabSAndreas Gohr     */
196*fe15e2c0SAndreas Gohr    public static function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true)
197091ad7bdSAndreas Gohr    {
198cbb44eabSAndreas Gohr        $evt = new Event($name, $data);
199cbb44eabSAndreas Gohr        return $evt->trigger($action, $canPreventDefault);
200cbb44eabSAndreas Gohr    }
201e1d9dcc8SAndreas Gohr}
202