Passed
Push — master ( 8d0b59...1902d4 )
by Melech
09:45 queued 05:35
created

Collection::setFromData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Event\Collection;
15
16
use Valkyrja\Event\Collection\Contract\Collection as Contract;
17
use Valkyrja\Event\Data;
18
use Valkyrja\Event\Data\Contract\Listener;
19
use Valkyrja\Event\Data\Listener as Model;
20
use Valkyrja\Event\Exception\InvalidArgumentException;
21
22
use function array_keys;
23
use function is_array;
24
use function is_object;
25
use function is_string;
26
27
/**
28
 * Class Collection.
29
 *
30
 * @author Melech Mizrachi
31
 */
32
class Collection implements Contract
33
{
34
    /**
35
     * The events.
36
     *
37
     * @var array<class-string, string[]>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string, string[]> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, string[]>.
Loading history...
38
     */
39
    protected array $events = [];
40
41
    /**
42
     * The listeners.
43
     *
44
     * @var array<string, Listener|string>
45
     */
46
    protected array $listeners = [];
47
48
    /**
49
     * @inheritDoc
50
     */
51
    public function getData(): Data
52
    {
53
        $data = new Data();
54
55
        $data->events    = $this->events;
56
        $data->listeners = [];
57
58
        foreach ($this->listeners as $id => $listener) {
59
            $data->listeners[$id] = serialize($listener);
60
        }
61
62
        return $data;
63
    }
64
65
    /**
66
     * @inheritDoc
67
     */
68
    public function setFromData(Data $data): void
69
    {
70
        $this->events    = $data->events;
71
        $this->listeners = $data->listeners;
72
    }
73
74
    /**
75
     * @inheritDoc
76
     */
77
    public function hasListener(Listener $listener): bool
78
    {
79
        return $this->hasListenerById($listener->getName());
80
    }
81
82
    /**
83
     * @inheritDoc
84
     */
85
    public function hasListenerById(string $listenerId): bool
86
    {
87
        return isset($this->listeners[$listenerId]);
88
    }
89
90
    /**
91
     * @inheritDoc
92
     */
93
    public function addListener(Listener $listener): void
94
    {
95
        $listenerId = $listener->getName();
96
        $eventId    = $listener->getEventId();
97
98
        $this->events[$eventId] ??= [];
99
        $this->events[$eventId][$listenerId] = $listenerId;
100
        $this->listeners[$listenerId]        = $listener;
101
    }
102
103
    /**
104
     * @inheritDoc
105
     */
106
    public function removeListener(Listener $listener): void
107
    {
108
        $listenerId = $listener->getName();
109
        $eventId    = $listener->getEventId();
110
111
        unset($this->events[$eventId][$listenerId], $this->listeners[$listenerId]);
112
    }
113
114
    /**
115
     * @inheritDoc
116
     */
117
    public function removeListenerById(string $listenerId): void
118
    {
119
        foreach ($this->events as $eventId => $listeners) {
120
            unset($this->events[$eventId][$listenerId]);
121
        }
122
123
        unset($this->listeners[$listenerId]);
124
    }
125
126
    /**
127
     * @inheritDoc
128
     */
129
    public function hasListenersForEvent(object $event): bool
130
    {
131
        return isset($this->events[$event::class]);
132
    }
133
134
    /**
135
     * @inheritDoc
136
     */
137
    public function hasListenersForEventById(string $eventId): bool
138
    {
139
        return isset($this->events[$eventId]);
140
    }
141
142
    /**
143
     * @inheritDoc
144
     */
145
    public function getListenersForEvent(object $event): array
146
    {
147
        return $this->getListenersForEventById($event::class);
148
    }
149
150
    /**
151
     * @inheritDoc
152
     */
153
    public function getListenersForEventById(string $eventId): array
154
    {
155
        $listenerIds = $this->events[$eventId];
156
        $listeners   = [];
157
158
        foreach ($listenerIds as $listenerId) {
159
            $listener               = $this->listeners[$listenerId];
160
            $listeners[$listenerId] = $this->ensureListener($listener);
161
        }
162
163
        return $listeners;
164
    }
165
166
    /**
167
     * @inheritDoc
168
     */
169
    public function setListenersForEvent(object $event, Listener ...$listeners): void
170
    {
171
        $this->setListenersForEventById($event::class, ...$listeners);
172
    }
173
174
    /**
175
     * @inheritDoc
176
     */
177
    public function setListenersForEventById(string $eventId, Listener ...$listeners): void
178
    {
179
        foreach ($listeners as $listener) {
180
            $this->addListener(
181
                $listener->withEventId($eventId)
182
            );
183
        }
184
    }
185
186
    /**
187
     * @inheritDoc
188
     */
189
    public function removeListenersForEvent(object $event): void
190
    {
191
        $this->removeListenersForEventById($event::class);
192
    }
193
194
    /**
195
     * @inheritDoc
196
     */
197
    public function removeListenersForEventById(string $eventId): void
198
    {
199
        unset($this->events[$eventId]);
200
    }
201
202
    /**
203
     * @inheritDoc
204
     */
205
    public function getListeners(): array
206
    {
207
        return array_map(
208
            [$this, 'ensureListener'],
209
            $this->listeners
210
        );
211
    }
212
213
    /**
214
     * @inheritDoc
215
     */
216
    public function getEvents(): array
217
    {
218
        return array_keys($this->events);
219
    }
220
221
    /**
222
     * @inheritDoc
223
     */
224
    public function getEventsWithListeners(): array
225
    {
226
        $eventsWithListeners = [];
227
        $events              = $this->events;
228
229
        foreach ($events as $eventId => $listenerIds) {
230
            $eventsWithListeners[$eventId] = $this->getListenersForEventById($eventId);
231
        }
232
233
        return $eventsWithListeners;
234
    }
235
236
    /**
237
     * @inheritDoc
238
     */
239
    public function offsetGet($offset): array
240
    {
241
        if (is_object($offset)) {
242
            return $this->getListenersForEvent($offset);
243
        }
244
245
        return $this->getListenersForEventById($offset);
246
    }
247
248
    /**
249
     * @inheritDoc
250
     */
251
    public function offsetSet($offset, $value): void
252
    {
253
        $listeners = is_array($value) ? $value : [$value];
254
255
        if (is_object($offset)) {
256
            $this->setListenersForEvent($offset, ...$listeners);
257
258
            return;
259
        }
260
261
        $this->setListenersForEventById($offset, ...$listeners);
262
    }
263
264
    /**
265
     * @inheritDoc
266
     */
267
    public function offsetUnset($offset): void
268
    {
269
        if (is_object($offset)) {
270
            $this->removeListenersForEvent($offset);
271
272
            return;
273
        }
274
275
        $this->removeListenersForEventById($offset);
276
    }
277
278
    /**
279
     * @inheritDoc
280
     */
281
    public function offsetExists($offset): bool
282
    {
283
        if (is_object($offset)) {
284
            return $this->hasListenersForEvent($offset);
285
        }
286
287
        return $this->hasListenersForEventById($offset);
288
    }
289
290
    /**
291
     * Ensure a listener, or null, is returned.
292
     *
293
     * @param Listener|string $listener The listener
294
     *
295
     * @return Listener
296
     */
297
    protected function ensureListener(Listener|string $listener): Listener
298
    {
299
        if (is_string($listener)) {
300
            $unserializedListener = unserialize($listener, ['allowed_classes' => true]);
301
302
            if (! $unserializedListener instanceof Model) {
303
                throw new InvalidArgumentException('Invalid object serialized.');
304
            }
305
306
            return $unserializedListener;
307
        }
308
309
        return $listener;
310
    }
311
}
312