Passed
Pull Request — master (#1316)
by Alexander
10:29
created

EventDispatcher::getListeners()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace JMS\Serializer\EventDispatcher;
6
7
use JMS\Serializer\Exception\InvalidArgumentException;
8
9
/**
10
 * Light-weight event dispatcher.
11
 *
12
 * This implementation focuses primarily on performance, and dispatching
13
 * events for certain classes. It is not a general purpose event dispatcher.
14
 *
15
 * @author Johannes M. Schmitt <[email protected]>
16
 */
17
class EventDispatcher implements EventDispatcherInterface
18
{
19
    /**
20
     * @var array
21
     */
22 3
    private $listeners = [];
23
24 3
    /**
25
     * ClassListeners cache
26
     *
27
     * @var array
28
     */
29
    private $classListeners = [];
30
31
    public static function getDefaultMethodName(string $eventName): string
32
    {
33
        return 'on' . str_replace(['_', '.'], '', $eventName);
34
    }
35
36
    /**
37
     * Sets the listeners.
38 25
     *
39
     * @param array $listeners
40 25
     */
41 25
    public function setListeners(array $listeners): void
42 25
    {
43
        $this->listeners = $listeners;
44 342
        $this->classListeners = [];
45
    }
46 342
47 342
    /**
48
     * @internal Used for profiling
49
     */
50
    public function getListeners(): array
51 342
    {
52 342
        return $this->listeners;
53 342
    }
54 342
55 342
    /**
56 342
     * {@inheritdoc}
57
     */
58 342
    public function addListener(string $eventName, $callable, ?string $class = null, ?string $format = null, ?string $interface = null): void
59
    {
60 229
        $this->listeners[$eventName][] = [$callable, $class, $format, $interface];
61
        unset($this->classListeners[$eventName]);
62 229
    }
63 197
64
    public function addSubscriber(EventSubscriberInterface $subscriber): void
65
    {
66 210
        foreach ($subscriber->getSubscribedEvents() as $eventData) {
67 210
            if (!isset($eventData['event'])) {
68
                throw new InvalidArgumentException(sprintf('Each event must have a "event" key.'));
69
            }
70 210
71
            $method = $eventData['method'] ?? self::getDefaultMethodName($eventData['event']);
72
            $class = $eventData['class'] ?? null;
73 225
            $format = $eventData['format'] ?? null;
74
            $interface = $eventData['interface'] ?? null;
75 225
            $this->listeners[$eventData['event']][] = [[$subscriber, $method], $class, $format, $interface];
76 5
            unset($this->classListeners[$eventData['event']]);
77
        }
78
    }
79 225
80 225
    public function hasListeners(string $eventName, string $class, string $format): bool
81 225
    {
82
        if (!isset($this->listeners[$eventName])) {
83 225
            return false;
84 35
        }
85
86
        if (!isset($this->classListeners[$eventName][$class][$format])) {
87 225
            $this->classListeners[$eventName][$class][$format] = $this->initializeListeners($eventName, $class, $format);
88
        }
89 225
90 210
        return !!$this->classListeners[$eventName][$class][$format];
91
    }
92
93 28
    public function dispatch(string $eventName, string $class, string $format, Event $event): void
94
    {
95 28
        if (!isset($this->listeners[$eventName])) {
96 28
            return;
97
        }
98
99 225
        $object = $event instanceof ObjectEvent ? $event->getObject() : null;
100
        $realClass = is_object($object) ? get_class($object) : '';
101
        $objectClass = $realClass !== $class ? $realClass . $class : $class;
102
103
        if (!isset($this->classListeners[$eventName][$objectClass][$format])) {
104
            $this->classListeners[$eventName][$objectClass][$format] = $this->initializeListeners($eventName, $class, $format);
105
        }
106
107
        foreach ($this->classListeners[$eventName][$objectClass][$format] as $listener) {
108 230
            if (!empty($listener[3]) && !($object instanceof $listener[3])) {
109
                continue;
110 230
            }
111 230
112 230
            \call_user_func($listener[0], $event, $eventName, $class, $format, $this);
113 10
114
            if ($event->isPropagationStopped()) {
115 230
                break;
116 3
            }
117
        }
118
    }
119 230
120
    /**
121
     * @return array An array of listeners
122 230
     */
123
    protected function initializeListeners(string $eventName, string $loweredClass, string $format): array
124
    {
125
        $listeners = [];
126
        foreach ($this->listeners[$eventName] as $listener) {
127
            if (null !== $listener[1] && $loweredClass !== $listener[1]) {
128
                continue;
129
            }
130
131
            if (null !== $listener[2] && $format !== $listener[2]) {
132
                continue;
133
            }
134
135
            $listeners[] = $listener;
136
        }
137
138
        return $listeners;
139
    }
140
}
141