Completed
Pull Request — master (#359)
by Luc
07:09
created

createSerializer()   D

Complexity

Conditions 10
Paths 8

Size

Total Lines 324
Code Lines 171

Duplication

Lines 18
Ratio 5.56 %

Importance

Changes 0
Metric Value
dl 18
loc 324
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 171
nc 8
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\PriceInfoUpdated as EventPriceInfoUpdated;
19
use CultuurNet\UDB3\Event\Events\TitleTranslated;
20
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted as EventTypicalAgeRangeDeleted;
21
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated as EventTypicalAgeRangeUpdated;
22
use CultuurNet\UDB3\EventSourcing\PayloadManipulatingSerializer;
23
use CultuurNet\UDB3\Label\ReadModels\JSON\Repository\ReadRepositoryInterface;
24
use CultuurNet\UDB3\Label\ValueObjects\Visibility;
25
use CultuurNet\UDB3\Place\Events\BookingInfoUpdated as PlaceBookingInfoUpdated;
26
use CultuurNet\UDB3\Place\Events\ContactPointUpdated as PlaceContactPointUpdated;
27
use CultuurNet\UDB3\Place\Events\DescriptionUpdated as PlaceDescriptionUpdated;
28
use CultuurNet\UDB3\Place\Events\OrganizerDeleted as PlaceOrganizerDeleted;
29
use CultuurNet\UDB3\Place\Events\OrganizerUpdated as PlaceOrganizerUpdated;
30
use CultuurNet\UDB3\Place\Events\PlaceDeleted;
31
use CultuurNet\UDB3\Place\Events\PriceInfoUpdated as PlacePriceInfoUpdated;
32
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeDeleted as PlaceTypicalAgeRangeDeleted;
33
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeUpdated as PlaceTypicalAgeRangeUpdated;
34
use ValueObjects\Identity\UUID;
35
36
/**
37
 * Factory chaining together the logic to manipulate the payload of old events
38
 * in order to make it usable by new events.
39
 *
40
 * Some cases:
41
 * - changing the class name / namespace after class renames
42
 * - changing the names of properties
43
 */
44
class BackwardsCompatiblePayloadSerializerFactory
45
{
46
    private function __construct()
47
    {
48
49
    }
50
51
    /**
52
     * @param ReadRepositoryInterface $labelRepository
53
     * @return SerializerInterface
54
     */
55
    public static function createSerializer(ReadRepositoryInterface $labelRepository)
56
    {
57
        $payloadManipulatingSerializer = new PayloadManipulatingSerializer(
58
            new SimpleInterfaceSerializer()
59
        );
60
61
        /*
62
         * CREATE EVENTS
63
         *
64
         */
65
66
        $payloadManipulatingSerializer->manipulateEventsOfClass(
67
            'CultuurNet\UDB3\Event\Events\EventCreated',
68
            function (array $serializedObject) {
69
                return self::addDefaultMainLanguage($serializedObject);
70
            }
71
        );
72
73
        $payloadManipulatingSerializer->manipulateEventsOfClass(
74
            'CultuurNet\UDB3\Place\Events\PlaceCreated',
75
            function (array $serializedObject) {
76
                return self::addDefaultMainLanguage($serializedObject);
77
            }
78
        );
79
80
        $payloadManipulatingSerializer->manipulateEventsOfClass(
81
            'CultuurNet\UDB3\Organizer\Events\OrganizerCreatedWithUniqueWebsite',
82
            function (array $serializedObject) {
83
                return self::addDefaultMainLanguage($serializedObject);
84
            }
85
        );
86
87
        /*
88
         * TRANSLATION EVENTS
89
         */
90
91
        $payloadManipulatingSerializer->manipulateEventsOfClass(
92
            'CultuurNet\UDB3\Event\TitleTranslated',
93
            function (array $serializedObject) {
94
                $serializedObject['class'] = TitleTranslated::class;
95
96
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
97
98
                return $serializedObject;
99
            }
100
        );
101
102
        $payloadManipulatingSerializer->manipulateEventsOfClass(
103
            'CultuurNet\UDB3\Event\DescriptionTranslated',
104
            function (array $serializedObject) {
105
                $serializedObject['class'] = DescriptionTranslated::class;
106
107
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
108
109
                return $serializedObject;
110
            }
111
        );
112
113
        /*
114
         * LABEL EVENTS
115
         */
116
117
        $payloadManipulatingSerializer->manipulateEventsOfClass(
118
            'CultuurNet\UDB3\Label\Events\MadeInvisible',
119
            function (array $serializedObject) use ($labelRepository) {
120
                return self::addLabelName($serializedObject, $labelRepository);
121
            }
122
        );
123
124
        $payloadManipulatingSerializer->manipulateEventsOfClass(
125
            'CultuurNet\UDB3\Label\Events\MadeVisible',
126
            function (array $serializedObject) use ($labelRepository) {
127
                return self::addLabelName($serializedObject, $labelRepository);
128
            }
129
        );
130
131
        $payloadManipulatingSerializer->manipulateEventsOfClass(
132
            'CultuurNet\UDB3\Label\Events\MadePrivate',
133
            function (array $serializedObject) use ($labelRepository) {
134
                return self::addLabelName($serializedObject, $labelRepository);
135
            }
136
        );
137
138
        $payloadManipulatingSerializer->manipulateEventsOfClass(
139
            'CultuurNet\UDB3\Label\Events\MadePublic',
140
            function (array $serializedObject) use ($labelRepository) {
141
                return self::addLabelName($serializedObject, $labelRepository);
142
            }
143
        );
144
145
        $payloadManipulatingSerializer->manipulateEventsOfClass(
146
            'CultuurNet\UDB3\Organizer\Events\LabelAdded',
147
            function (array $serializedObject) use ($labelRepository) {
148
                return self::fixOrganizerLabelEvent($serializedObject, $labelRepository);
149
            }
150
        );
151
152
        $payloadManipulatingSerializer->manipulateEventsOfClass(
153
            'CultuurNet\UDB3\Organizer\Events\LabelRemoved',
154
            function (array $serializedObject) use ($labelRepository) {
155
                return self::fixOrganizerLabelEvent($serializedObject, $labelRepository);
156
            }
157
        );
158
159
        $payloadManipulatingSerializer->manipulateEventsOfClass(
160
            'CultuurNet\UDB3\Event\Events\EventWasLabelled',
161
            function (array $serializedObject) {
162
                $serializedObject['class'] = LabelAdded::class;
163
164
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
165
166
                return $serializedObject;
167
            }
168
        );
169
170
        $payloadManipulatingSerializer->manipulateEventsOfClass(
171
            'CultuurNet\UDB3\Event\EventWasTagged',
172 View Code Duplication
            function (array $serializedObject) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
                $serializedObject['class'] = LabelAdded::class;
174
175
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
176
177
                $serializedObject = self::replaceKeywordWithLabel($serializedObject);
178
179
                return $serializedObject;
180
            }
181
        );
182
183
        $payloadManipulatingSerializer->manipulateEventsOfClass(
184
            'CultuurNet\UDB3\Event\TagErased',
185 View Code Duplication
            function (array $serializedObject) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
                $serializedObject['class'] = LabelRemoved::class;
187
188
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
189
190
                $serializedObject = self::replaceKeywordWithLabel($serializedObject);
191
192
                return $serializedObject;
193
            }
194
        );
195
196
        $payloadManipulatingSerializer->manipulateEventsOfClass(
197
            'CultuurNet\UDB3\Event\Events\Unlabelled',
198
            function (array $serializedObject) {
199
                $serializedObject['class'] = LabelRemoved::class;
200
201
                $serializedObject = self::replaceEventIdWithItemId($serializedObject);
202
203
                return $serializedObject;
204
            }
205
        );
206
207
        /**
208
         * UBD2 IMPORT
209
         */
210
211
        $payloadManipulatingSerializer->manipulateEventsOfClass(
212
            'CultuurNet\UDB3\Event\EventImportedFromUDB2',
213
            function (array $serializedObject) {
214
                $serializedObject['class'] = EventImportedFromUDB2::class;
215
216
                return $serializedObject;
217
            }
218
        );
219
220
        /**
221
         * PLACE FACILITIES EVENT
222
         */
223
        $payloadManipulatingSerializer->manipulateEventsOfClass(
224
            'CultuurNet\UDB3\Place\Events\FacilitiesUpdated',
225
            function (array $serializedObject) {
226
                $serializedObject = self::replacePlaceIdWithItemId($serializedObject);
227
228
                return $serializedObject;
229
            }
230
        );
231
232
        /**
233
         * GEOCOORDINATES UPDATED EVENT
234
         */
235
        $payloadManipulatingSerializer->manipulateEventsOfClass(
236
            'CultuurNet\UDB3\Place\Events\GeoCoordinatesUpdated',
237
            function (array $serializedObject) {
238
                $serializedObject = self::replacePlaceIdWithItemId($serializedObject);
239
240
                return $serializedObject;
241
            }
242
        );
243
244
        /**
245
         * BOOKING INFO EVENT
246
         */
247
        $manipulateAvailability = function (array $serializedBookingInfo, $propertyName) {
248
            if (!isset($serializedBookingInfo[$propertyName]) || empty($serializedBookingInfo[$propertyName])) {
249
                $serializedBookingInfo[$propertyName] = null;
250
                return $serializedBookingInfo;
251
            }
252
253
            $dateTimeString = $serializedBookingInfo[$propertyName];
254
255
            // The new serialized date time format is a string according the ISO 8601 format.
256
            // If this is so return without modifications.
257
            $dateTimeFromAtom = \DateTimeImmutable::createFromFormat(\DATE_ATOM, $dateTimeString);
258
            if ($dateTimeFromAtom) {
259
                return $serializedBookingInfo;
260
            }
261
262
            // For older format a modification is needed to ISO 8601 format.
263
            $dateTimeFromAtomWithMilliseconds = \DateTimeImmutable::createFromFormat(
264
                'Y-m-d\TH:i:s.uP',
265
                $dateTimeString
266
            );
267
            if ($dateTimeFromAtomWithMilliseconds) {
268
                $serializedBookingInfo[$propertyName] = $dateTimeFromAtomWithMilliseconds->format(\DATE_ATOM);
269
                return $serializedBookingInfo;
270
            }
271
272
            // In case of unknown format clear the available date property.
273
            unset($serializedBookingInfo[$propertyName]);
274
            return $serializedBookingInfo;
275
        };
276
277
        $manipulateBookingInfoEvent = function (array $serializedEvent) use ($manipulateAvailability) {
278
            $serializedEvent = self::replaceEventIdWithItemId($serializedEvent);
279
            $serializedEvent = self::replacePlaceIdWithItemId($serializedEvent);
280
281
            $serializedBookingInfo = $serializedEvent['payload']['bookingInfo'];
282
            $serializedBookingInfo = $manipulateAvailability($serializedBookingInfo, 'availabilityStarts');
283
            $serializedBookingInfo = $manipulateAvailability($serializedBookingInfo, 'availabilityEnds');
284
            $serializedEvent['payload']['bookingInfo'] = $serializedBookingInfo;
285
286
            return $serializedEvent;
287
        };
288
289
        $payloadManipulatingSerializer->manipulateEventsOfClass(
290
            EventBookingInfoUpdated::class,
291
            $manipulateBookingInfoEvent
292
        );
293
294
        $payloadManipulatingSerializer->manipulateEventsOfClass(
295
            PlaceBookingInfoUpdated::class,
296
            $manipulateBookingInfoEvent
297
        );
298
299
        /**
300
         * EventEvent to AbstractEvent (Offer)
301
         */
302
        $refactoredEventEvents = [
303
            EventTypicalAgeRangeDeleted::class,
304
            EventTypicalAgeRangeUpdated::class,
305
            EventContactPointUpdated::class,
306
            MajorInfoUpdated::class,
307
            EventOrganizerUpdated::class,
308
            EventOrganizerDeleted::class,
309
            EventDescriptionUpdated::class,
310
            EventDeleted::class,
311
        ];
312
313
        foreach ($refactoredEventEvents as $refactoredEventEvent) {
314
            $payloadManipulatingSerializer->manipulateEventsOfClass(
315
                $refactoredEventEvent,
316
                function (array $serializedObject) {
317
                    $serializedObject = self::replaceEventIdWithItemId($serializedObject);
318
                    return $serializedObject;
319
                }
320
            );
321
        }
322
323
        /**
324
         * PlaceEvent to AbstractEvent (Offer)
325
         */
326
        $refactoredPlaceEvents = [
327
            PlaceOrganizerUpdated::class,
328
            PlaceOrganizerDeleted::class,
329
            PlaceTypicalAgeRangeDeleted::class,
330
            PlaceTypicalAgeRangeUpdated::class,
331
            PlaceContactPointUpdated::class,
332
            PlaceDescriptionUpdated::class,
333
            PlaceDeleted::class,
334
        ];
335
336
        foreach ($refactoredPlaceEvents as $refactoredPlaceEvent) {
337
            $payloadManipulatingSerializer->manipulateEventsOfClass(
338
                $refactoredPlaceEvent,
339
                function (array $serializedObject) {
340
                    $serializedObject = self::replacePlaceIdWithItemId($serializedObject);
341
                    return $serializedObject;
342
                }
343
            );
344
        }
345
346
        /**
347
         * PriceInfoUpdated events
348
         */
349
        $priceInfoEvents = [
350
            EventPriceInfoUpdated::class,
351
            PlacePriceInfoUpdated::class,
352
        ];
353
354
        foreach ($priceInfoEvents as $priceInfoEvent) {
355
            $payloadManipulatingSerializer->manipulateEventsOfClass(
356
                $priceInfoEvent,
357
                function (array $serializedObject) {
358
                    $payload = &$serializedObject['payload'];
359
                    $priceInfo = &$payload['price_info'];
360
                    $tariffs = array_map(
361
                        function (array $tariff) {
362
                            $name = $tariff['name'];
363
                            if (is_string($name)) {
364
                                $name = ['nl' => $name];
365
                            }
366
                            $tariff['name'] = $name;
367
                            return $tariff;
368
                        },
369
                        isset($priceInfo['tariffs']) ? $priceInfo['tariffs'] : []
370
                    );
371
                    $priceInfo['tariffs'] = $tariffs;
372
                    return $serializedObject;
373
                }
374
            );
375
        }
376
377
        return $payloadManipulatingSerializer;
378
    }
