EventHandler::hasListener()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 4
nop 1
dl 0
loc 13
ccs 0
cts 7
cp 0
crap 20
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of Biurad opensource projects.
5
 *
6
 * @copyright 2019 Biurad Group (https://biurad.com/)
7
 * @license   https://opensource.org/licenses/BSD-3-Clause License
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Flange\Handler;
14
15
use Psr\EventDispatcher\{EventDispatcherInterface, ListenerProviderInterface, StoppableEventInterface};
16
17
/**
18
 * A fully strict PSR 14 dispatcher and listener.
19
 *
20
 * @author Divine Niiquaye Ibok <[email protected]>
21
 */
22
class EventHandler implements EventDispatcherInterface, ListenerProviderInterface
23
{
24
    private array $listeners = [], $calledEvents = [];
25
26
    /**
27
     * {@inheritdoc}
28
     */
29
    public function dispatch(object $event): object
30
    {
31
        $stoppable = $event instanceof StoppableEventInterface;
32
33
        /** @var callable(object) $listener */
34
        foreach ($this->getListenersForEvent($event) as $listener) {
35
            if ($stoppable && $event->isPropagationStopped()) {
36
                break;
37
            }
38
            $listener($event);
39
        }
40
41
        return $event;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function getListenersForEvent(object $event): iterable
48
    {
49
        if (null === $calledListeners = &$this->calledEvents[$event::class] ?? null) {
50
            if (empty($listeners = $this->listeners[$event::class] ?? [])) {
51
                return [];
52
            }
53
54
            \krsort($listeners); // Sort Listeners by priority.
55
            $calledListeners = \array_merge(...$listeners);
56
        }
57
58
        yield from $calledListeners;
59
    }
60
61
    /**
62
     * Attaches listener to corresponding event based on the type-hint used for the event argument.
63
     *
64
     * @param callable $listener Any callable could be used be it a closure or invokable object
65
     * @param int      $priority The higher this value, the earlier an event listener will be triggered in the chain (defaults to 0)
66
     */
67
    public function addListener(string $eventClass, callable $listener, int $priority = 0): void
68
    {
69
        $this->listeners[$eventClass][$priority][] = $listener;
70
        unset($this->calledEvents[$eventClass]);
71
    }
72
73
    /**
74
     * Checks if listeners exist for an event, else in general if event name is null.
75
     */
76
    public function hasListener(string $eventClass = null): bool
77
    {
78
        if (null !== $eventClass) {
79
            return !empty($this->listeners[$eventClass]);
80
        }
81
82
        foreach ($this->listeners as $eventListeners) {
83
            if ($eventListeners) {
84
                return true;
85
            }
86
        }
87
88
        return false;
89
    }
90
}
91