1 <?php
2 
3 // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
4 
5 namespace dokuwiki\Extension;
6 
7 /**
8  * Controls the registration and execution of all events,
9  */
10 class EventHandler
11 {
12     // public properties:  none
13 
14     // private properties
15     protected $hooks = [];          // array of events and their registered handlers
16 
17     /**
18      * event_handler
19      *
20      * constructor, loads all action plugins and calls their register() method giving them
21      * an opportunity to register any hooks they require
22      */
23     public function __construct()
24     {
25 
26         // load action plugins
27         /** @var ActionPlugin $plugin */
28         $plugin = null;
29         $pluginlist = plugin_list('action');
30 
31         foreach ($pluginlist as $plugin_name) {
32             $plugin = plugin_load('action', $plugin_name);
33 
34             if ($plugin instanceof PluginInterface) $plugin->register($this);
35         }
36     }
37 
38     /**
39      * register_hook
40      *
41      * register a hook for an event
42      *
43      * @param string $event name used by the event
44      * @param string $advise BEFORE|AFTER
45      * @param object $obj scope for the method be executed on, NULL for global function or callable
46      * @param string|callable $method event handler function
47      * @param mixed $param data passed to the event handler
48      * @param int $seq sequence number for ordering hook execution (ascending)
49      */
50     public function register_hook($event, $advise, $obj, $method, $param = null, $seq = 0)
51     {
52         $seq = (int)$seq;
53         $doSort = !isset($this->hooks[$event . '_' . $advise][$seq]);
54         $this->hooks[$event . '_' . $advise][$seq][] = [$obj, $method, $param];
55 
56         if ($doSort) {
57             ksort($this->hooks[$event . '_' . $advise]);
58         }
59     }
60 
61     /**
62      * process the before/after event
63      *
64      * @param Event $event
65      * @param string $advise BEFORE or AFTER
66      */
67     public function process_event($event, $advise = '')
68     {
69 
70         $evt_name = $event->name . ($advise ? '_' . $advise : '_BEFORE');
71 
72         if (!empty($this->hooks[$evt_name])) {
73             foreach ($this->hooks[$evt_name] as $sequenced_hooks) {
74                 foreach ($sequenced_hooks as $hook) {
75                     [$obj, $method, $param] = $hook;
76 
77                     if ($obj === null) {
78                         $method($event, $param);
79                     } else {
80                         $obj->$method($event, $param);
81                     }
82 
83                     if (!$event->mayPropagate()) return;
84                 }
85             }
86         }
87     }
88 
89     /**
90      * Check if an event has any registered handlers
91      *
92      * When $advise is empty, both BEFORE and AFTER events will be considered,
93      * otherwise only the given advisory is checked
94      *
95      * @param string $name Name of the event
96      * @param string $advise BEFORE, AFTER or empty
97      * @return bool
98      */
99     public function hasHandlerForEvent($name, $advise = '')
100     {
101         if ($advise) {
102             return isset($this->hooks[$name . '_' . $advise]);
103         }
104 
105         return isset($this->hooks[$name . '_BEFORE']) || isset($this->hooks[$name . '_AFTER']);
106     }
107 
108     /**
109      * Get all hooks and their currently registered handlers
110      *
111      * The handlers are sorted by sequence, then by register time
112      *
113      * @return array
114      */
115     public function getEventHandlers()
116     {
117         return $this->hooks;
118     }
119 }
120