379
380
    /**
381
     * @param array $serializedObject
382
     * @return array
383
     */
384
    private static function replaceEventIdWithItemId(array $serializedObject)
385
    {
386
        return self::replaceKeys('event_id', 'item_id', $serializedObject);
387
    }
388
389
    /**
390
     * @param array $serializedObject
391
     * @return array
392
     */
393
    private static function replacePlaceIdWithItemId(array $serializedObject)
394
    {
395
        return self::replaceKeys('place_id', 'item_id', $serializedObject);
396
    }
397
398
    /**
399
     * @param string $oldKey
400
     * @param string $newKey
401
     * @param array $serializedObject
402
     * @return array
403
     */
404
    private static function replaceKeys($oldKey, $newKey, $serializedObject)
405
    {
406
        if (isset($serializedObject['payload'][$oldKey])) {
407
            $value = $serializedObject['payload'][$oldKey];
408
            $serializedObject['payload'][$newKey] = $value;
409
            unset($serializedObject['payload'][$oldKey]);
410
        }
411
412
        return $serializedObject;
413
    }
414
415
    /**
416
     * @param array $serializedObject
417
     * @return array
418
     */
419
    private static function replaceKeywordWithLabel(array $serializedObject)
420
    {
421
        $keyword = $serializedObject['payload']['keyword'];
422
        $serializedObject['payload']['label'] = $keyword;
423
        unset($serializedObject['payload']['keyword']);
424
425
        return $serializedObject;
426
    }
