Completed
Push — master ( 694b48...b76062 )
by Luc
434:27 queued 424:47
created

PlaceLDProjector::applyPlaceCreated()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 9.0254
c 0
b 0
f 0
cc 3
nc 4
nop 2

How to fix   Long Method   

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\Place\ReadModel\JSONLD;
4
5
use Broadway\Domain\DateTime;
6
use Broadway\Domain\DomainMessage;
7
use Broadway\EventHandling\EventListenerInterface;
8
use CultuurNet\UDB3\Actor\ActorImportedFromUDB2;
9
use CultuurNet\UDB3\Address\Address;
10
use CultuurNet\UDB3\Cdb\ActorItemFactory;
11
use CultuurNet\UDB3\EntityServiceInterface;
12
use CultuurNet\UDB3\Event\EventType;
13
use CultuurNet\UDB3\Event\ReadModel\DocumentGoneException;
14
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
15
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
16
use CultuurNet\UDB3\Language;
17
use CultuurNet\UDB3\Offer\AvailableTo;
18
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferLDProjector;
19
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferUpdate;
20
use CultuurNet\UDB3\Offer\WorkflowStatus;
21
use CultuurNet\UDB3\Place\Events\AddressTranslated;
22
use CultuurNet\UDB3\Place\Events\AddressUpdated;
23
use CultuurNet\UDB3\Place\Events\BookingInfoUpdated;
24
use CultuurNet\UDB3\Place\Events\CalendarUpdated;
25
use CultuurNet\UDB3\Place\Events\ContactPointUpdated;
26
use CultuurNet\UDB3\Place\Events\DescriptionTranslated;
27
use CultuurNet\UDB3\Place\Events\DescriptionUpdated;
28
use CultuurNet\UDB3\Place\Events\FacilitiesUpdated;
29
use CultuurNet\UDB3\Place\Events\GeoCoordinatesUpdated;
30
use CultuurNet\UDB3\Place\Events\Image\ImagesImportedFromUDB2;
31
use CultuurNet\UDB3\Place\Events\Image\ImagesUpdatedFromUDB2;
32
use CultuurNet\UDB3\Place\Events\ImageAdded;
33
use CultuurNet\UDB3\Place\Events\ImageRemoved;
34
use CultuurNet\UDB3\Place\Events\ImageUpdated;
35
use CultuurNet\UDB3\Place\Events\LabelAdded;
36
use CultuurNet\UDB3\Place\Events\LabelRemoved;
37
use CultuurNet\UDB3\Place\Events\MainImageSelected;
38
use CultuurNet\UDB3\Place\Events\MajorInfoUpdated;
39
use CultuurNet\UDB3\Place\Events\Moderation\Approved;
40
use CultuurNet\UDB3\Place\Events\Moderation\FlaggedAsDuplicate;
41
use CultuurNet\UDB3\Place\Events\Moderation\FlaggedAsInappropriate;
42
use CultuurNet\UDB3\Place\Events\Moderation\Published;
43
use CultuurNet\UDB3\Place\Events\Moderation\Rejected;
44
use CultuurNet\UDB3\Place\Events\OrganizerDeleted;
45
use CultuurNet\UDB3\Place\Events\OrganizerUpdated;
46
use CultuurNet\UDB3\Place\Events\PlaceCreated;
47
use CultuurNet\UDB3\Place\Events\PlaceDeleted;
48
use CultuurNet\UDB3\Place\Events\PlaceImportedFromUDB2;
49
use CultuurNet\UDB3\Place\Events\PlaceUpdatedFromUDB2;
50
use CultuurNet\UDB3\Place\Events\PriceInfoUpdated;
51
use CultuurNet\UDB3\Place\Events\ThemeUpdated;
52
use CultuurNet\UDB3\Place\Events\TitleTranslated;
53
use CultuurNet\UDB3\Place\Events\TitleUpdated;
54
use CultuurNet\UDB3\Place\Events\TypeUpdated;
55
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeDeleted;
56
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeUpdated;
57
use CultuurNet\UDB3\ReadModel\JsonDocument;
58
use CultuurNet\UDB3\ReadModel\JsonDocumentMetaDataEnricherInterface;
59
use CultuurNet\UDB3\Theme;
60
use Symfony\Component\Serializer\SerializerInterface;
61
62
/**
63
 * Projects state changes on Place entities to a JSON-LD read model in a
64
 * document repository.
65
 */
