Completed
Push — master ( 124f2b...1346f4 )
by Arnold
03:01
created

ListenerProvider   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 27
dl 0
loc 73
ccs 28
cts 28
cp 1
rs 10
c 0
b 0
f 0
wmc 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A on() 0 10 2
A getListenersForEvent() 0 13 5
A off() 0 18 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Jasny\EventDispatcher;
6
7
use Improved\IteratorPipeline\Pipeline;
8
use Psr\EventDispatcher\ListenerProviderInterface;
9
10
/**
11
 * Event dispatcher.
12
 * @immutable
13
 */
14
class ListenerProvider implements ListenerProviderInterface
15
{
16
    /**
17
     * @var array
18
     */
19
    protected $listeners = [];
20
21
22
    /**
23
     * Bind a handler for an event.
24
     *
25
     * @param string   $eventName
26
     * @param callable $listener
27
     * @return static
28
     */
29 3
    public function on(string $eventName, callable $listener): self
30
    {
31 3
        if (strpos($eventName, '*') !== false) {
32 1
            throw new \InvalidArgumentException("Invalid event name '$eventName': illegal character '*'");
33
        }
34
35 2
        $clone = clone $this;
36 2
        $clone->listeners[] = ['event' => $eventName, 'listener' => $listener];
37
38 2
        return $clone;
39
    }
40
41
    /**
42
     * Unbind a handler of an event.
43
     *
44
     * @param string $eventName  Event name, optionally with wildcards
45
     * @return $this
46
     */
47 5
    public function off(string $eventName): self
48
    {
49 5
        $listeners = Pipeline::with($this->listeners)
50
            ->filter(function ($trigger) use ($eventName) {
51 5
                return !fnmatch($eventName, $trigger['event'], FNM_NOESCAPE)
52 5
                    && !fnmatch("$eventName.*", $trigger['event'], FNM_NOESCAPE);
53 5
            })
54 5
            ->values()
55 5
            ->toArray();
56
57 5
        if (count($listeners) === count($this->listeners)) {
58 1
            return $this;
59
        }
60
61 5
        $clone = clone $this;
62 5
        $clone->listeners = $listeners;
63
64 5
        return $clone;
65
    }
66
67
68
    /**
69
     * Get the relevant listeners for the given event
70
     *
71
     * @param object $event
72
     * @return callable[]
73
     */
74 7
    public function getListenersForEvent(object $event): iterable
75
    {
76 7
        $eventName = $event instanceof Event ? $event->getName() : null;
77
78 7
        return Pipeline::with($this->listeners)
79
            ->filter(function ($trigger) use ($event, $eventName) {
80 7
                return is_a($event, $trigger['event'])
81 6
                    || $eventName === $trigger['event']
82 7
                    || ($eventName !== null && fnmatch("{$eventName}.*", $trigger['event'], FNM_NOESCAPE));
83 7
            })
84 7
            ->column('listener')
85 7
            ->values()
86 7
            ->toArray();
87
    }
88
}
89