EventDispatcher::hasListeners()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace As3\Modlr\Events;
4
5
/**
6
 * Handles and dispatches events.
7
 * Listeners are registered with the manager and events are dispatched through this service.
8
 * Events include model/store lifecycle, and persister events.
9
 *
10
 * @author Jacob Bare <[email protected]>
11
 */
12
class EventDispatcher
13
{
14
    /**
15
     * All registered event listener objects and their assigned events.
16
     *
17
     * @var array
18
     */
19
    private $listeners = [];
20
21
    /**
22
     * Adds an event listener.
23
     *
24
     * @param   string|array    $eventNames The event name(s) to listen for.
25
     * @param   object          $listener   The event listener object.
26
     * @return  self
27
     * @throws  \InvalidArgumentException   If the listener does not contain the event method.
28
     */
29
    public function addListener($eventNames, $listener)
30
    {
31
        $key = $this->getListenerKey($listener);
32
        foreach ((Array) $eventNames as $eventName) {
33
            if (!method_exists($listener, $eventName)) {
34
                throw new \InvalidArgumentException(sprintf('The listener class %s does not have the appropriate event method. Expected method "%s"', get_class($listener), $eventName));
35
            }
36
            $this->listeners[$eventName][$key] = $listener;
37
        }
38
        return $this;
39
    }
40
41
    /**
42
     * Adds an event subscriber.
43
     *
44
     * @param   EventSubscriberInterface    $subscriber
45
     * @return  self
46
     */
47
    public function addSubscriber(EventSubscriberInterface $subscriber)
48
    {
49
        return $this->addListener($subscriber->getEvents(), $subscriber);
50
    }
51
52
    /**
53
     * Dispatches an event to all registered listeners.
54
     *
55
     * @param   EventArguments|null     $arguments
56
     * @return  self
57
     */
58
    public function dispatch($eventName, EventArguments $arguments = null)
59
    {
60
        if (false === $this->hasListeners($eventName)) {
61
            return $this;
62
        }
63
        $arguments = $arguments ?: EventArguments::createEmpty();
64
        foreach ($this->getListeners($eventName) as $listener) {
0 ignored issues
show
Bug introduced by
The expression $this->getListeners($eventName) of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
65
            $listener->$eventName($arguments);
66
        }
67
        return $this;
68
    }
69
70
    /**
71
     * Gets the key for a listener object.
72
     *
73
     * @param   object  $listener
74
     * @return  string
75
     * @throws  \InvalidArgumentException   If the listener is not an object.
76
     */
77
    protected function getListenerKey($listener)
78
    {
79
        if (!is_object($listener)) {
80
            throw new \InvalidArgumentException('Event listeners must be an object.');
81
        }
82
        return spl_object_hash($listener);
83
    }
84
85
    /**
86
     * Gets all registered listeners for an event name.
87
     *
88
     * @param   string  $eventName
89
     * @return  array|null
90
     */
91
    protected function getListeners($eventName)
92
    {
93
        if (isset($this->listeners[$eventName])) {
94
            return $this->listeners[$eventName];
95
        }
96
        return null;
97
    }
98
99
     /**
100
     * Determines if registered listeners exist for an event name.
101
     *
102
     * @param   string  $eventName
103
     * @return  bool
104
     */
105
    public function hasListeners($eventName)
106
    {
107
        return null !== $this->getListeners($eventName);
108
    }
109
110
    /**
111
     * Removes an event listener, if registered.
112
     *
113
     * @param   string|array    $eventNames The event name(s) to listen for.
114
     * @param   object          $listener   The event listener object.
115
     * @return  self
116
     */
117
    public function removeListener($eventNames, $listener)
118
    {
119
        $key = $this->getListenerKey($listener);
120
        foreach ((Array) $eventNames as $eventName) {
121
            if (isset($this->listeners[$eventName][$key])) {
122
                unset($this->listeners[$eventName][$key]);
123
            }
124
        }
125
        return $this;
126
    }
127
128
    /**
129
     * Removes an event subscriber.
130
     *
131
     * @param   EventSubscriberInterface    $subscriber
132
     * @return  self
133
     */
134
    public function removeSubscriber(EventSubscriberInterface $subscriber)
135
    {
136
        return $this->removeListener($subscriber->getEvents(), $subscriber);
137
    }
138
}
139