Passed
Pull Request — master (#19)
by Mathieu
11:01 queued 08:41
created

EventDispatcher::fire()   B

Complexity

Conditions 7
Paths 16

Size

Total Lines 43
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 7

Importance

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