EventDispatcher::fire()   B
last analyzed

Complexity

Conditions 7
Paths 16

Size

Total Lines 43
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 27
nc 16
nop 2
dl 0
loc 43
ccs 23
cts 23
cp 1
crap 7
rs 8.5546
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate\Event;
6
7
use Suricate\Suricate;
8
use InvalidArgumentException;
9
use Suricate\Service;
10
11
class EventDispatcher extends Service
12
{
13
    /**
14
     * Array of declared listeners
15
     *
16
     * @var array
17
     */
18
    protected $listeners = [];
19
20
    /**
21
     * Array of sorted listeners (flattened from listeners)
22
     *
23
     * @var array
24
     */
25
    protected $sortedListeners = [];
26
27
    /**
28
     * Configure EventDispatcher
29
     *
30
     * @param array $parameters
31
     * @return void
32 1
     */
33
    public function configure($parameters = [])
34 1
    {
35
        foreach ($parameters as $eventListenerData) {
36 1
            if (
37 1
                isset($eventListenerData['event']) &&
38
                isset($eventListenerData['listeners'])
39 1
            ) {
40 1
                foreach ((array) $eventListenerData['listeners'] as $listener) {
41 1
                    $listenerDefinition = explode('|', $listener);
42 1
                    $listenerName = $listenerDefinition[0];
43 1
                    $listenerPriority = isset($listenerDefinition[1])
44 1
                        ? (int) $listenerDefinition[1]
45 1
                        : 0;
46 1
                    $this->addListener(
47
                        $eventListenerData['event'],
48
                        $listenerName,
49
                        $listenerPriority
50
                    );
51
                }
52
            }
53 1
        }
54
    }
55
56
    /**
57
     * Declare event listened to
58
     *
59
     * @param string $event    One or more event to listen to
60
     * @param string $listener Listener class name
61
     * @param int    $priority Listener priority, 0 is high priority
62
     *
63
     * @return void
64 6
     */
65
    public function addListener($event, string $listener, int $priority = 0)
66 6
    {
67 1
        $eventType = is_subclass_of($event, '\Suricate\Event\Event')
68 6
            ? $event::getEventType()
69
            : $event;
70 6
71
        $this->listeners[$eventType][$priority][] = $listener;
72 6
73 6
        unset($this->sortedListeners[$eventType]);
74
    }
75
76
    /**
77
     * Dispatch an event
78
     *
79
     * @param string|\Suricate\Event\Event $event   Event to be dispatched
80
     * @param mixed                        $payload Optionnal event payload
81
     * @return void
82 3
     */
83
    public function fire($event, $payload = null)
84 3
    {
85 3
        $eventType = null;
86
        $eventPayload = null;
87
88 3
        if (
89 3
            is_object($event) &&
90
            is_subclass_of($event, '\Suricate\Event\Event')
91 1
        ) {
92 1
            $eventType = $event::getEventType();
93
            $eventPayload = $event;
94 3
        }
95 1
        if (is_string($event)) {
96 1
            $eventType = $event;
97
            $eventPayload = $payload;
98
        }
99 3
100 1
        if ($eventType === null) {
101 1
            throw new InvalidArgumentException(
102
                'Event type is not a string nor Event subclass'
103
            );
104
        }
105 2
106
        $impactedListeners = $this->getImpactedListeners($eventType);
107 2
108 2
        foreach ($impactedListeners as $listener) {
109 2
            Suricate::Logger()->debug(
110 2
                sprintf(
111
                    '[event] Passing event type: "%s" to "%s"',
112
                    $eventType,
113
                    $listener
114
                )
115
            );
116 2
            
117 2
            $result = with(new $listener($eventPayload, $eventType))->handle();
118 2
            if ($result === false) {
119 2
                Suricate::Logger()->debug(
120 2
                    sprintf(
121
                        '[event] stop propagation of event "%s"',
122
                        $eventType
123
                    )
124 2
                );
125
                break;
126
            }
127 2
        }
128
    }
129
130
    /**
131
     * Get list of eligible listeners for an event
132
     *
133
     * @param string $eventType
134
     * @return array
135 3
     */
136
    protected function getImpactedListeners(string $eventType): array
137 3
    {
138 1
        if (isset($this->sortedListeners[$eventType])) {
139
            return $this->sortedListeners[$eventType];
140 3
        }
141
        $this->sortListeners($eventType);
142 3
143
        return $this->sortedListeners[$eventType] ?? [];
144
    }
145
146
    /**
147
     * Sort and flatten listeners list according ot priority
148
     *
149
     * @param string $eventType event type
150
     * @return void
151 4
     */
152
    protected function sortListeners(string $eventType)
153 4
    {
154 4
        if (isset($this->listeners[$eventType])) {
155 4
            $listeners = $this->listeners[$eventType];
156 4
            ksort($listeners);
157
            $this->sortedListeners[$eventType] = flatten($listeners);
158 4
        }
159
    }
160
}
161