Completed
Push — sidebaracl ( 7a112d...7c3e4a )
by Andreas
04:38
created

Doku_Event   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0
Metric Value
wmc 13
lcom 1
cbo 0
dl 0
loc 125
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __toString() 0 3 1
A stopPropagation() 0 3 1
A preventDefault() 0 3 1
A __construct() 0 6 1
A advise_before() 0 8 2
A advise_after() 0 6 1
B trigger() 0 22 6
1
<?php
2
/**
3
 * DokuWiki Events
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Christopher Smith <[email protected]>
7
 */
8
9
if(!defined('DOKU_INC')) die('meh.');
10
11
/**
12
 * The event
13
 */
14
class Doku_Event {
15
16
    // public properties
17
    public $name = '';                // READONLY  event name, objects must register against this name to see the event
18
    public $data = null;              // READWRITE data relevant to the event, no standardised format (YET!)
19
    public $result = null;            // READWRITE the results of the event action, only relevant in "_AFTER" advise
20
    //    event handlers may modify this if they are preventing the default action
21
    //    to provide the after event handlers with event results
22
    public $canPreventDefault = true; // READONLY  if true, event handlers can prevent the events default action
23
24
    // private properties, event handlers can effect these through the provided methods
25
    var $_default = true;     // whether or not to carry out the default action associated with the event
26
    var $_continue = true;    // whether or not to continue propagating the event to other handlers
27
28
    /**
29
     * event constructor
30
     *
31
     * @param string $name
32
     * @param mixed $data
33
     */
34
    function __construct($name, &$data) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
35
36
        $this->name = $name;
37
        $this->data =& $data;
38
39
    }
40
41
    /**
42
     * @return string
43
     */
44
    function __toString() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
45
        return $this->name;
46
    }
47
48
    /**
49
     * advise functions
50
     *
51
     * advise all registered 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 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->_default
65
     */
66
    function advise_before($enablePreventDefault=true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
67
        global $EVENT_HANDLER;
68
69
        $this->canPreventDefault = $enablePreventDefault;
70
        $EVENT_HANDLER->process_event($this,'BEFORE');
71
72
        return (!$enablePreventDefault || $this->_default);
73
    }
74
75
    function advise_after() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
76
        global $EVENT_HANDLER;
77
78
        $this->_continue = true;
79
        $EVENT_HANDLER->process_event($this,'AFTER');
80
    }
81
82
    /**
83
     * trigger
84
     *
85
     * - advise all registered (<event>_BEFORE) handlers that this event is about to take place
86
     * - carry out the default action using $this->data based on $enablePrevent and
87
     *   $this->_default, all of which may have been modified by the event handlers.
88
     * - advise all registered (<event>_AFTER) handlers that the event has taken place
89
     *
90
     * @param null|callable $action
91
     * @param bool $enablePrevent
92
     * @return  mixed $event->results
93
     *          the value set by any <event>_before or <event> handlers if the default action is prevented
94
     *          or the results of the default action (as modified by <event>_after handlers)
95
     *          or NULL no action took place and no handler modified the value
96
     */
97
    function trigger($action=null, $enablePrevent=true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
98
99
        if (!is_callable($action)) {
100
            $enablePrevent = false;
101
            if (!is_null($action)) {
102
                trigger_error('The default action of '.$this.' is not null but also not callable. Maybe the method is not public?', E_USER_WARNING);
103
            }
104
        }
105
106
        if ($this->advise_before($enablePrevent) && is_callable($action)) {
107
            if (is_array($action)) {
108
                list($obj,$method) = $action;
109
                $this->result = $obj->$method($this->data);
110
            } else {
111
                $this->result = $action($this->data);
112
            }
113
        }
114
115
        $this->advise_after();
116
117
        return $this->result;
118
    }
119
120
    /**
121
     * stopPropagation
122
     *
123
     * stop any further processing of the event by event handlers
124
     * this function does not prevent the default action taking place
125
     */
126
    function stopPropagation() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
