Passed
Push — master ( 7656d0...dbe1c1 )
by Divine Niiquaye
04:04
created

EventHandler::hasListener()   A

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