EventEmitter::emit()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 13
c 0
b 0
f 0
rs 9.6111
cc 5
nc 5
nop 2
1
<?php
2
/**
3
 * @Author : a.zinovyev
4
 * @Package: emittr
5
 * @License: http://www.opensource.org/licenses/mit-license.php
6
 */
7
8
namespace xobotyi\emittr;
9
10
class EventEmitter implements Interfaces\EventEmitter
11
{
12
    public const EVENT_LISTENER_ADDED   = 'listenerAdded';
13
    public const EVENT_LISTENER_REMOVED = 'listenerRemoved';
14
15
    /**
16
     * @var Interfaces\GlobalEventHandler;
17
     */
18
    private $eventEmitterGlobal;
19
20
    /**
21
     * @var array
22
     */
23
    private $eventListeners = [];
24
25
    /**
26
     * @var int
27
     */
28
    private $maxListenersCount = 10;
29
30
    /**
31
     * EventEmitter constructor.
32
     *
33
     * @param null|\xobotyi\emittr\Interfaces\GlobalEventHandler $emitterGlobal
34
     */
35
    public function __construct(?Interfaces\GlobalEventHandler $emitterGlobal = null) {
36
        $this->setGlobalEmitter($emitterGlobal ?: GlobalEventHandler::getInstance());
37
    }
38
39
    /**
40
     * @inheritdoc
41
     *
42
     * @param string|\xobotyi\emittr\Event $event
43
     * @param null                         $payload
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $payload is correct as it would always require null to be passed?
Loading history...
44
     *
45
     * @return \xobotyi\emittr\EventEmitter
46
     */
47
    public function emit($event, $payload = null) :self {
48
        if (is_string($event)) {
49
            $event = new Event($event, $payload, get_called_class(), $this);
50
        }
51
        else if (!($event instanceof Event)) {
0 ignored issues
show
introduced by
$event is always a sub-type of xobotyi\emittr\Event.
Loading history...
52
            throw new \TypeError('first parameter has to be of type string or \xobotyi\emittr\Event instance, got ' . gettype($event));
53
        }
54
55
        if (empty($this->eventListeners) || $this->eventEmitterGlobal::propagateEvent($event, $this->eventListeners)) {
56
            $this->eventEmitterGlobal->propagateEventGlobal($event);
57
        }
58
59
        return $this;
60
    }
61
62
    /**
63
     * @inheritdoc
64
     *
65
     * @param string                $eventName
66
     * @param array|callable|string $callback
67
     *
68
     * @return \xobotyi\emittr\EventEmitter
69
     */
70
    public function on(string $eventName, $callback) :self {
71
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, false, false);
72
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
73
74
        return $this;
75
    }
76
77
    /**
78
     * @inheritdoc
79
     *
80
     * @param string                $eventName
81
     * @param array|callable|string $callback
82
     *
83
     * @return \xobotyi\emittr\EventEmitter
84
     */
85
    public function once(string $eventName, $callback) :self {
86
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, true, false);
87
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
88
89
        return $this;
90
    }
91
92
    /**
93
     * @inheritdoc
94
     *
95
     * @param string                $eventName
96
     * @param array|callable|string $callback
97
     *
98
     * @return \xobotyi\emittr\EventEmitter
99
     */
100
    public function prependListener(string $eventName, $callback) :self {
101
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, false, true);
102
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
103
104
        return $this;
105
    }
106
107
    /**
108
     * @inheritdoc
109
     *
110
     * @param string                $eventName
111
     * @param array|callable|string $callback
112
     *
113
     * @return \xobotyi\emittr\EventEmitter
114
     */
115
    public function prependOnceListener(string $eventName, $callback) :self {
116
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, true, true);
117
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
118
119
        return $this;
120
    }
121
122
    /**
123
     * @inheritdoc
124
     *
125
     * @param string                $eventName
126
     * @param array|callable|string $callback
127
     *
128
     * @return \xobotyi\emittr\EventEmitter
129
     */
