xref: /dokuwiki/inc/Extension/Event.php (revision 091ad7bd4cdbf6a629b100911b6fe6cd98226867)
1e1d9dcc8SAndreas Gohr<?php
2*091ad7bdSAndreas 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{
11*091ad7bdSAndreas Gohr    /** @var string READONLY  event name, objects must register against this name to see the event */
12*091ad7bdSAndreas Gohr    public $name = '';
13*091ad7bdSAndreas Gohr    /** @var mixed|null READWRITE data relevant to the event, no standardised format, refer to event docs */
14*091ad7bdSAndreas Gohr    public $data = null;
15*091ad7bdSAndreas Gohr    /**
16*091ad7bdSAndreas Gohr     * @var mixed|null READWRITE the results of the event action, only relevant in "_AFTER" advise
17*091ad7bdSAndreas Gohr     *                 event handlers may modify this if they are preventing the default action
18*091ad7bdSAndreas Gohr     *                 to provide the after event handlers with event results
19*091ad7bdSAndreas Gohr     */
20*091ad7bdSAndreas Gohr    public $result = null;
21*091ad7bdSAndreas Gohr    /** @var bool READONLY  if true, event handlers can prevent the events default action */
22*091ad7bdSAndreas Gohr    public $canPreventDefault = true;
23e1d9dcc8SAndreas Gohr
24*091ad7bdSAndreas Gohr    /** @var bool whether or not to carry out the default action associated with the event */
25*091ad7bdSAndreas Gohr    protected $runDefault = true;
26*091ad7bdSAndreas Gohr    /** @var bool whether or not to continue propagating the event to other handlers */
27*091ad7bdSAndreas 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    /**
51*091ad7bdSAndreas 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
64*091ad7bdSAndreas 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
77*091ad7bdSAndreas Gohr        return (!$enablePreventDefault || $this->runDefault);
78e1d9dcc8SAndreas Gohr    }
79e1d9dcc8SAndreas Gohr
80*091ad7bdSAndreas Gohr    /**
81*091ad7bdSAndreas Gohr     * advise all registered AFTER handlers of this event
82*091ad7bdSAndreas Gohr     *
83*091ad7bdSAndreas Gohr     * @param bool $enablePreventDefault
84*091ad7bdSAndreas Gohr     * @see advise_before() for details
85*091ad7bdSAndreas Gohr     */
86e1d9dcc8SAndreas Gohr    public function advise_after()
87e1d9dcc8SAndreas Gohr    {
88e1d9dcc8SAndreas Gohr        global $EVENT_HANDLER;
89e1d9dcc8SAndreas Gohr
90*091ad7bdSAndreas 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;
119*091ad7bdSAndreas 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)) {
129e1d9dcc8SAndreas Gohr            if (is_array($action)) {
130e1d9dcc8SAndreas Gohr                list($obj, $method) = $action;
131e1d9dcc8SAndreas Gohr                $this->result = $obj->$method($this->data);
132e1d9dcc8SAndreas Gohr            } else {
133e1d9dcc8SAndreas Gohr                $this->result = $action($this->data);
134e1d9dcc8SAndreas Gohr            }
135e1d9dcc8SAndreas Gohr        }
136e1d9dcc8SAndreas Gohr
137e1d9dcc8SAndreas Gohr        $this->advise_after();
138e1d9dcc8SAndreas Gohr
139e1d9dcc8SAndreas Gohr        return $this->result;
140e1d9dcc8SAndreas Gohr    }
141e1d9dcc8SAndreas Gohr
142e1d9dcc8SAndreas Gohr    /**
143e1d9dcc8SAndreas Gohr     * stopPropagation
144e1d9dcc8SAndreas Gohr     *
145e1d9dcc8SAndreas Gohr     * stop any further processing of the event by event handlers
146e1d9dcc8SAndreas Gohr     * this function does not prevent the default action taking place
147e1d9dcc8SAndreas Gohr     */
148e1d9dcc8SAndreas Gohr    public function stopPropagation()
149e1d9dcc8SAndreas Gohr    {
150*091ad7bdSAndreas Gohr        $this->mayContinue = false;
151e1d9dcc8SAndreas Gohr    }
152e1d9dcc8SAndreas Gohr
153e1d9dcc8SAndreas Gohr    /**
154e1d9dcc8SAndreas Gohr     * may the event propagate to the next handler?
155e1d9dcc8SAndreas Gohr     *
156e1d9dcc8SAndreas Gohr     * @return bool
157e1d9dcc8SAndreas Gohr     */
158e1d9dcc8SAndreas Gohr    public function mayPropagate()
159e1d9dcc8SAndreas Gohr    {
160*091ad7bdSAndreas Gohr        return $this->mayContinue;
161e1d9dcc8SAndreas Gohr    }
162e1d9dcc8SAndreas Gohr
163e1d9dcc8SAndreas Gohr    /**
164e1d9dcc8SAndreas Gohr     * preventDefault
165e1d9dcc8SAndreas Gohr     *
166e1d9dcc8SAndreas Gohr     * prevent the default action taking place
167e1d9dcc8SAndreas Gohr     */
168e1d9dcc8SAndreas Gohr    public function preventDefault()
169e1d9dcc8SAndreas Gohr    {
170*091ad7bdSAndreas Gohr        $this->runDefault = false;
171e1d9dcc8SAndreas Gohr    }
172e1d9dcc8SAndreas Gohr
173e1d9dcc8SAndreas Gohr    /**
174e1d9dcc8SAndreas Gohr     * should the default action be executed?
175e1d9dcc8SAndreas Gohr     *
176e1d9dcc8SAndreas Gohr     * @return bool
177e1d9dcc8SAndreas Gohr     */
178e1d9dcc8SAndreas Gohr    public function mayRunDefault()
179e1d9dcc8SAndreas Gohr    {
180*091ad7bdSAndreas Gohr        return $this->runDefault;
181e1d9dcc8SAndreas Gohr    }
182cbb44eabSAndreas Gohr
183cbb44eabSAndreas Gohr    /**
184cbb44eabSAndreas Gohr     * Convenience method to trigger an event
185cbb44eabSAndreas Gohr     *
186cbb44eabSAndreas Gohr     * Creates, triggers and destroys an event in one go
187cbb44eabSAndreas Gohr     *
188cbb44eabSAndreas Gohr     * @param string $name name for the event
189cbb44eabSAndreas Gohr     * @param mixed $data event data
190cbb44eabSAndreas Gohr     * @param callable $action (optional, default=NULL) default action, a php callback function
191cbb44eabSAndreas Gohr     * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action
192cbb44eabSAndreas Gohr     *
193cbb44eabSAndreas Gohr     * @return mixed                        the event results value after all event processing is complete
194cbb44eabSAndreas Gohr     *                                      by default this is the return value of the default action however
195cbb44eabSAndreas Gohr     *                                      it can be set or modified by event handler hooks
196cbb44eabSAndreas Gohr     */
197*091ad7bdSAndreas Gohr    static public function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true)
198*091ad7bdSAndreas Gohr    {
199cbb44eabSAndreas Gohr        $evt = new Event($name, $data);
200cbb44eabSAndreas Gohr        return $evt->trigger($action, $canPreventDefault);
201cbb44eabSAndreas Gohr    }
202e1d9dcc8SAndreas Gohr}
203