Completed
Pull Request — master (#358)
by Luc
05:10
created

replaceKeywordWithLabel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3;
4
5
use Broadway\Serializer\SerializerInterface;
6
use Broadway\Serializer\SimpleInterfaceSerializer;
7
use CultuurNet\UDB3\Event\Events\BookingInfoUpdated as EventBookingInfoUpdated;
8
use CultuurNet\UDB3\Event\Events\ContactPointUpdated as EventContactPointUpdated;
9
use CultuurNet\UDB3\Event\Events\DescriptionTranslated;
10
use CultuurNet\UDB3\Event\Events\DescriptionUpdated as EventDescriptionUpdated;
11
use CultuurNet\UDB3\Event\Events\EventDeleted;
12
use CultuurNet\UDB3\Event\Events\EventImportedFromUDB2;
13
use CultuurNet\UDB3\Event\Events\LabelAdded;
14
use CultuurNet\UDB3\Event\Events\LabelRemoved;
15
use CultuurNet\UDB3\Event\Events\MajorInfoUpdated;
16
use CultuurNet\UDB3\Event\Events\OrganizerDeleted as EventOrganizerDeleted;
17
use CultuurNet\UDB3\Event\Events\OrganizerUpdated as EventOrganizerUpdated;
18
use CultuurNet\UDB3\Event\Events\TitleTranslated;
19
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted as EventTypicalAgeRangeDeleted;
20
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated as EventTypicalAgeRangeUpdated;
21
use CultuurNet\UDB3\EventSourcing\PayloadManipulatingSerializer;
22
use CultuurNet\UDB3\Label\ReadModels\JSON\Repository\ReadRepositoryInterface;
23
use CultuurNet\UDB3\Label\ValueObjects\Visibility;
24
use CultuurNet\UDB3\Place\Events\BookingInfoUpdated as PlaceBookingInfoUpdated;
25
use CultuurNet\UDB3\Place\Events\ContactPointUpdated as PlaceContactPointUpdated;
26
use CultuurNet\UDB3\Place\Events\DescriptionUpdated as PlaceDescriptionUpdated;
27
use CultuurNet\UDB3\Place\Events\OrganizerDeleted as PlaceOrganizerDeleted;
28
use CultuurNet\UDB3\Place\Events\OrganizerUpdated as PlaceOrganizerUpdated;
29
use CultuurNet\UDB3\Place\Events\PlaceDeleted;
30
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeDeleted as PlaceTypicalAgeRangeDeleted;
31
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeUpdated as PlaceTypicalAgeRangeUpdated;
32
use ValueObjects\Identity\UUID;
33
34
/**
35
 * Factory chaining together the logic to manipulate the payload of old events
36
 * in order to make it usable by new events.
37
 *
38
 * Some cases:
39
 * - changing the class name / namespace after class renames
40
 * - changing the names of properties
41
 */
42
class BackwardsCompatiblePayloadSerializerFactory
43
{
44
    private function __construct()
45
    {
46
47
    }
48
49
    /**
50
     * @param ReadRepositoryInterface $labelRepository
51
     * @return SerializerInterface
52
     */
53
    public static function createSerializer(ReadRepositoryInterface $labelRepository)
54
    {
55
        $payloadManipulatingSerializer = new PayloadManipulatingSerializer(
56
            new SimpleInterfaceSerializer()
57
        );
58
59
        /*
60
         * CREATE EVENTS
61
         *
62
         */
63
64
        $payloadManipulatingSerializer->manipulateEventsOfClass(
65
            'CultuurNet\UDB3\Event\Events\EventCreated',
66
            function (array $serializedObject) {
67
                return self::addDefaultMainLanguage($serializedObject);
68
            }
69
        );
70
71
        $payloadManipulatingSerializer->manipulateEventsOfClass(
72
            'CultuurNet\UDB3\Place\Events\PlaceCreated',
73
            function (array $serializedObject) {
74
                return self::addDefaultMainLanguage($serializedObject);
75
            }
76
        );
77
78
        $payloadManipulatingSerializer->manipulateEventsOfClass(
79
            'CultuurNet\UDB3\Organizer\Events\OrganizerCreatedWithUniqueWebsite',
80
            function (array $serializedObject) {
81
                return self::addDefaultMainLanguage($serializedObject);
82
            }
83
        );
84
85
        /*
86
         * TRANSLATION EVENTS
87
         */
88
89
        $payloadManipulatingSerializer->manipulateEventsOfClass(
90
            'CultuurNet\UDB3\Event\TitleTranslated',
91
            function (array $serializedObject) {
92
                $serializedObject['class'] = TitleTranslated::class;
93
94
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
95
96
                return $serializedObject;
97
            }
98
        );
99
100
        $payloadManipulatingSerializer->manipulateEventsOfClass(
101
            'CultuurNet\UDB3\Event\DescriptionTranslated',
102
            function (array $serializedObject) {
103
                $serializedObject['class'] = DescriptionTranslated::class;
104
105
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
106
107
                return $serializedObject;
108
            }
109
        );
110
111
        /*
112
         * LABEL EVENTS
113
         */
114
115
        $payloadManipulatingSerializer->manipulateEventsOfClass(
116
            'CultuurNet\UDB3\Label\Events\MadeInvisible',
117
            function (array $serializedObject) use ($labelRepository) {
118
                return self::addLabelName($serializedObject, $labelRepository);
119
            }
120
        );
121
122
        $payloadManipulatingSerializer->manipulateEventsOfClass(
123
            'CultuurNet\UDB3\Label\Events\MadeVisible',
124
            function (array $serializedObject) use ($labelRepository) {
125
                return self::addLabelName($serializedObject, $labelRepository);
126
            }
127
        );
128
129
        $payloadManipulatingSerializer->manipulateEventsOfClass(
130
            'CultuurNet\UDB3\Label\Events\MadePrivate',
131
            function (array $serializedObject) use ($labelRepository) {
132
                return self::addLabelName($serializedObject, $labelRepository);
133
            }
134
        );
135
136
        $payloadManipulatingSerializer->manipulateEventsOfClass(
137
            'CultuurNet\UDB3\Label\Events\MadePublic',
138
            function (array $serializedObject) use ($labelRepository) {
139
                return self::addLabelName($serializedObject, $labelRepository);
140
            }
141
        );
142
143
        $payloadManipulatingSerializer->manipulateEventsOfClass(
144
            'CultuurNet\UDB3\Organizer\Events\LabelAdded',
145
            function (array $serializedObject) use ($labelRepository) {
146
                return self::fixOrganizerLabelEvent($serializedObject, $labelRepository);
147
            }
148
        );
149
150
        $payloadManipulatingSerializer->manipulateEventsOfClass(
151
            'CultuurNet\UDB3\Organizer\Events\LabelRemoved',
152
            function (array $serializedObject) use ($labelRepository) {
153
                return self::fixOrganizerLabelEvent($serializedObject, $labelRepository);
154
            }
155
        );
156
157
        $payloadManipulatingSerializer->manipulateEventsOfClass(
158
            'CultuurNet\UDB3\Event\Events\EventWasLabelled',
159
            function (array $serializedObject) {
160
                $serializedObject['class'] = LabelAdded::class;
161
162
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
163
164
                return $serializedObject;
165
            }
166
        );
167
168
        $payloadManipulatingSerializer->manipulateEventsOfClass(
169
            'CultuurNet\UDB3\Event\EventWasTagged',
170
            function (array $serializedObject) {
171
                $serializedObject['class'] = LabelAdded::class;
172
173
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
174
175
                $serializedObject = self::replaceKeywordWithLabel($serializedObject);
176
177
                return $serializedObject;
178
            }
179
        );
180
181
        $payloadManipulatingSerializer->manipulateEventsOfClass(
182
            'CultuurNet\UDB3\Event\TagErased',
183
            function (array $serializedObject) {
184
                $serializedObject['class'] = LabelRemoved::class;
185
186
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
187
188
                $serializedObject = self::replaceKeywordWithLabel($serializedObject);
189
190
                return $serializedObject;
191
            }
192
        );
193
194
        $payloadManipulatingSerializer->manipulateEventsOfClass(
195
            'CultuurNet\UDB3\Event\Events\Unlabelled',
196
            function (array $serializedObject) {
197
                $serializedObject['class'] = LabelRemoved::class;
198
199
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
200
201
                return $serializedObject;
202
            }
203
        );
204
205
        /**
206
         * UBD2 IMPORT
207
         */
208
209
        $payloadManipulatingSerializer->manipulateEventsOfClass(
210
            'CultuurNet\UDB3\Event\EventImportedFromUDB2',
211
            function (array $serializedObject) {
212
                $serializedObject['class'] = EventImportedFromUDB2::class;
213
214
                return $serializedObject;
215
            }
216
        );
217
218
        /**
219
         * PLACE FACILITIES EVENT
220
         */
221
        $payloadManipulatingSerializer->manipulateEventsOfClass(
222
            'CultuurNet\UDB3\Place\Events\FacilitiesUpdated',
223
            function (array $serializedObject) {
224
                $serializedObject = self::replacePlaceIdWithItemId($serializedObject);
225
226
                return $serializedObject;
227
            }
228
        );
229
230
        /**
231
         * GEOCOORDINATES UPDATED EVENT
232
         */
233
        $payloadManipulatingSerializer->manipulateEventsOfClass(
234
            'CultuurNet\UDB3\Place\Events\GeoCoordinatesUpdated',
235
            function (array $serializedObject) {
236
                $serializedObject = self::replacePlaceIdWithItemId($serializedObject);
237
238
                return $serializedObject;
239
            }
240
        );
241
242
        /**
243
         * BOOKING INFO EVENT
244
         */
245
        $manipulateAvailability = function (array $serializedBookingInfo, $propertyName) {
246
            if (!isset($serializedBookingInfo[$propertyName]) || empty($serializedBookingInfo[$propertyName])) {
247
                $serializedBookingInfo[$propertyName] = null;
248
                return $serializedBookingInfo;
249
            }
250
251
            $dateTimeString = $serializedBookingInfo[$propertyName];
252
253
            // The new serialized date time format is a string according the ISO 8601 format.
254
            // If this is so return without modifications.
255
            $dateTimeFromAtom = \DateTimeImmutable::createFromFormat(\DATE_ATOM, $dateTimeString);
256
            if ($dateTimeFromAtom) {
257
                return $serializedBookingInfo;
258
            }
259
260
            // For older format a modification is needed to ISO 8601 format.
261
            $dateTimeFromAtomWithMilliseconds = \DateTimeImmutable::createFromFormat(
262
                'Y-m-d\TH:i:s.uP',
263
                $dateTimeString
264
            );
265
            if ($dateTimeFromAtomWithMilliseconds) {
266
                $serializedBookingInfo[$propertyName] = $dateTimeFromAtomWithMilliseconds->format(\DATE_ATOM);
267
                return $serializedBookingInfo;
268
            }
269
270
            // In case of unknown format clear the available date property.
271
            unset($serializedBookingInfo[$propertyName]);
272
            return $serializedBookingInfo;
273
        };
274
275
        $manipulateBookingInfoEvent = function (array $serializedEvent) use ($manipulateAvailability) {
276
            $serializedEvent = self::replaceEventIdWithItemId($serializedEvent);
277
            $serializedEvent = self::replacePlaceIdWithItemId($serializedEvent);
278
279
            $serializedBookingInfo = $serializedEvent['payload']['bookingInfo'];
280
            $serializedBookingInfo = $manipulateAvailability($serializedBookingInfo, 'availabilityStarts');
281
            $serializedBookingInfo = $manipulateAvailability($serializedBookingInfo, 'availabilityEnds');
282
            $serializedEvent['payload']['bookingInfo'] = $serializedBookingInfo;
283
284
            return $serializedEvent;
285
        };
286
287
        $payloadManipulatingSerializer->manipulateEventsOfClass(
288
            EventBookingInfoUpdated::class,
289
            $manipulateBookingInfoEvent
290
        );
291
292
        $payloadManipulatingSerializer->manipulateEventsOfClass(
293
            PlaceBookingInfoUpdated::class,
294
            $manipulateBookingInfoEvent
295
        );
296
297
        /**
298
         * EventEvent to AbstractEvent (Offer)
299
         */
300
        $refactoredEventEvents = [
301
            EventTypicalAgeRangeDeleted::class,
302
            EventTypicalAgeRangeUpdated::class,
303
            EventContactPointUpdated::class,
304
            MajorInfoUpdated::class,
305
            EventOrganizerUpdated::class,
306
            EventOrganizerDeleted::class,
307
            EventDescriptionUpdated::class,
308
            EventDeleted::class,
309
        ];
310
311
        foreach ($refactoredEventEvents as $refactoredEventEvent) {
312
            $payloadManipulatingSerializer->manipulateEventsOfClass(
313
                $refactoredEventEvent,
314
                function (array $serializedObject) {
315
                    $serializedObject = self::replaceEventIdWithItemId($serializedObject);
316
                    return $serializedObject;
317
                }
318
            );
319
        }
320
321
        /**
322
         * PlaceEvent to AbstractEvent (Offer)
323
         */
324
        $refactoredPlaceEvents = [
325
            PlaceOrganizerUpdated::class,
326
            PlaceOrganizerDeleted::class,
327
            PlaceTypicalAgeRangeDeleted::class,
328
            PlaceTypicalAgeRangeUpdated::class,
329
            PlaceContactPointUpdated::class,
330
            PlaceDescriptionUpdated::class,
331
            PlaceDeleted::class,
332
        ];
333
334
        foreach ($refactoredPlaceEvents as $refactoredPlaceEvent) {
335
            $payloadManipulatingSerializer->manipulateEventsOfClass(
336
                $refactoredPlaceEvent,
337
                function (array $serializedObject) {
338
                    $serializedObject = self::replacePlaceIdWithItemId($serializedObject);
339
                    return $serializedObject;
340
                }
341
            );
342
        }
343
344
        return $payloadManipulatingSerializer;
345
    }
346
347
    /**
348
     * @param array $serializedObject
349
     * @return array
350
     */
351
    private static function replaceEventIdWithItemId(array $serializedObject)
352
    {
353
        return self::replaceKeys('event_id', 'item_id', $serializedObject);
354
    }
355
356
    /**
357
     * @param array $serializedObject
358
     * @return array
359
     */
360
    private static function replacePlaceIdWithItemId(array $serializedObject)
361
    {
362
        return self::replaceKeys('place_id', 'item_id', $serializedObject);
363
    }
364
365
    /**
366
     * @param string $oldKey
367
     * @param string $newKey
368
     * @param array $serializedObject
369
     * @return array
370
     */
371
    private static function replaceKeys($oldKey, $newKey, $serializedObject)
372
    {
373
        if (isset($serializedObject['payload'][$oldKey])) {
374
            $value = $serializedObject['payload'][$oldKey];
375
            $serializedObject['payload'][$newKey] = $value;
376
            unset($serializedObject['payload'][$oldKey]);
377
        }
378
379
        return $serializedObject;
380
    }
381
382
    /**
383
     * @param array $serializedObject
384
     * @return array
385
     */
386
    private static function replaceKeywordWithLabel(array $serializedObject)
387
    {
388
        $keyword = $serializedObject['payload']['keyword'];
389
        $serializedObject['payload']['label'] = $keyword;
390
        unset($serializedObject['payload']['keyword']);
391
392
        return $serializedObject;
393
    }
394
395
    /**
396
     * @param array $serializedObject
397
     * @param ReadRepositoryInterface $labelRepository
398
     * @return array
399
     */
400
    private static function addLabelName(
401
        array $serializedObject,
402
        ReadRepositoryInterface $labelRepository
403
    ) {
404
        if (!isset($serializedObject['payload']['name'])) {
405
            $uuid = $serializedObject['payload']['uuid'];
406
            $label = $labelRepository->getByUuid(new UUID($uuid));
407
408
            $serializedObject['payload']['name'] = $label->getName()->toNative();
409
        }
410
411
        return $serializedObject;
412
    }
413
414
    /**
415
     * @param array $serializedObject
416
     * @param ReadRepositoryInterface $labelRepository
417
     * @return array
418
     */
419
    private static function fixOrganizerLabelEvent(
420
        array $serializedObject,
421
        ReadRepositoryInterface $labelRepository
422
    ) {
423
        if (!isset($serializedObject['payload']['label']) ||
424
            !isset($serializedObject['payload']['visibility'])) {
425
            $uuid = $serializedObject['payload']['labelId'];
426
            $label = $labelRepository->getByUuid(new UUID($uuid));
427
428
            $serializedObject['payload']['label'] = $label->getName()->toNative();
429
            $serializedObject['payload']['visibility'] = $label->getVisibility() === Visibility::VISIBLE();
430
        }
431
432
        return $serializedObject;
433
    }
434
435
    /**
436
     * @param array $serializedObject
437
     * @return array
438
     */
439
    private static function addDefaultMainLanguage(array $serializedObject)
440
    {
441
        if (!isset($serializedObject['payload']['main_language'])) {
442
            $mainLanguage = new Language('nl');
443
            $serializedObject['payload']['main_language'] = $mainLanguage->getCode();
444
        }
445
446
        return $serializedObject;
447
    }
448
}
449