Passed
Push — master ( 2cca3c...c649c5 )
by Asmir
05:31 queued 02:57
created

EventDispatcher::addSubscriber()   B

Complexity

Conditions 7
Paths 18

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 7.049

Importance

Changes 0
Metric Value
cc 7
eloc 9
nc 18
nop 1
dl 0
loc 13
ccs 9
cts 10
cp 0.9
crap 7.049
rs 8.2222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
namespace JMS\Serializer\EventDispatcher;
22
23
use JMS\Serializer\Exception\InvalidArgumentException;
24
25
/**
26
 * Light-weight event dispatcher.
27
 *
28
 * This implementation focuses primarily on performance, and dispatching
29
 * events for certain classes. It is not a general purpose event dispatcher.
30
 *
31
 * @author Johannes M. Schmitt <[email protected]>
32
 */
33
class EventDispatcher implements EventDispatcherInterface
34
{
35
    private $listeners = [];
36
    private $classListeners = [];
37
38 3
    public static function getDefaultMethodName($eventName)
39
    {
40 3
        return 'on' . str_replace(['_', '.'], '', $eventName);
41
    }
42
43
    /**
44
     * Sets the listeners.
45
     *
46
     * @param array $listeners
47
     */
48
    public function setListeners(array $listeners): void
49
    {
50
        $this->listeners = $listeners;
51
        $this->classListeners = [];
52
    }
53
54 25
    public function addListener(string $eventName, $callable, ?string $class = null, ?string $format = null, ?string $interface = null): void
55
    {
56 25
        $this->listeners[$eventName][] = [$callable, $class, $format, $interface];
57 25
        unset($this->classListeners[$eventName]);
58 25
    }
59
60 329
    public function addSubscriber(EventSubscriberInterface $subscriber): void
61
    {
62 329
        foreach ($subscriber->getSubscribedEvents() as $eventData) {
63 329
            if (!isset($eventData['event'])) {
64
                throw new InvalidArgumentException(sprintf('Each event must have a "event" key.'));
65
            }
66
67 329
            $method = isset($eventData['method']) ? $eventData['method'] : self::getDefaultMethodName($eventData['event']);
68 329
            $class = isset($eventData['class']) ? $eventData['class'] : null;
69 329
            $format = isset($eventData['format']) ? $eventData['format'] : null;
70 329
            $interface = isset($eventData['interface']) ? $eventData['interface'] : null;
71 329
            $this->listeners[$eventData['event']][] = [[$subscriber, $method], $class, $format, $interface];
72 329
            unset($this->classListeners[$eventData['event']]);
73
        }
74 329
    }
75
76 216
    public function hasListeners(string $eventName, string $class, string $format): bool
77
    {
78 216
        if (!isset($this->listeners[$eventName])) {
79 184
            return false;
80
        }
81
82 198
        if (!isset($this->classListeners[$eventName][$class][$format])) {
83 198
            $this->classListeners[$eventName][$class][$format] = $this->initializeListeners($eventName, $class, $format);
84
        }
85
86 198
        return !!$this->classListeners[$eventName][$class][$format];
87
    }
88
89 213
    public function dispatch($eventName, string $class, string $format, Event $event): void
90
    {
91 213
        if (!isset($this->listeners[$eventName])) {
92 5
            return;
93
        }
94
95 213
        $object = $event instanceof ObjectEvent ? $event->getObject() : null;
96 213
        $realClass = is_object($object) ? get_class($object) : '';
97 213
        $objectClass = $realClass !== $class ? ($realClass . $class) : $class;
98
99 213
        if (!isset($this->classListeners[$eventName][$objectClass][$format])) {
100 35
            $this->classListeners[$eventName][$objectClass][$format] = $this->initializeListeners($eventName, $class, $format);
101
        }
102
103 213
        foreach ($this->classListeners[$eventName][$objectClass][$format] as $listener) {
104
105 213
            if ($listener[3] !== null && !($object instanceof $listener[3])) {
106 198
                continue;
107
            }
108
109 28
            \call_user_func($listener[0], $event, $eventName, $class, $format, $this);
110
111 28
            if ($event->isPropagationStopped()) {
112 28
                break;
113
            }
114
        }
115 213
    }
116
117
    /**
118
     * @param string $eventName
119
     * @param string $loweredClass
120
     * @param string $format
121
     *
122
     * @return array An array of listeners
123
     */
124 218
    protected function initializeListeners($eventName, $loweredClass, $format)
125
    {
126 218
        $listeners = [];
127 218
        foreach ($this->listeners[$eventName] as $listener) {
128 218
            if (null !== $listener[1] && $loweredClass !== $listener[1]) {
129 10
                continue;
130
            }
131 218
            if (null !== $listener[2] && $format !== $listener[2]) {
132 3
                continue;
133
            }
134
135 218
            $listeners[] = $listener;
136
        }
137
138 218
        return $listeners;
139
    }
140
}
141
142