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