1<?php
2// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
3
4namespace dokuwiki\Extension;
5
6/**
7 * Controls the registration and execution of all events,
8 */
9class EventHandler
10{
11
12    // public properties:  none
13
14    // private properties
15    protected $hooks = array();          // 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 !== null) $plugin->register($this);
35        }
36    }
37
38    /**
39     * register_hook
40     *
41     * register a hook for an event
42     *
43     * @param  string $event string   name used by the event, (incl '_before' or '_after' for triggers)
44     * @param  string $advise
45     * @param  object $obj object in whose scope method is to be executed,
46     *                             if NULL, method is assumed to be a globally available function
47     * @param  string $method event handler function
48     * @param  mixed $param data passed to the event handler
49     * @param  int $seq sequence number for ordering hook execution (ascending)
50     */
51    public function register_hook($event, $advise, $obj, $method, $param = null, $seq = 0)
52    {
53        $seq = (int)$seq;
54        $doSort = !isset($this->hooks[$event . '_' . $advise][$seq]);
55        $this->hooks[$event . '_' . $advise][$seq][] = array($obj, $method, $param);
56
57        if ($doSort) {
58            ksort($this->hooks[$event . '_' . $advise]);
59        }
60    }
61
62    /**
63     * process the before/after event
64     *
65     * @param Event $event
66     * @param string $advise BEFORE or AFTER
67     */
68    public function process_event($event, $advise = '')
69    {
70
71        $evt_name = $event->name . ($advise ? '_' . $advise : '_BEFORE');
72
73        if (!empty($this->hooks[$evt_name])) {
74            foreach ($this->hooks[$evt_name] as $sequenced_hooks) {
75                foreach ($sequenced_hooks as $hook) {
76                    list($obj, $method, $param) = $hook;
77
78                    if ($obj === null) {
79                        $method($event, $param);
80                    } else {
81                        $obj->$method($event, $param);
82                    }
83
84                    if (!$event->mayPropagate()) return;
85                }
86            }
87        }
88    }
89
90    /**
91     * Check if an event has any registered handlers
92     *
93     * When $advise is empty, both BEFORE and AFTER events will be considered,
94     * otherwise only the given advisory is checked
95     *
96     * @param string $name Name of the event
97     * @param string $advise BEFORE, AFTER or empty
98     * @return bool
99     */
100    public function hasHandlerForEvent($name, $advise = '')
101    {
102        if ($advise) {
103            return isset($this->hooks[$name . '_' . $advise]);
104        }
105
106        return isset($this->hooks[$name . '_BEFORE']) || isset($this->hooks[$name . '_AFTER']);
107    }
108}
109