127
        $this->_continue = false;
128
    }
129
130
    /**
131
     * preventDefault
132
     *
133
     * prevent the default action taking place
134
     */
135
    function preventDefault() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
136
        $this->_default = false;
137
    }
138
}
139
140
/**
141
 * Controls the registration and execution of all events,
142
 */
143
class Doku_Event_Handler {
144
145
    // public properties:  none
146
147
    // private properties
148
    protected $_hooks = array();          // array of events and their registered handlers
149
150
    /**
151
     * event_handler
152
     *
153
     * constructor, loads all action plugins and calls their register() method giving them
154
     * an opportunity to register any hooks they require
155
     */
156
    function __construct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
157
158
        // load action plugins
159
        /** @var DokuWiki_Action_Plugin $plugin */
160
        $plugin = null;
0 ignored issues
show
Unused Code introduced by
$plugin is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
161
        $pluginlist = plugin_list('action');
162
163
        foreach ($pluginlist as $plugin_name) {
164
            $plugin = plugin_load('action',$plugin_name);
165
166
            if ($plugin !== null) $plugin->register($this);
0 ignored issues
show
Documentation Bug introduced by
The method register does not exist on object<DokuWiki_Plugin>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
167
        }
168
    }
169
170
    /**
171
     * register_hook
172
     *
173
     * register a hook for an event
174
     *
175
     * @param  string   $event   string   name used by the event, (incl '_before' or '_after' for triggers)
176
     * @param  string   $advise
177
     * @param  object   $obj     object in whose scope method is to be executed,
178
     *                             if NULL, method is assumed to be a globally available function
179
     * @param  string   $method  event handler function
180
     * @param  mixed    $param   data passed to the event handler
181
     * @param  int      $seq     sequence number for ordering hook execution (ascending)
182
     */
183
    function register_hook($event, $advise, $obj, $method, $param=null, $seq=0) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
184
        $seq = (int)$seq;
185
        $doSort = !isset($this->_hooks[$event.'_'.$advise][$seq]);
186
        $this->_hooks[$event.'_'.$advise][$seq][] = array($obj, $method, $param);
187
188
        if ($doSort) {
189
            ksort($this->_hooks[$event.'_'.$advise]);
190
        }
191
    }
192
193
    /**
194
     * process the before/after event
195
     *
196
     * @param Doku_Event $event
197
     * @param string     $advise BEFORE or AFTER
198
     */
199
    function process_event($event,$advise='') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
200
201
        $evt_name = $event->name . ($advise ? '_'.$advise : '_BEFORE');
202
203
        if (!empty($this->_hooks[$evt_name])) {
204
            foreach ($this->_hooks[$evt_name] as $sequenced_hooks) {
205
                foreach ($sequenced_hooks as $hook) {
206
                    list($obj, $method, $param) = $hook;
207
208
                    if (is_null($obj)) {
209
                        $method($event, $param);
210
                    } else {
211
                        $obj->$method($event, $param);
212
                    }
213
214
                    if (!$event->_continue) return;
0 ignored issues
show
Bug introduced by
The property _continue cannot be accessed from this context as it is declared private in class Doku_Event.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
215
                }
216
            }
217
        }
218
    }
219
}
220
221
/**
222
 * trigger_event
223
 *
224
 * function wrapper to process (create, trigger and destroy) an event
225
 *
226
 * @param  string   $name               name for the event
227
 * @param  mixed    $data               event data
228
 * @param  callback $action             (optional, default=NULL) default action, a php callback function
229
 * @param  bool     $canPreventDefault  (optional, default=true) can hooks prevent the default action
230
 *
231
 * @return mixed                        the event results value after all event processing is complete
232
 *                                      by default this is the return value of the default action however
233
 *                                      it can be set or modified by event handler hooks
234
 */
235
function trigger_event($name, &$data, $action=null, $canPreventDefault=true) {
236
237
    $evt = new Doku_Event($name, $data);
238
    return $evt->trigger($action, $canPreventDefault);
239
}
240