427
428
    /**
429
     * @param array $serializedObject
430
     * @param ReadRepositoryInterface $labelRepository
431
     * @return array
432
     */
433
    private static function addLabelName(
434
        array $serializedObject,
435
        ReadRepositoryInterface $labelRepository
436
    ) {
437
        if (!isset($serializedObject['payload']['name'])) {
438
            $uuid = $serializedObject['payload']['uuid'];
439
            $label = $labelRepository->getByUuid(new UUID($uuid));
440
441
            $serializedObject['payload']['name'] = $label->getName()->toNative();
442
        }
443
444
        return $serializedObject;
445
    }
446
447
    /**
448
     * @param array $serializedObject
449
     * @param ReadRepositoryInterface $labelRepository
450
     * @return array
451
     */
452
    private static function fixOrganizerLabelEvent(
453
        array $serializedObject,
454
        ReadRepositoryInterface $labelRepository
455
    ) {
456
        if (!isset($serializedObject['payload']['label']) ||
457
            !isset($serializedObject['payload']['visibility'])) {
458
            $uuid = $serializedObject['payload']['labelId'];
459
            $label = $labelRepository->getByUuid(new UUID($uuid));
460
461
            $serializedObject['payload']['label'] = $label->getName()->toNative();
462
            $serializedObject['payload']['visibility'] = $label->getVisibility() === Visibility::VISIBLE();
463
        }
464
465
        return $serializedObject;
466
    }
467
468
    /**
469
     * @param array $serializedObject
470
     * @return array
471
     */
472
    private static function addDefaultMainLanguage(array $serializedObject)
473
    {
474
        if (!isset($serializedObject['payload']['main_language'])) {
475
            $mainLanguage = new Language('nl');
476
            $serializedObject['payload']['main_language'] = $mainLanguage->getCode();
477
        }
478
479
        return $serializedObject;
480
    }
481
}
482