130
    public function off(string $eventName, $callback) :self {
131
        if (empty($this->eventListeners[$eventName])) {
132
            return $this;
133
        }
134
135
        $this->eventListeners[$eventName] = \array_values(\array_filter($this->eventListeners[$eventName], function ($item) use (&$callback) { return $item[1] !== $callback; }));
136
        $this->emit(self::EVENT_LISTENER_REMOVED, ['eventName' => $eventName, 'callback' => &$callback]);
137
138
        if (empty($this->eventListeners[$eventName])) {
139
            unset($this->eventListeners[$eventName]);
140
        }
141
142
        return $this;
143
    }
144
145
    /**
146
     * @inheritdoc
147
     *
148
     * @param null|string $eventName
149
     *
150
     * @return \xobotyi\emittr\EventEmitter
151
     */
152
    public function removeAllListeners(?string $eventName = null) :self {
153
        if ($eventName === null) {
154
            foreach ($this->eventListeners as $eventName => $callbacks) {
155
                foreach ($callbacks as &$callback) {
156
                    $this->emit(self::EVENT_LISTENER_REMOVED, [
157
                        'eventName' => $eventName,
158
                        'callback'  => &$callback[1],
159
                    ]);
160
                }
161
            }
162
163
            $this->eventListeners = [];
164
165
            return $this;
166
        }
167
168
        if (empty($this->eventListeners[$eventName])) {
169
            return $this;
170
        }
171
172
        foreach ($this->eventListeners[$eventName] as $callback) {
173
            $this->emit(self::EVENT_LISTENER_REMOVED, ['eventName' => $eventName, 'callback' => &$callback[1]]);
174
        }
175
176
        unset($this->eventListeners[$eventName]);
177
178
        return $this;
179
    }
180
181
    /**
182
     * @inheritdoc
183
     *
184
     * @return array
185
     */
186
    public function getEventNames() :array {
187
        return empty($this->eventListeners) ? [] : \array_keys($this->eventListeners);
188
    }
189
190
    /**
191
     * @inheritdoc
192
     *
193
     * @param null|string $eventName
194
     *
195
     * @return array
196
     */
197
    public function getListeners(?string $eventName = null) :array {
198
        return $eventName ? $this->eventListeners[$eventName] ?? [] : $this->eventListeners;
199
    }
200
201
    /**
202
     * @inheritdoc
203
     *
204
     * @return int
205
     */
206
    public function getMaxListenersCount() :int {
207
        return $this->maxListenersCount;
208
    }
209
210
    /**
211
     * @inheritdoc
212
     *
213
     * @param int $maxListenersCount
214
     *
215
     * @return \xobotyi\emittr\EventEmitter
216
     */
217
    public function setMaxListenersCount(int $maxListenersCount) :self {
218
        if ($maxListenersCount < 0) {
219
            throw new \InvalidArgumentException('Listeners count must be greater or equal 0, got ' . $maxListenersCount);
220
        }
221
222
        $this->maxListenersCount = $maxListenersCount;
223
224
        return $this;
225
    }
226
227
    /**
228
     * @inheritdoc
229
     *
230
     * @return \xobotyi\emittr\Interfaces\GlobalEventHandler
231
     */
232
    public function getGlobalEmitter() :Interfaces\GlobalEventHandler {
233
        return $this->eventEmitterGlobal;
234
    }
235
236
    /**
237
     * @inheritdoc
238
     *
239
     * @param \xobotyi\emittr\Interfaces\GlobalEventHandler $emitterGlobal
240
     *
241
     * @return \xobotyi\emittr\EventEmitter
242
     */
243
    public function setGlobalEmitter(Interfaces\GlobalEventHandler $emitterGlobal) :self {
244
        $this->eventEmitterGlobal = $emitterGlobal;
245
246
        return $this;
247
    }
248
}