Passed
Push — master ( 0dda89...446f71 )
by Anton
02:01
created

EventEmitter::emit()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 5
nop 2
dl 0
loc 13
rs 8.8571
c 0
b 0
f 0
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\EventEmitterGlobal;
17
     */
18
    private $eventEmitterGlobal;
19
20
    private $eventListeners = [];
21
22
    private $maxListenersCount = 10;
23
24
    public function __construct(?Interfaces\EventEmitterGlobal $emitterGlobal = null) {
25
        $this->setGlobalEmitter($emitterGlobal ?: EventEmitterGlobal::getInstance());
26
    }
27
28
    /**
29
     * @param string|\xobotyi\emittr\Event $event
30
     * @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...
31
     *
32
     * @return \xobotyi\emittr\EventEmitter
33
     */
34
    public function emit($event, $payload = null) :self {
35
        if (is_string($event)) {
36
            $event = new Event($event, $payload, get_called_class(), $this);
37
        }
38
        else if (!($event instanceof Event)) {
0 ignored issues
show
introduced by
$event is always a sub-type of xobotyi\emittr\Event.
Loading history...
39
            throw new \TypeError('first parameter has to be of type string or \xobotyi\emittr\Event instance, got ' . gettype($event));
40
        }
41
42
        if (empty($this->eventListeners) || $this->eventEmitterGlobal::propagateEvent($event, $this->eventListeners)) {
43
            $this->eventEmitterGlobal->propagateEventGlobal($event);
44
        }
45
46
        return $this;
47
    }
48
49
    public function on(string $eventName, $callback) :self {
50
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, false, false);
51
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
52
53
        return $this;
54
    }
55
56
    public function once(string $eventName, $callback) :self {
57
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, true, false);
58
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
59
60
        return $this;
61
    }
62
63
    public function prependListener(string $eventName, $callback) :self {
64
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, false, true);
65
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
66
67
        return $this;
68
    }
69
70
    public function prependOnceListener(string $eventName, $callback) :self {
71
        $this->eventEmitterGlobal::storeCallback($this->eventListeners, $eventName, $callback, $this->maxListenersCount, true, true);
72
        $this->emit(self::EVENT_LISTENER_ADDED, ['callback' => &$callback]);
73
74
        return $this;
75
    }
76
77
    public function off(string $eventName, $callback) :self {
78
        if (empty($this->eventListeners[$eventName])) {
79
            return $this;
80
        }
81
82
        $this->eventListeners[$eventName] = \array_values(\array_filter($this->eventListeners[$eventName], function ($item) use (&$callback) { return $item[1] !== $callback; }));
83
        $this->emit(self::EVENT_LISTENER_REMOVED, ['eventName' => $eventName, 'callback' => &$callback]);
84
85
        if (empty($this->eventListeners[$eventName])) {
86
            unset($this->eventListeners[$eventName]);
87
        }
88
89
        return $this;
90
    }
91
92
    public function removeAllListeners(?string $eventName = null) :self {
93
        if ($eventName === null) {
94
            foreach ($this->eventListeners as $eventName => $callbacks) {
95
                foreach ($callbacks as &$callback) {
96
                    $this->emit(self::EVENT_LISTENER_REMOVED, [
97
                        'eventName' => $eventName,
98
                        'callback'  => &$callback[1],
99
                    ]);
100
                }
101
            }
102
103
            $this->eventListeners = [];
104
105
            return $this;
106
        }
107
108
        if (empty($this->eventListeners[$eventName])) {
109
            return $this;
110
        }
111
112
        foreach ($this->eventListeners[$eventName] as $callback) {
113
            $this->emit(self::EVENT_LISTENER_REMOVED, ['eventName' => $eventName, 'callback' => &$callback[1]]);
114
        }
115
116
        unset($this->eventListeners[$eventName]);
117
118
        return $this;
119
    }
120
121
    public function getEventNames() :array {
122
        return empty($this->eventListeners) ? [] : \array_keys($this->eventListeners);
123
    }
124
125
    public function getListeners(?string $eventName = null) :array {
126
        return $eventName ? $this->eventListeners[$eventName] ?? [] : $this->eventListeners;
127
    }
128
129
    public function getMaxListenersCount() :int {
130
        return $this->maxListenersCount;
131
    }
132
133
    public function setMaxListenersCount(int $maxListenersCount) :self {
134
        if ($maxListenersCount < 0) {
135
            throw new \InvalidArgumentException('Listeners count must be greater or equal 0, got ' . $maxListenersCount);
136
        }
137
138
        $this->maxListenersCount = $maxListenersCount;
139
140
        return $this;
141
    }
142
143
    public function getGlobalEmitter() :Interfaces\EventEmitterGlobal {
144
        return $this->eventEmitterGlobal;
145
    }
146
147
    public function setGlobalEmitter(Interfaces\EventEmitterGlobal $emitterGlobal) :self {
148
        $this->eventEmitterGlobal = $emitterGlobal;
149
150
        return $this;
151
    }
152
}