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