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