xref: /dokuwiki/inc/Extension/Event.php (revision 8cbc5ee84fe788597ede5266255a74af6da47555)
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            if (is_array($action)) {
130                list($obj, $method) = $action;
131                $this->result = $obj->$method($this->data);
132            } else {
133                $this->result = $action($this->data);
134            }
135        }
136
137        $this->advise_after();
138
139        return $this->result;
140    }
141
142    /**
143     * stopPropagation
144     *
145     * stop any further processing of the event by event handlers
146     * this function does not prevent the default action taking place
147     */
148    public function stopPropagation()
149    {
150        $this->mayContinue = false;
151    }
152
153    /**
154     * may the event propagate to the next handler?
155     *
156     * @return bool
157     */
158    public function mayPropagate()
159    {
160        return $this->mayContinue;
161    }
162
163    /**
164     * preventDefault
165     *
166     * prevent the default action taking place
167     */
168    public function preventDefault()
169    {
170        $this->runDefault = false;
171    }
172
173    /**
174     * should the default action be executed?
175     *
176     * @return bool
177     */
178    public function mayRunDefault()
179    {
180        return $this->runDefault;
181    }
182
183    /**
184     * Convenience method to trigger an event
185     *
186     * Creates, triggers and destroys an event in one go
187     *
188     * @param string $name name for the event
189     * @param mixed $data event data
190     * @param callable $action (optional, default=NULL) default action, a php callback function
191     * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action
192     *
193     * @return mixed                        the event results value after all event processing is complete
194     *                                      by default this is the return value of the default action however
195     *                                      it can be set or modified by event handler hooks
196     */
197    static public function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true)
198    {
199        $evt = new Event($name, $data);
200        return $evt->trigger($action, $canPreventDefault);
201    }
202}
203