xref: /dokuwiki/inc/Extension/Event.php (revision 4352f9743c9435eb23a267b4ac253a717102fec7)
1e1d9dcc8SAndreas Gohr<?php
2091ad7bdSAndreas Gohr// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
3e1d9dcc8SAndreas Gohr
4e1d9dcc8SAndreas Gohrnamespace dokuwiki\Extension;
5e1d9dcc8SAndreas Gohr
6e1d9dcc8SAndreas Gohr/**
7e1d9dcc8SAndreas Gohr * The Action plugin event
8e1d9dcc8SAndreas Gohr */
9e1d9dcc8SAndreas Gohrclass Event
10e1d9dcc8SAndreas Gohr{
11091ad7bdSAndreas Gohr    /** @var string READONLY  event name, objects must register against this name to see the event */
12091ad7bdSAndreas Gohr    public $name = '';
13091ad7bdSAndreas Gohr    /** @var mixed|null READWRITE data relevant to the event, no standardised format, refer to event docs */
14091ad7bdSAndreas Gohr    public $data = null;
15091ad7bdSAndreas Gohr    /**
16091ad7bdSAndreas Gohr     * @var mixed|null READWRITE the results of the event action, only relevant in "_AFTER" advise
17091ad7bdSAndreas Gohr     *                 event handlers may modify this if they are preventing the default action
18091ad7bdSAndreas Gohr     *                 to provide the after event handlers with event results
19091ad7bdSAndreas Gohr     */
20091ad7bdSAndreas Gohr    public $result = null;
21091ad7bdSAndreas Gohr    /** @var bool READONLY  if true, event handlers can prevent the events default action */
22091ad7bdSAndreas Gohr    public $canPreventDefault = true;
23e1d9dcc8SAndreas Gohr
24091ad7bdSAndreas Gohr    /** @var bool whether or not to carry out the default action associated with the event */
25091ad7bdSAndreas Gohr    protected $runDefault = true;
26091ad7bdSAndreas Gohr    /** @var bool whether or not to continue propagating the event to other handlers */
27091ad7bdSAndreas Gohr    protected $mayContinue = true;
28e1d9dcc8SAndreas Gohr
29e1d9dcc8SAndreas Gohr    /**
30e1d9dcc8SAndreas Gohr     * event constructor
31e1d9dcc8SAndreas Gohr     *
32e1d9dcc8SAndreas Gohr     * @param string $name
33e1d9dcc8SAndreas Gohr     * @param mixed $data
34e1d9dcc8SAndreas Gohr     */
35e1d9dcc8SAndreas Gohr    public function __construct($name, &$data)
36e1d9dcc8SAndreas Gohr    {
37e1d9dcc8SAndreas Gohr
38e1d9dcc8SAndreas Gohr        $this->name = $name;
39e1d9dcc8SAndreas Gohr        $this->data =& $data;
40e1d9dcc8SAndreas Gohr    }
41e1d9dcc8SAndreas Gohr
42e1d9dcc8SAndreas Gohr    /**
43e1d9dcc8SAndreas Gohr     * @return string
44e1d9dcc8SAndreas Gohr     */
45e1d9dcc8SAndreas Gohr    public function __toString()
46e1d9dcc8SAndreas Gohr    {
47e1d9dcc8SAndreas Gohr        return $this->name;
48e1d9dcc8SAndreas Gohr    }
49e1d9dcc8SAndreas Gohr
50e1d9dcc8SAndreas Gohr    /**
51091ad7bdSAndreas Gohr     * advise all registered BEFORE handlers of this event
52e1d9dcc8SAndreas Gohr     *
53e1d9dcc8SAndreas Gohr     * if these methods are used by functions outside of this object, they must
54e1d9dcc8SAndreas Gohr     * properly handle correct processing of any default action and issue an
55e1d9dcc8SAndreas Gohr     * advise_after() signal. e.g.
56e1d9dcc8SAndreas Gohr     *    $evt = new dokuwiki\Plugin\Doku_Event(name, data);
57e1d9dcc8SAndreas Gohr     *    if ($evt->advise_before(canPreventDefault) {
58e1d9dcc8SAndreas Gohr     *      // default action code block
59e1d9dcc8SAndreas Gohr     *    }
60e1d9dcc8SAndreas Gohr     *    $evt->advise_after();
61e1d9dcc8SAndreas Gohr     *    unset($evt);
62e1d9dcc8SAndreas Gohr     *
63e1d9dcc8SAndreas Gohr     * @param bool $enablePreventDefault
64091ad7bdSAndreas Gohr     * @return bool results of processing the event, usually $this->runDefault
65e1d9dcc8SAndreas Gohr     */
66e1d9dcc8SAndreas Gohr    public function advise_before($enablePreventDefault = true)
67e1d9dcc8SAndreas Gohr    {
68e1d9dcc8SAndreas Gohr        global $EVENT_HANDLER;
69e1d9dcc8SAndreas Gohr
70e1d9dcc8SAndreas Gohr        $this->canPreventDefault = $enablePreventDefault;
7189614c82SAndreas Gohr        if ($EVENT_HANDLER !== null) {
72e1d9dcc8SAndreas Gohr            $EVENT_HANDLER->process_event($this, 'BEFORE');
7389614c82SAndreas Gohr        } else {
7489614c82SAndreas Gohr            dbglog($this->name . ':BEFORE event triggered before event system was initialized');
7589614c82SAndreas Gohr        }
76e1d9dcc8SAndreas Gohr
77091ad7bdSAndreas Gohr        return (!$enablePreventDefault || $this->runDefault);
78e1d9dcc8SAndreas Gohr    }
79e1d9dcc8SAndreas Gohr
80091ad7bdSAndreas Gohr    /**
81091ad7bdSAndreas Gohr     * advise all registered AFTER handlers of this event
82091ad7bdSAndreas Gohr     *
83091ad7bdSAndreas Gohr     * @param bool $enablePreventDefault
84091ad7bdSAndreas Gohr     * @see advise_before() for details
85091ad7bdSAndreas Gohr     */
86e1d9dcc8SAndreas Gohr    public function advise_after()
87e1d9dcc8SAndreas Gohr    {
88e1d9dcc8SAndreas Gohr        global $EVENT_HANDLER;
89e1d9dcc8SAndreas Gohr
90091ad7bdSAndreas Gohr        $this->mayContinue = true;
9189614c82SAndreas Gohr
9289614c82SAndreas Gohr        if ($EVENT_HANDLER !== null) {
93e1d9dcc8SAndreas Gohr            $EVENT_HANDLER->process_event($this, 'AFTER');
9489614c82SAndreas Gohr        } else {
9589614c82SAndreas Gohr            dbglog($this->name . ':AFTER event triggered before event system was initialized');
9689614c82SAndreas Gohr        }
97e1d9dcc8SAndreas Gohr    }
98e1d9dcc8SAndreas Gohr
99e1d9dcc8SAndreas Gohr    /**
100e1d9dcc8SAndreas Gohr     * trigger
101e1d9dcc8SAndreas Gohr     *
102e1d9dcc8SAndreas Gohr     * - advise all registered (<event>_BEFORE) handlers that this event is about to take place
103e1d9dcc8SAndreas Gohr     * - carry out the default action using $this->data based on $enablePrevent and
104e1d9dcc8SAndreas Gohr     *   $this->_default, all of which may have been modified by the event handlers.
105e1d9dcc8SAndreas Gohr     * - advise all registered (<event>_AFTER) handlers that the event has taken place
106e1d9dcc8SAndreas Gohr     *
107e1d9dcc8SAndreas Gohr     * @param null|callable $action
108e1d9dcc8SAndreas Gohr     * @param bool $enablePrevent
109e1d9dcc8SAndreas Gohr     * @return  mixed $event->results
110e1d9dcc8SAndreas Gohr     *          the value set by any <event>_before or <event> handlers if the default action is prevented
111e1d9dcc8SAndreas Gohr     *          or the results of the default action (as modified by <event>_after handlers)
112e1d9dcc8SAndreas Gohr     *          or NULL no action took place and no handler modified the value
113e1d9dcc8SAndreas Gohr     */
114e1d9dcc8SAndreas Gohr    public function trigger($action = null, $enablePrevent = true)
115e1d9dcc8SAndreas Gohr    {
116e1d9dcc8SAndreas Gohr
117e1d9dcc8SAndreas Gohr        if (!is_callable($action)) {
118e1d9dcc8SAndreas Gohr            $enablePrevent = false;
119091ad7bdSAndreas Gohr            if ($action !== null) {
120e1d9dcc8SAndreas Gohr                trigger_error(
121e1d9dcc8SAndreas Gohr                    'The default action of ' . $this .
122e1d9dcc8SAndreas Gohr                    ' is not null but also not callable. Maybe the method is not public?',
123e1d9dcc8SAndreas Gohr                    E_USER_WARNING
124e1d9dcc8SAndreas Gohr                );
125e1d9dcc8SAndreas Gohr            }
126e1d9dcc8SAndreas Gohr        }
127e1d9dcc8SAndreas Gohr
128e1d9dcc8SAndreas Gohr        if ($this->advise_before($enablePrevent) && is_callable($action)) {
129*4352f974SAndreas Gohr            $this->result = call_user_func_array($action, [&$this->data]);
130e1d9dcc8SAndreas Gohr        }
131e1d9dcc8SAndreas Gohr
132e1d9dcc8SAndreas Gohr        $this->advise_after();
133e1d9dcc8SAndreas Gohr
134e1d9dcc8SAndreas Gohr        return $this->result;
135e1d9dcc8SAndreas Gohr    }
136e1d9dcc8SAndreas Gohr
137e1d9dcc8SAndreas Gohr    /**
138e1d9dcc8SAndreas Gohr     * stopPropagation
139e1d9dcc8SAndreas Gohr     *
140e1d9dcc8SAndreas Gohr     * stop any further processing of the event by event handlers
141e1d9dcc8SAndreas Gohr     * this function does not prevent the default action taking place
142e1d9dcc8SAndreas Gohr     */
143e1d9dcc8SAndreas Gohr    public function stopPropagation()
144e1d9dcc8SAndreas Gohr    {
145091ad7bdSAndreas Gohr        $this->mayContinue = false;
146e1d9dcc8SAndreas Gohr    }
147e1d9dcc8SAndreas Gohr
148e1d9dcc8SAndreas Gohr    /**
149e1d9dcc8SAndreas Gohr     * may the event propagate to the next handler?
150e1d9dcc8SAndreas Gohr     *
151e1d9dcc8SAndreas Gohr     * @return bool
152e1d9dcc8SAndreas Gohr     */
153e1d9dcc8SAndreas Gohr    public function mayPropagate()
154e1d9dcc8SAndreas Gohr    {
155091ad7bdSAndreas Gohr        return $this->mayContinue;
156e1d9dcc8SAndreas Gohr    }
157e1d9dcc8SAndreas Gohr
158e1d9dcc8SAndreas Gohr    /**
159e1d9dcc8SAndreas Gohr     * preventDefault
160e1d9dcc8SAndreas Gohr     *
161e1d9dcc8SAndreas Gohr     * prevent the default action taking place
162e1d9dcc8SAndreas Gohr     */
163e1d9dcc8SAndreas Gohr    public function preventDefault()
164e1d9dcc8SAndreas Gohr    {
165091ad7bdSAndreas Gohr        $this->runDefault = false;
166e1d9dcc8SAndreas Gohr    }
167e1d9dcc8SAndreas Gohr
168e1d9dcc8SAndreas Gohr    /**
169e1d9dcc8SAndreas Gohr     * should the default action be executed?
170e1d9dcc8SAndreas Gohr     *
171e1d9dcc8SAndreas Gohr     * @return bool
172e1d9dcc8SAndreas Gohr     */
173e1d9dcc8SAndreas Gohr    public function mayRunDefault()
174e1d9dcc8SAndreas Gohr    {
175091ad7bdSAndreas Gohr        return $this->runDefault;
176e1d9dcc8SAndreas Gohr    }
177cbb44eabSAndreas Gohr
178cbb44eabSAndreas Gohr    /**
179cbb44eabSAndreas Gohr     * Convenience method to trigger an event
180cbb44eabSAndreas Gohr     *
181cbb44eabSAndreas Gohr     * Creates, triggers and destroys an event in one go
182cbb44eabSAndreas Gohr     *
183cbb44eabSAndreas Gohr     * @param string $name name for the event
184cbb44eabSAndreas Gohr     * @param mixed $data event data
185cbb44eabSAndreas Gohr     * @param callable $action (optional, default=NULL) default action, a php callback function
186cbb44eabSAndreas Gohr     * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action
187cbb44eabSAndreas Gohr     *
188cbb44eabSAndreas Gohr     * @return mixed                        the event results value after all event processing is complete
189cbb44eabSAndreas Gohr     *                                      by default this is the return value of the default action however
190cbb44eabSAndreas Gohr     *                                      it can be set or modified by event handler hooks
191cbb44eabSAndreas Gohr     */
192091ad7bdSAndreas Gohr    static public function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true)
193091ad7bdSAndreas Gohr    {
194cbb44eabSAndreas Gohr        $evt = new Event($name, $data);
195cbb44eabSAndreas Gohr        return $evt->trigger($action, $canPreventDefault);
196cbb44eabSAndreas Gohr    }
197e1d9dcc8SAndreas Gohr}
198