SimpleEventDispatcher::dispatch()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 6
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 10
ccs 7
cts 7
cp 1
crap 4
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Test\Support\EventDispatcher;
6
7
use Closure;
8
use InvalidArgumentException;
9
use Psr\EventDispatcher\EventDispatcherInterface;
10
use Psr\EventDispatcher\StoppableEventInterface;
11
12
final class SimpleEventDispatcher implements EventDispatcherInterface
13
{
14
    /** @var Closure[] */
15
    private array $listeners;
16
17
    /**
18
     * @var object[]
19
     * @psalm-var list<object>
20
     */
21
    private array $events = [];
22
23
    /**
24
     * @param Closure ...$listeners Functions that will handle each event.
25
     */
26 18
    public function __construct(Closure ...$listeners)
27
    {
28 18
        $this->listeners = $listeners;
29
    }
30
31 16
    public function dispatch(object $event): object
32
    {
33 16
        $this->events[] = $event;
34 16
        foreach ($this->listeners as $listener) {
35 4
            if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
36 2
                return $event;
37
            }
38 3
            $listener($event);
39
        }
40 13
        return $event;
41
    }
42
43
    /**
44
     * @return object[]
45
     * @psalm-return list<object>
46
     */
47 3
    public function getEvents(): array
48
    {
49 3
        return $this->events;
50
    }
51
52
    /**
53
     * @psalm-return list<class-string>
54
     */
55 1
    public function getEventClasses(): array
56
    {
57 1
        return array_map('\get_class', $this->events);
58
    }
59
60 1
    public function clearEvents(): void
61
    {
62 1
        $this->events = [];
63
    }
64
65 3
    public function isObjectTriggered(object $event, ?int $times = null): bool
66
    {
67 3
        return $this->processBoolResult(static fn (object $e): bool => $e === $event, $times);
68
    }
69
70 4
    public function isClassTriggered(string $class, ?int $times = null): bool
71
    {
72 4
        return $this->processBoolResult(static fn (object $event): bool => $event::class === $class, $times);
73
    }
74
75 3
    public function isInstanceOfTriggered(string $class, ?int $times = null): bool
76
    {
77 3
        return $this->processBoolResult(static fn (object $event): bool => $event instanceof $class, $times);
78
    }
79
80 10
    private function processBoolResult(Closure $closure, ?int $times): bool
81
    {
82 10
        if ($times < 0) {
83 1
            throw new InvalidArgumentException('The $times argument cannot be less than zero.');
84
        }
85 9
        if ($times === null) {
86 3
            return $this->hasEvent($closure);
87
        }
88 6
        return $times === $this->calcEvent($closure);
89
    }
90
91 3
    private function hasEvent(Closure $closure): bool
92
    {
93 3
        foreach ($this->events as $event) {
94 3
            if ($closure($event)) {
95 3
                return true;
96
            }
97
        }
98 3
        return false;
99
    }
100
101 6
    private function calcEvent(Closure $closure): int
102
    {
103 6
        $count = 0;
104 6
        foreach ($this->events as $event) {
105 6
            if ($closure($event)) {
106 6
                ++$count;
107
            }
108
        }
109 6
        return $count;
110
    }
111
}
112