MutableListenerProvider   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 12
eloc 23
c 1
b 0
f 0
dl 0
loc 77
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A prependListenerForEvent() 0 11 2
A appendListenerForEvent() 0 7 1
A assertUnique() 0 10 3
A makeRemoveCallback() 0 13 2
A getListenersForEvent() 0 6 4
1
<?php
2
3
/*
4
 * (c) Olivier Laviale <[email protected]>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace olvlvl\EventDispatcher;
11
12
use LogicException;
13
14
use function array_search;
15
use function array_unshift;
16
use function in_array;
17
18
final class MutableListenerProvider implements MutableListenerProviderInterface
19
{
20
    /**
21
     * @var array<class-string, array<int, callable>>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string, array<int, callable>> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, array<int, callable>>.
Loading history...
22
     */
23
    private $listeners = [];
24
25
    /**
26
     * @inheritDoc
27
     *
28
     * @return iterable<callable(object):void>
29
     */
30
    public function getListenersForEvent(object $event): iterable
31
    {
32
        foreach ($this->listeners as $class => $listeners) {
33
            if ($event instanceof $class) {
34
                foreach ($listeners as $listener) {
35
                    yield $listener;
36
                }
37
            }
38
        }
39
    }
40
41
    /**
42
     * @inheritDoc
43
     */
44
    public function appendListenerForEvent(string $eventType, callable $listener): callable
45
    {
46
        $this->assertUnique($eventType, $listener);
47
48
        $this->listeners[$eventType][] = $listener;
49
50
        return $this->makeRemoveCallback($eventType, $listener);
51
    }
52
53
    /**
54
     * @inheritDoc
55
     */
56
    public function prependListenerForEvent(string $eventType, callable $listener): callable
57
    {
58
        $this->assertUnique($eventType, $listener);
59
60
        if (!isset($this->listeners[$eventType])) {
61
            $this->listeners[$eventType] = [];
62
        }
63
64
        array_unshift($this->listeners[$eventType], $listener);
65
66
        return $this->makeRemoveCallback($eventType, $listener);
67
    }
68
69
    private function assertUnique(string $eventType, callable $listener): void
70
    {
71
        $listeners = $this->listeners[$eventType] ?? null;
72
73
        if (!$listeners) {
74
            return;
75
        }
76
77
        if (in_array($listener, $listeners, true)) {
78
            throw new LogicException("Listener already defined for event type '$eventType'.");
79
        }
80
    }
81
82
    private function makeRemoveCallback(string $eventType, callable $listener): callable
83
    {
84
        return function () use ($eventType, $listener) {
85
            $key = array_search($listener, $this->listeners[$eventType], true);
86
87
            if ($key === false) {
88
                // The Listener has already been removed.
89
                // It's not great that the user is removing the listener twice,
90
                // but it's not critical since the result is the same.
91
                return;
92
            }
93
94
            unset($this->listeners[$eventType][$key]);
95
        };
96
    }
97
}
98