Completed
Push — feature/events ( 96fd77...b5e13c )
by Mathieu
02:04
created

EventDispatcher::configure()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 13
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 17
ccs 14
cts 14
cp 1
crap 6
rs 9.2222
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 1
                        $listenerName,
45 1
                        $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 6
    public function addListener($event, string $listener, int $priority = 0)
62
    {
63 6
        $eventType = is_subclass_of($event, '\Suricate\Event')
64 1
            ? $event::getEventType()
65 6
            : $event;
66
67 6
        $this->listeners[$eventType][$priority][] = $listener;
68
69 6
        unset($this->sortedListeners[$eventType]);
70 6
    }
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 3
    public function fire($event, $payload = null)
80
    {
81 3
        $eventType = null;
82 3
        $eventPayload = null;
83
84 3
        if (is_object($event) && is_subclass_of($event, '\Suricate\Event')) {
85 1
            $eventType = $event::getEventType();
86 1
            $eventPayload = $event;
87
        }
88 3
        if (is_string($event)) {
89 1
            $eventType = $event;
90 1
            $eventPayload = $payload;
91
        }
92
93 3
        if ($eventType === null) {
94 1
            throw new \InvalidArgumentException(
95 1
                'Event type is not a string nor Event subclass'
96
            );
97
        }
98
99 2
        $impactedListeners = $this->getImpactedListeners($eventType);
100
101 2
        foreach ($impactedListeners as $listener) {
102 2
            Suricate::Logger()->debug(
103 2
                sprintf(
104 2
                    '[event] Passing event type: "%s" to "%s"',
105 2
                    $eventType,
106 2
                    $listener
107
                )
108
            );
109
110 2
            $result = with(new $listener($eventPayload))->handle();
111 2
            if ($result === false) {
112 2
                Suricate::Logger()->debug(
113 2
                    sprintf(
114 2
                        '[event] stop propagation of event "%s"',
115 2
                        $eventType
116
                    )
117
                );
118 2
                break;
119
            }
120
        }
121 2
    }
122
123
    /**
124
     * Get list of eligible listeners for an event
125
     *
126
     * @param string $eventType
127
     * @return array
128
     */
129 3
    protected function getImpactedListeners(string $eventType): array
130
    {
131 3
        if (isset($this->sortedListeners[$eventType])) {
132 1
            return $this->sortedListeners[$eventType];
133
        }
134 3
        $this->sortListeners($eventType);
135
136 3
        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 4
    protected function sortListeners(string $eventType)
146
    {
147 4
        if (isset($this->listeners[$eventType])) {
148 4
            $listeners = $this->listeners[$eventType];
149 4
            ksort($listeners);
150 4
            $this->sortedListeners[$eventType] = flatten($listeners);
151
        }
152 4
    }
153
}
154