Completed
Pull Request — master (#419)
by
unknown
03:44
created

PlaceLDProjector::getBookingInfoUpdatedClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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\MarkedAsCanonical;
40
use CultuurNet\UDB3\Place\Events\MarkedAsDuplicate;
41
use CultuurNet\UDB3\Place\Events\Moderation\Approved;
42
use CultuurNet\UDB3\Place\Events\Moderation\FlaggedAsDuplicate;
43
use CultuurNet\UDB3\Place\Events\Moderation\FlaggedAsInappropriate;
44
use CultuurNet\UDB3\Place\Events\Moderation\Published;
45
use CultuurNet\UDB3\Place\Events\Moderation\Rejected;
46
use CultuurNet\UDB3\Place\Events\OrganizerDeleted;
47
use CultuurNet\UDB3\Place\Events\OrganizerUpdated;
48
use CultuurNet\UDB3\Place\Events\PlaceCreated;
49
use CultuurNet\UDB3\Place\Events\PlaceDeleted;
50
use CultuurNet\UDB3\Place\Events\PlaceImportedFromUDB2;
51
use CultuurNet\UDB3\Place\Events\PlaceUpdatedFromUDB2;
52
use CultuurNet\UDB3\Place\Events\PriceInfoUpdated;
53
use CultuurNet\UDB3\Place\Events\ThemeUpdated;
54
use CultuurNet\UDB3\Place\Events\TitleTranslated;
55
use CultuurNet\UDB3\Place\Events\TitleUpdated;
56
use CultuurNet\UDB3\Place\Events\TypeUpdated;
57
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeDeleted;
58
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeUpdated;
59
use CultuurNet\UDB3\ReadModel\JsonDocument;
60
use CultuurNet\UDB3\ReadModel\JsonDocumentMetaDataEnricherInterface;
61
use CultuurNet\UDB3\Theme;
62
use Symfony\Component\Serializer\SerializerInterface;
63
64
/**
65
 * Projects state changes on Place entities to a JSON-LD read model in a
66
 * document repository.
67
 */
68
class PlaceLDProjector extends OfferLDProjector implements EventListenerInterface
69
{
70
    /**
71
     * @var CdbXMLImporter
72
     */
73
    protected $cdbXMLImporter;
74
75
    /**
76
     * @param DocumentRepositoryInterface $repository
77
     * @param IriGeneratorInterface $iriGenerator
78
     * @param EntityServiceInterface $organizerService
79
     * @param SerializerInterface $mediaObjectSerializer
80
     * @param CdbXMLImporter $cdbXMLImporter
81
     * @param JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
82
     * @param string[] $basePriceTranslations
83
     */
84
    public function __construct(
85
        DocumentRepositoryInterface $repository,
86
        IriGeneratorInterface $iriGenerator,
87
        EntityServiceInterface $organizerService,
88
        SerializerInterface $mediaObjectSerializer,
89
        CdbXMLImporter $cdbXMLImporter,
90
        JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher,
91
        array $basePriceTranslations
92
    ) {
93
        parent::__construct(
94
            $repository,
95
            $iriGenerator,
96
            $organizerService,
97
            $mediaObjectSerializer,
98
            $jsonDocumentMetaDataEnricher,
99
            $basePriceTranslations
100
        );
101
102
        $this->cdbXMLImporter = $cdbXMLImporter;
103
    }
104
105
    /**
106
     * @param PlaceImportedFromUDB2 $placeImportedFromUDB2
107
     * @return JsonDocument
108
     */
109
    protected function applyPlaceImportedFromUDB2(
110
        PlaceImportedFromUDB2 $placeImportedFromUDB2
111
    ) {
112
        return $this->projectActorImportedFromUDB2(
113
            $placeImportedFromUDB2
114
        );
115
    }
116
117
    /**
118
     * @param PlaceUpdatedFromUDB2 $placeUpdatedFromUDB2
119
     * @return JsonDocument
120
     */
121
    protected function applyPlaceUpdatedFromUDB2(
122
        PlaceUpdatedFromUDB2 $placeUpdatedFromUDB2
123
    ) {
124
        return $this->projectActorImportedFromUDB2(
125
            $placeUpdatedFromUDB2
126
        );
127
    }
128
129
    /**
130
     * @param ActorImportedFromUDB2 $actorImportedFromUDB2
131
     * @return JsonDocument
132
     * @throws \CultureFeed_Cdb_ParseException
133
     */
134
    protected function projectActorImportedFromUDB2(
135
        ActorImportedFromUDB2 $actorImportedFromUDB2
136
    ) {
137
        $actorId = $actorImportedFromUDB2->getActorId();
138
139
        $udb2Actor = ActorItemFactory::createActorFromCdbXml(
140
            $actorImportedFromUDB2->getCdbXmlNamespaceUri(),
141
            $actorImportedFromUDB2->getCdbXml()
142
        );
143
144
        try {
145
            $document = $this->loadPlaceDocumentFromRepositoryById($actorId);
146
        } catch (DocumentGoneException $e) {
147
            $document = $this->newDocument($actorId);
148
        }
149
150
        $actorLd = $document->getBody();
151
152
        $actorLd = $this->cdbXMLImporter->documentWithCdbXML(
153
            $actorLd,
154
            $udb2Actor
155
        );
156
157
        // When importing from UDB2 the main language is always nl.
158
        // When updating from UDB2 never change the main language.
159
        if (!isset($actorLd->mainLanguage)) {
160
            $this->setMainLanguage($actorLd, new Language('nl'));
161
        }
162
163
        // Remove geocoordinates, because the address might have been
164
        // updated and we might get inconsistent data if it takes a while
165
        // before the new geocoordinates are added.
166
        // In case geocoding fails, it's also easier to look for places that
167
        // have no geocoordinates instead of places that have incorrect
168
        // geocoordinates.
169
        unset($actorLd->geo);
170
171
        return $document->withBody($actorLd);
172
    }
173
174
    /**
175
     * @param string $id
176
     * @return JsonDocument
177
     */
178 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...
179
    {
180
        $document = new JsonDocument($id);
181
182
        $placeLd = $document->getBody();
183
        $placeLd->{'@id'} = $this->iriGenerator->iri($id);
184
        $placeLd->{'@context'} = '/contexts/place';
185
186
        return $document->withBody($placeLd);
187
    }
188
189
    /**
190
     * @param PlaceCreated $placeCreated
191
     * @param DomainMessage $domainMessage
192
     * @return JsonDocument
193
     */
194
    protected function applyPlaceCreated(PlaceCreated $placeCreated, DomainMessage $domainMessage)
195
    {
196
        $document = $this->newDocument($placeCreated->getPlaceId());
197
198
        $jsonLD = $document->getBody();
199
200
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
201
            $placeCreated->getPlaceId()
202
        );
203
204
        $this->setMainLanguage($jsonLD, $placeCreated->getMainLanguage());
205
206
        $jsonLD->name[$placeCreated->getMainLanguage()->getCode()] = $placeCreated->getTitle();
207
208
        $this->setAddress(
209
            $jsonLD,
210
            $placeCreated->getAddress(),
211
            $this->getMainLanguage($jsonLD)
212
        );
213
214
        $calendarJsonLD = $placeCreated->getCalendar()->toJsonLd();
215
        $jsonLD = (object) array_merge((array) $jsonLD, $calendarJsonLD);
216
217
        $availableTo = AvailableTo::createFromCalendar($placeCreated->getCalendar());
218
        $jsonLD->availableTo = (string)$availableTo;
219
220
        $eventType = $placeCreated->getEventType();
221
        $jsonLD->terms = [
222
            $eventType->toJsonLd(),
223
        ];
224
225
        $theme = $placeCreated->getTheme();
226
        if (!empty($theme)) {
227
            $jsonLD->terms[] = $theme->toJsonLd();
228
        }
229
230
        $recordedOn = $domainMessage->getRecordedOn()->toString();
231
        $jsonLD->created = \DateTime::createFromFormat(
232
            DateTime::FORMAT_STRING,
233
            $recordedOn
234
        )->format('c');
235
236
        $jsonLD->modified = $jsonLD->created;
237
238
        $metaData = $domainMessage->getMetadata()->serialize();
239
        if (isset($metaData['user_id'])) {
240
            $jsonLD->creator = $metaData['user_id'];
241
        }
242
243
        $jsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
244
245
        return $document->withBody($jsonLD);
246
    }
247
248
    /**
249
     * @param PlaceDeleted $placeDeleted
250
     * @return null
251
     */
252
    protected function applyPlaceDeleted(PlaceDeleted $placeDeleted)
253
    {
254
        $document = $this->loadDocumentFromRepository($placeDeleted);
255
256
        $jsonLD = $document->getBody();
257
258
        $jsonLD->workflowStatus = WorkflowStatus::DELETED()->getName();
259
260
        return $document->withBody($jsonLD);
261
    }
262
263
    /**
264
     * Apply the major info updated command to the projector.
265
     * @param MajorInfoUpdated $majorInfoUpdated
266
     * @return JsonDocument
267
     */
268
    protected function applyMajorInfoUpdated(MajorInfoUpdated $majorInfoUpdated)
269
    {
270
        $document = $this
271
            ->loadPlaceDocumentFromRepositoryById($majorInfoUpdated->getPlaceId())
272
            ->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...
273
274
        $jsonLD = $document->getBody();
275
276
        $jsonLD->name->{$this->getMainLanguage($jsonLD)->getCode()} = $majorInfoUpdated->getTitle();
277
278
        $this->setAddress(
279
            $jsonLD,
280
            $majorInfoUpdated->getAddress(),
281
            $this->getMainLanguage($jsonLD)
282
        );
283
284
        $availableTo = AvailableTo::createFromCalendar($majorInfoUpdated->getCalendar());
285
        $jsonLD->availableTo = (string)$availableTo;
286
287
        // Remove old theme and event type.
288
        $jsonLD->terms = array_filter($jsonLD->terms, function ($term) {
289
            return $term->domain !== EventType::DOMAIN &&  $term->domain !== Theme::DOMAIN;
290
        });
291
292
        $eventType = $majorInfoUpdated->getEventType();
293
        $jsonLD->terms = [
294
            $eventType->toJsonLd(),
295
        ];
296
297
        $theme = $majorInfoUpdated->getTheme();
298
        if (!empty($theme)) {
299
            $jsonLD->terms[] = $theme->toJsonLd();
300
        }
301
302
        // Remove geocoordinates, because the address might have been
303
        // updated and we might get inconsistent data if it takes a while
304
        // before the new geocoordinates are added.
305
        // In case geocoding fails, it's also easier to look for places that
306
        // have no geocoordinates instead of places that have incorrect
307
        // geocoordinates.
308
        unset($jsonLD->geo);
309
310
        return $document->withBody($jsonLD);
311
    }
312
313
    /**
314
     * @param AddressUpdated $addressUpdated
315
     * @return JsonDocument
316
     */
317 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...
318
    {
319
        $document = $this->loadPlaceDocumentFromRepositoryById($addressUpdated->getPlaceId());
320
        $jsonLD = $document->getBody();
321
        $this->setAddress($jsonLD, $addressUpdated->getAddress(), $this->getMainLanguage($jsonLD));
322
        return $document->withBody($jsonLD);
323
    }
324
325
    /**
326
     * @param AddressTranslated $addressTranslated
327
     * @return JsonDocument
328
     */
329 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...
330
    {
331
        $document = $this->loadPlaceDocumentFromRepositoryById($addressTranslated->getPlaceId());
332
        $jsonLD = $document->getBody();
333
        $this->setAddress($jsonLD, $addressTranslated->getAddress(), $addressTranslated->getLanguage());
334
        return $document->withBody($jsonLD);
335
    }
336
337
    /**
338
     * @param \stdClass $jsonLd
339
     * @param Address $address
340
     * @param Language $language
341
     */
342
    protected function setAddress(\stdClass $jsonLd, Address $address, Language $language)
343
    {
344
        if (!isset($jsonLd->address)) {
345
            $jsonLd->address = new \stdClass();
346
        }
347
348
        if (isset($jsonLd->address->streetAddress)) {
349
            // Old projections have their address in a single language.
350
            // Set the old address as the address for the main language before
351
            // updating it or adding another address.
352
            // @replay_i18n
353
            // @see https://jira.uitdatabank.be/browse/III-2201
354
            $mainLanguageCode = $this->getMainLanguage($jsonLd)->getCode();
355
            $jsonLd->address = (object) [
356
                $mainLanguageCode => $jsonLd->address,
357
            ];
358
        }
359
360
        $jsonLd->address->{$language->getCode()} = $address->toJsonLd();
361
    }
362
363
    /**
364
     * @param GeoCoordinatesUpdated $geoCoordinatesUpdated
365
     * @return JsonDocument
366
     */
367
    protected function applyGeoCoordinatesUpdated(GeoCoordinatesUpdated $geoCoordinatesUpdated)
368
    {
369
        $document = $this->loadPlaceDocumentFromRepositoryById($geoCoordinatesUpdated->getItemId());
370
371
        $placeLd = $document->getBody();
372
373
        $placeLd->geo = (object) [
374
            'latitude' => $geoCoordinatesUpdated->getCoordinates()->getLatitude()->toDouble(),
375
            'longitude' => $geoCoordinatesUpdated->getCoordinates()->getLongitude()->toDouble(),
376
        ];
377
378
        return $document->withBody($placeLd);
379
    }
380
381 View Code Duplication
    protected function applyMarkedAsDuplicate(MarkedAsDuplicate $markedAsDuplicate): JsonDocument
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...
382
    {
383
        $document = $this->loadPlaceDocumentFromRepositoryById($markedAsDuplicate->getPlaceId());
384
385
        return $document->apply(function ($placeLd) use ($markedAsDuplicate) {
386
            $placeLd->duplicateOf = $this->iriGenerator->iri($markedAsDuplicate->getDuplicateOf());
387
            return $placeLd;
388
        });
389
    }
390
391 View Code Duplication
    protected function applyMarkedAsCanonical(MarkedAsCanonical $markedAsCanonical): JsonDocument
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...
392
    {
393
        $document = $this->loadPlaceDocumentFromRepositoryById($markedAsCanonical->getPlaceId());
394
395
        return $document->apply(function ($placeLd) use ($markedAsCanonical) {
396
            $placeLd->duplicatedBy[] = $this->iriGenerator->iri($markedAsCanonical->getDuplicatedBy());
397
            return $placeLd;
398
        });
399
    }
400
401
    /**
402
     * @param string $itemId
403
     * @return JsonDocument
404
     */
405
    protected function loadPlaceDocumentFromRepositoryById($itemId)
406
    {
407
        $document = $this->repository->get($itemId);
408
409
        if (!$document) {
410
            return $this->newDocument($itemId);
411
        }
412
413
        return $document;
414
    }
415
416
    /**
417
     * @return string
418
     */
419
    protected function getLabelAddedClassName()
420
    {
421
        return LabelAdded::class;
422
    }
423
424
    /**
425
     * @return string
426
     */
427
    protected function getLabelRemovedClassName()
428
    {
429
        return LabelRemoved::class;
430
    }
431
432
    /**
433
     * @return string
434
     */
435
    protected function getImageAddedClassName()
436
    {
437
        return ImageAdded::class;
438
    }
439
440
    /**
441
     * @return string
442
     */
443
    protected function getImageRemovedClassName()
444
    {
445
        return ImageRemoved::class;
446
    }
447
448
    /**
449
     * @return string
450
     */
451
    protected function getImageUpdatedClassName()
452
    {
453
        return ImageUpdated::class;
454
    }
455
456
    protected function getMainImageSelectedClassName()
457
    {
458
        return MainImageSelected::class;
459
    }
460
461
    /**
462
     * @return string
463
     */
464
    protected function getTitleTranslatedClassName()
465
    {
466
        return TitleTranslated::class;
467
    }
468
469
    /**
470
     * @return string
471
     */
472
    protected function getDescriptionTranslatedClassName()
473
    {
474
        return DescriptionTranslated::class;
475
    }
476
477
    /**
478
     * @return string
479
     */
480
    protected function getOrganizerUpdatedClassName()
481
    {
482
        return OrganizerUpdated::class;
483
    }
484
485
    /**
486
     * @return string
487
     */
488
    protected function getOrganizerDeletedClassName()
489
    {
490
        return OrganizerDeleted::class;
491
    }
492
493
    protected function getBookingInfoUpdatedClassName()
494
    {
495
        return BookingInfoUpdated::class;
496
    }
497
498
    /**
499
     * @return string
500
     */
501
    protected function getPriceInfoUpdatedClassName()
502
    {
503
        return PriceInfoUpdated::class;
504
    }
505
506
    protected function getContactPointUpdatedClassName()
507
    {
508
        return ContactPointUpdated::class;
509
    }
510
511
    protected function getDescriptionUpdatedClassName()
512
    {
513
        return DescriptionUpdated::class;
514
    }
515
516
    protected function getCalendarUpdatedClassName()
517
    {
518
        return CalendarUpdated::class;
519
    }
520
521
    protected function getTypicalAgeRangeUpdatedClassName()
522
    {
523
        return TypicalAgeRangeUpdated::class;
524
    }
525
526
    protected function getTypicalAgeRangeDeletedClassName()
527
    {
528
        return TypicalAgeRangeDeleted::class;
529
    }
530
531
    protected function getPublishedClassName()
532
    {
533
        return Published::class;
534
    }
535
536
    protected function getApprovedClassName()
537
    {
538
        return Approved::class;
539
    }
540
541
    protected function getRejectedClassName()
542
    {
543
        return Rejected::class;
544
    }
545
546
    protected function getFlaggedAsDuplicateClassName()
547
    {
548
        return FlaggedAsDuplicate::class;
549
    }
550
551
    protected function getFlaggedAsInappropriateClassName()
552
    {
553
        return FlaggedAsInappropriate::class;
554
    }
555
556
    protected function getImagesImportedFromUdb2ClassName()
557
    {
558
        return ImagesImportedFromUDB2::class;
559
    }
560
561
    protected function getImagesUpdatedFromUdb2ClassName()
562
    {
563
        return ImagesUpdatedFromUDB2::class;
564
    }
565
566
    protected function getTitleUpdatedClassName()
567
    {
568
        return TitleUpdated::class;
569
    }
570
571
    protected function getTypeUpdatedClassName()
572
    {
573
        return TypeUpdated::class;
574
    }
575
576
    protected function getThemeUpdatedClassName()
577
    {
578
        return ThemeUpdated::class;
579
    }
580
581
    protected function getFacilitiesUpdatedClassName()
582
    {
583
        return FacilitiesUpdated::class;
584
    }
585
}
586