EventDispatcher::getEventName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
ccs 2
cts 2
cp 1
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php declare(strict_types = 1);
2
3
namespace Venta\Event;
4
5
use Venta\Contracts\Event\Event;
6
use Venta\Contracts\Event\EventDispatcher as EventDispatcherContract;
7
use Venta\Event\Exception\InvalidListenerException;
8
9
/**
10
 * Class EventDispatcher
11
 *
12
 * @package Venta\Event
13
 */
14
class EventDispatcher implements EventDispatcherContract
15
{
16
    /**
17
     * Array of events, being dispatched now.
18
     *
19
     * @var array
20
     */
21
    private $dispatching = [];
22
23
    /**
24
     * Array of defined events and it listeners.
25
     *
26
     * @var array
27
     */
28
    private $listeners = [];
29
30
    /**
31
     * Sorted listeners array cache.
32
     *
33
     * @var array
34
     */
35
    private $sortedListeners = [];
36
37
    /**
38
     * @inheritDoc
39
     * @throws InvalidListenerException
40
     */
41 3
    public function addListener(string $eventName, $listener, int $priority = 0)
42
    {
43 3
        if (!$this->canBeCalled($listener)) {
44
            throw new InvalidListenerException($listener);
45
        }
46
47 3
        $this->listeners[$eventName][$priority][] = $listener;
48 3
        unset($this->sortedListeners[$eventName]);
49 3
    }
50
51
    /**
52
     * @inheritDoc
53
     */
54 3
    public function dispatch(Event $event)
55
    {
56 3
        if (isset($this->dispatching[$this->getEventName($event)])) {
57
            return;
58
        }
59
60 3
        $this->dispatching[$this->getEventName($event)] = true;
61 3
        $listeners = $this->getListeners($this->getEventName($event));
62
63 3
        foreach ($listeners as $index => $listener) {
64 3
            $this->callListener($listener, $event);
65
66 3
            if ($event->isPropagationStopped()) {
67 3
                break;
68
            }
69
        }
70
71 3
        unset($this->dispatching[$this->getEventName($event)]);
72 3
    }
73
74
    /**
75
     * Performs call of the listener.
76
     *
77
     * @param mixed $listener
78
     * @param Event $event
79
     */
80 3
    protected function callListener($listener, Event $event)
81
    {
82 3
        $listener($event);
83 3
    }
84
85
    /**
86
     * Defines, if listener can be called.
87
     *
88
     * @param  mixed $listener
89
     * @return bool
90
     */
91 3
    protected function canBeCalled($listener): bool
92
    {
93 3
        return is_callable($listener);
94
    }
95
96
    /**
97
     * Returns array of event listeners.
98
     *
99
     * @param  string $eventName
100
     * @return array
101
     */
102 3
    protected function getListeners(string $eventName): array
103
    {
104 3
        if (!isset($this->listeners[$eventName])) {
105
            return [];
106
        }
107
108 3
        if (!isset($this->sortedListeners[$eventName])) {
109 3
            $this->sortedListeners[$eventName] = $this->sortEventListeners($eventName);
110
        }
111
112 3
        return $this->sortedListeners[$eventName];
113
    }
114
115
    /**
116
     * Merges all event listeners for particular event.
117
     *
118
     * @param  string $eventName
119
     * @return array
120
     */
121 3
    protected function sortEventListeners(string $eventName): array
122
    {
123 3
        $listeners = $this->listeners[$eventName];
124 3
        $normalised = [];
125
126 3
        ksort($listeners);
127
128 3
        foreach ($listeners as $priorityListeners) {
129 3
            foreach ($priorityListeners as $listener) {
130 3
                $normalised[] = $listener;
131
            }
132
        }
133
134 3
        return $normalised;
135
    }
136
137
    /**
138
     * Returns event name.
139
     *
140
     * @param  Event $event
141
     * @return string
142
     */
143 3
    private function getEventName(Event $event)
144
    {
145 3
        return ltrim(get_class($event), '\\');
146
    }
147
}