66
class PlaceLDProjector extends OfferLDProjector implements EventListenerInterface
67
{
68
    /**
69
     * @var CdbXMLImporter
70
     */
71
    protected $cdbXMLImporter;
72
73
    /**
74
     * @param DocumentRepositoryInterface $repository
75
     * @param IriGeneratorInterface $iriGenerator
76
     * @param EntityServiceInterface $organizerService
77
     * @param SerializerInterface $mediaObjectSerializer
78
     * @param CdbXMLImporter $cdbXMLImporter
79
     * @param JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
80
     * @param string[] $basePriceTranslations
81
     */
82
    public function __construct(
83
        DocumentRepositoryInterface $repository,
84
        IriGeneratorInterface $iriGenerator,
85
        EntityServiceInterface $organizerService,
86
        SerializerInterface $mediaObjectSerializer,
87
        CdbXMLImporter $cdbXMLImporter,
88
        JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher,
89
        array $basePriceTranslations
90
    ) {
91
        parent::__construct(
92
            $repository,
93
            $iriGenerator,
94
            $organizerService,
95
            $mediaObjectSerializer,
96
            $jsonDocumentMetaDataEnricher,
97
            $basePriceTranslations
98
        );
99
100
        $this->cdbXMLImporter = $cdbXMLImporter;
101
    }
102
103
    /**
104
     * @param PlaceImportedFromUDB2 $placeImportedFromUDB2
105
     * @return JsonDocument
106
     */
107
    protected function applyPlaceImportedFromUDB2(
108
        PlaceImportedFromUDB2 $placeImportedFromUDB2
109
    ) {
110
        return $this->projectActorImportedFromUDB2(
111
            $placeImportedFromUDB2
112
        );
113
    }
114
115
    /**
116
     * @param PlaceUpdatedFromUDB2 $placeUpdatedFromUDB2
117
     * @return JsonDocument
118
     */
119
    protected function applyPlaceUpdatedFromUDB2(
120
        PlaceUpdatedFromUDB2 $placeUpdatedFromUDB2
121
    ) {
122
        return $this->projectActorImportedFromUDB2(
123
            $placeUpdatedFromUDB2
124
        );
125
    }
126
127
    /**
128
     * @param ActorImportedFromUDB2 $actorImportedFromUDB2
129
     * @return JsonDocument
130
     * @throws \CultureFeed_Cdb_ParseException
131
     */
132
    protected function projectActorImportedFromUDB2(
133
        ActorImportedFromUDB2 $actorImportedFromUDB2
134
    ) {
135
        $actorId = $actorImportedFromUDB2->getActorId();
136
137
        $udb2Actor = ActorItemFactory::createActorFromCdbXml(
138
            $actorImportedFromUDB2->getCdbXmlNamespaceUri(),
139
            $actorImportedFromUDB2->getCdbXml()
140
        );
141
142
        try {
143
            $document = $this->loadPlaceDocumentFromRepositoryById($actorId);
144
        } catch (DocumentGoneException $e) {
145
            $document = $this->newDocument($actorId);
146
        }
147
148
        $actorLd = $document->getBody();
149
150
        $actorLd = $this->cdbXMLImporter->documentWithCdbXML(
151
            $actorLd,
152
            $udb2Actor
153
        );
154
155
        // When importing from UDB2 the main language is always nl.
156
        // When updating from UDB2 never change the main language.
157
        if (!isset($actorLd->mainLanguage)) {
158
            $this->setMainLanguage($actorLd, new Language('nl'));
159
        }
160
161
        // Remove geocoordinates, because the address might have been
162
        // updated and we might get inconsistent data if it takes a while
163
        // before the new geocoordinates are added.
164
        // In case geocoding fails, it's also easier to look for places that
165
        // have no geocoordinates instead of places that have incorrect
166
        // geocoordinates.
167
        unset($actorLd->geo);
168
169
        return $document->withBody($actorLd);
170
    }
171
172
    /**
173
     * @param string $id
174
     * @return JsonDocument
175
     */
176 View Code Duplication
    protected function newDocument($id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
177
    {
178
        $document = new JsonDocument($id);
179
180
        $placeLd = $document->getBody();
181
        $placeLd->{'@id'} = $this->iriGenerator->iri($id);
182
        $placeLd->{'@context'} = '/contexts/place';
183
184
        return $document->withBody($placeLd);
185
    }
186
187
    /**
188
     * @param PlaceCreated $placeCreated
189
     * @param DomainMessage $domainMessage
190
     * @return JsonDocument
191
     */
192
    protected function applyPlaceCreated(PlaceCreated $placeCreated, DomainMessage $domainMessage)
193
    {
194
        $document = $this->newDocument($placeCreated->getPlaceId());
195
196
        $jsonLD = $document->getBody();
197
198
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
199
            $placeCreated->getPlaceId()
200
        );
201
202
        $this->setMainLanguage($jsonLD, $placeCreated->getMainLanguage());
203
204
        $jsonLD->name[$placeCreated->getMainLanguage()->getCode()] = $placeCreated->getTitle();
205
206
        $this->setAddress(
207
            $jsonLD,
208
            $placeCreated->getAddress(),
209
            $this->getMainLanguage($jsonLD)
210
        );
211
212
        $calendarJsonLD = $placeCreated->getCalendar()->toJsonLd();
213
        $jsonLD = (object) array_merge((array) $jsonLD, $calendarJsonLD);
214
215
        $availableTo = AvailableTo::createFromCalendar($placeCreated->getCalendar());
216
        $jsonLD->availableTo = (string)$availableTo;
217
218
        $eventType = $placeCreated->getEventType();
219
        $jsonLD->terms = [
220
            $eventType->toJsonLd(),
221
        ];
222
223
        $theme = $placeCreated->getTheme();
224
        if (!empty($theme)) {
225
            $jsonLD->terms[] = $theme->toJsonLd();
226
        }
227
228
        $recordedOn = $domainMessage->getRecordedOn()->toString();
229
        $jsonLD->created = \DateTime::createFromFormat(
230
            DateTime::FORMAT_STRING,
231
            $recordedOn
232
        )->format('c');
233
234
        $jsonLD->modified = $jsonLD->created;
235
236
        $metaData = $domainMessage->getMetadata()->serialize();
237
        if (isset($metaData['user_id'])) {
238
            $jsonLD->creator = $metaData['user_id'];
239
        }
240
241
        $jsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
242
243
        return $document->withBody($jsonLD);
244
    }
245
246
    /**
247
     * @param PlaceDeleted $placeDeleted
248
     * @return null
249
     */
250
    protected function applyPlaceDeleted(PlaceDeleted $placeDeleted)
251
    {
252
        $document = $this->loadDocumentFromRepository($placeDeleted);
253
254
        $jsonLD = $document->getBody();
255
256
        $jsonLD->workflowStatus = WorkflowStatus::DELETED()->getName();
257
258
        return $document->withBody($jsonLD);
259
    }
260
261
    /**
262
     * Apply the major info updated command to the projector.
263
     * @param MajorInfoUpdated $majorInfoUpdated
264
     * @return JsonDocument
265
     */
266
    protected function applyMajorInfoUpdated(MajorInfoUpdated $majorInfoUpdated)
267
    {
268
        $document = $this
269
            ->loadPlaceDocumentFromRepositoryById($majorInfoUpdated->getPlaceId())
270
            ->apply(OfferUpdate::calendar($majorInfoUpdated->getCalendar()));
0 ignored issues
show
Compatibility introduced by
$majorInfoUpdated->getCalendar() of type object<CultuurNet\UDB3\CalendarInterface> is not a sub-type of object<CultuurNet\UDB3\Calendar>. It seems like you assume a concrete implementation of the interface CultuurNet\UDB3\CalendarInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
271
272
        $jsonLD = $document->getBody();
273
274
        $jsonLD->name->{$this->getMainLanguage($jsonLD)->getCode()} = $majorInfoUpdated->getTitle();
275
276
        $this->setAddress(
277
            $jsonLD,
278
            $majorInfoUpdated->getAddress(),
279
            $this->getMainLanguage($jsonLD)
280
        );
281
282
        $availableTo = AvailableTo::createFromCalendar($majorInfoUpdated->getCalendar());
283
        $jsonLD->availableTo = (string)$availableTo;
284
285
        // Remove old theme and event type.
286
        $jsonLD->terms = array_filter($jsonLD->terms, function ($term) {
287
            return $term->domain !== EventType::DOMAIN &&  $term->domain !== Theme::DOMAIN;
288
        });
289
290
        $eventType = $majorInfoUpdated->getEventType();
291
        $jsonLD->terms = [
292
            $eventType->toJsonLd(),
293
        ];
294
295
        $theme = $majorInfoUpdated->getTheme();
296
        if (!empty($theme)) {
297
            $jsonLD->terms[] = $theme->toJsonLd();
298
        }
299
300
        // Remove geocoordinates, because the address might have been
301
        // updated and we might get inconsistent data if it takes a while
302
        // before the new geocoordinates are added.
303
        // In case geocoding fails, it's also easier to look for places that
304
        // have no geocoordinates instead of places that have incorrect
305
        // geocoordinates.
306
        unset($jsonLD->geo);
307
308
        return $document->withBody($jsonLD);
309
    }
310
311
    /**
312
     * @param AddressUpdated $addressUpdated
313
     * @return JsonDocument
314
     */
315 View Code Duplication
    protected function applyAddressUpdated(AddressUpdated $addressUpdated)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
316
    {
317
        $document = $this->loadPlaceDocumentFromRepositoryById($addressUpdated->getPlaceId());
318
        $jsonLD = $document->getBody();
319
        $this->setAddress($jsonLD, $addressUpdated->getAddress(), $this->getMainLanguage($jsonLD));
320
        return $document->withBody($jsonLD);
321
    }
322
323
    /**
324
     * @param AddressTranslated $addressTranslated
325
     * @return JsonDocument
326
     */
327 View Code Duplication
    protected function applyAddressTranslated(AddressTranslated $addressTranslated)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
328
    {
329
        $document = $this->loadPlaceDocumentFromRepositoryById($addressTranslated->getPlaceId());
330
        $jsonLD = $document->getBody();
331
        $this->setAddress($jsonLD, $addressTranslated->getAddress(), $addressTranslated->getLanguage());
332
        return $document->withBody($jsonLD);
333
    }
334
335
    /**
336
     * @param \stdClass $jsonLd
337
     * @param Address $address
338
     * @param Language $language
339
     */
340
    protected function setAddress(\stdClass $jsonLd, Address $address, Language $language)
341
    {
342
        if (!isset($jsonLd->address)) {
343
            $jsonLd->address = new \stdClass();
344
        }
345
346
        if (isset($jsonLd->address->streetAddress)) {
347
            // Old projections have their address in a single language.
348
            // Set the old address as the address for the main language before
349
            // updating it or adding another address.
350
            // @replay_i18n
351
            // @see https://jira.uitdatabank.be/browse/III-2201
352
            $mainLanguageCode = $this->getMainLanguage($jsonLd)->getCode();
353
            $jsonLd->address = (object) [
354
                $mainLanguageCode => $jsonLd->address,
355
            ];
356
        }
357
358
        $jsonLd->address->{$language->getCode()} = $address->toJsonLd();
359
    }
360
361
    /**
362
     * @param GeoCoordinatesUpdated $geoCoordinatesUpdated
363
     * @return JsonDocument
364
     */
365
    protected function applyGeoCoordinatesUpdated(GeoCoordinatesUpdated $geoCoordinatesUpdated)
366
    {
367
        $document = $this->loadPlaceDocumentFromRepositoryById($geoCoordinatesUpdated->getItemId());
368
369
        $placeLd = $document->getBody();
370
371
        $placeLd->geo = (object) [
372
            'latitude' => $geoCoordinatesUpdated->getCoordinates()->getLatitude()->toDouble(),
373
            'longitude' => $geoCoordinatesUpdated->getCoordinates()->getLongitude()->toDouble(),
374
        ];
375
376
        return $document->withBody($placeLd);
377
    }
378
379
    /**
380
     * @param string $itemId
381
     * @return JsonDocument
382
     */
383
    protected function loadPlaceDocumentFromRepositoryById($itemId)
384
    {
385
        $document = $this->repository->get($itemId);
386
387
        if (!$document) {
388
            return $this->newDocument($itemId);
389
        }
390
391
        return $document;
392
    }
393
394
    /**
395
     * @return string
396
     */
397
    protected function getLabelAddedClassName()
398
    {
399
        return LabelAdded::class;
400
    }
401
402
    /**
403
     * @return string
404
     */
405
    protected function getLabelRemovedClassName()
406
    {
407
        return LabelRemoved::class;
408
    }
409
410
    /**
411
     * @return string
412
     */
413
    protected function getImageAddedClassName()
414
    {
415
        return ImageAdded::class;
416
    }
417
418
    /**
419
     * @return string
420
     */
421
    protected function getImageRemovedClassName()
422
    {
423
        return ImageRemoved::class;
424
    }
425
426
    /**
427
     * @return string
428
     */
429
    protected function getImageUpdatedClassName()
430
    {
431
        return ImageUpdated::class;
432
    }
433
434
    protected function getMainImageSelectedClassName()
435
    {
436
        return MainImageSelected::class;
437
    }
438
439
    /**
440
     * @return string
441
     */
442
    protected function getTitleTranslatedClassName()
443
    {
444
        return TitleTranslated::class;
445
    }
446
447
    /**
448
     * @return string
449
     */
450
    protected function getDescriptionTranslatedClassName()
451
    {
452
        return DescriptionTranslated::class;
453
    }
454
455
    /**
456
     * @return string
457
     */
458
    protected function getOrganizerUpdatedClassName()
459
    {
460
        return OrganizerUpdated::class;
461
    }
462
463
    /**
464
     * @return string
465
     */
466
    protected function getOrganizerDeletedClassName()
467
    {
468
        return OrganizerDeleted::class;
469
    }
470
471
    protected function getBookingInfoUpdatedClassName()
472
    {
473
        return BookingInfoUpdated::class;
474
    }
475
476
    /**
477
     * @return string
478
     */
479
    protected function getPriceInfoUpdatedClassName()
480
    {
481
        return PriceInfoUpdated::class;
482
    }
483
484
    protected function getContactPointUpdatedClassName()
485
    {
486
        return ContactPointUpdated::class;
487
    }
488
489
    protected function getDescriptionUpdatedClassName()
490
    {
491
        return DescriptionUpdated::class;
492
    }
493
494
    protected function getCalendarUpdatedClassName()
495
    {
496
        return CalendarUpdated::class;
497
    }
498
499
    protected function getTypicalAgeRangeUpdatedClassName()
500
    {
501
        return TypicalAgeRangeUpdated::class;
502
    }
503
504
    protected function getTypicalAgeRangeDeletedClassName()
505
    {
506
        return TypicalAgeRangeDeleted::class;
507
    }
508
509
    protected function getPublishedClassName()
510
    {
511
        return Published::class;
512
    }
513
514
    protected function getApprovedClassName()
515
    {
516
        return Approved::class;
517
    }
518
519
    protected function getRejectedClassName()
520
    {
521
        return Rejected::class;
522
    }
523
524
    protected function getFlaggedAsDuplicateClassName()
525
    {
526
        return FlaggedAsDuplicate::class;
527
    }
528
529
    protected function getFlaggedAsInappropriateClassName()
530
    {
531
        return FlaggedAsInappropriate::class;
532
    }
533
534
    protected function getImagesImportedFromUdb2ClassName()
535
    {
536
        return ImagesImportedFromUDB2::class;
537
    }
538
539
    protected function getImagesUpdatedFromUdb2ClassName()
540
    {
541
        return ImagesUpdatedFromUDB2::class;
542
    }
543
544
    protected function getTitleUpdatedClassName()
545
    {
546
        return TitleUpdated::class;
547
    }
548
549
    protected function getTypeUpdatedClassName()
550
    {
551
        return TypeUpdated::class;
552
    }
553
554
    protected function getThemeUpdatedClassName()
555
    {
556
        return ThemeUpdated::class;
557
    }
558
559
    protected function getFacilitiesUpdatedClassName()
560
    {
561
        return FacilitiesUpdated::class;
562
    }
563
}
564