Passed
Push — feature/events ( 9d660f...96fd77 )
by Mathieu
02:50
created

EventDispatcher::fire()   B

Complexity

Conditions 7
Paths 16

Size

Total Lines 40
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

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