Completed
Push — master ( 3bc119...0177d6 )
by Jonas
23s queued 11s
created

PlaceLDProjector::getLabelRemovedClassName()   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
    protected function applyMarkedAsDuplicate(MarkedAsDuplicate $markedAsDuplicate): JsonDocument
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
    protected function applyMarkedAsCanonical(MarkedAsCanonical $markedAsCanonical): JsonDocument
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
            foreach ($markedAsCanonical->getDuplicatesOfDuplicate() as $duplicateOfDuplicate) {
398
                $placeLd->duplicatedBy[] = $this->iriGenerator->iri($duplicateOfDuplicate);
399
            }
400
            return $placeLd;
401
        });
402
    }
403
404
    /**
405
     * @param string $itemId
406
     * @return JsonDocument
407
     */
408
    protected function loadPlaceDocumentFromRepositoryById($itemId)
409
    {
410
        $document = $this->repository->get($itemId);
411
412
        if (!$document) {
413
            return $this->newDocument($itemId);
414
        }
415
416
        return $document;
417
    }
418
419
    /**
420
     * @return string
421
     */
422
    protected function getLabelAddedClassName()
423
    {
424
        return LabelAdded::class;
425
    }
426
427
    /**
428
     * @return string
429
     */
430
    protected function getLabelRemovedClassName()
431
    {
432
        return LabelRemoved::class;
433
    }
434
435
    /**
436
     * @return string
437
     */
438
    protected function getImageAddedClassName()
439
    {
440
        return ImageAdded::class;
441
    }
442
443
    /**
444
     * @return string
445
     */
446
    protected function getImageRemovedClassName()
447
    {
448
        return ImageRemoved::class;
449
    }
450
451
    /**
452
     * @return string
453
     */
454
    protected function getImageUpdatedClassName()
455
    {
456
        return ImageUpdated::class;
457
    }
458
459
    protected function getMainImageSelectedClassName()
460
    {
461
        return MainImageSelected::class;
462
    }
463
464
    /**
465
     * @return string
466
     */
467
    protected function getTitleTranslatedClassName()
468
    {
469
        return TitleTranslated::class;
470
    }
471
472
    /**
473
     * @return string
474
     */
475
    protected function getDescriptionTranslatedClassName()
476
    {
477
        return DescriptionTranslated::class;
478
    }
479
480
    /**
481
     * @return string
482
     */
483
    protected function getOrganizerUpdatedClassName()
484
    {
485
        return OrganizerUpdated::class;
486
    }
487
488
    /**
489
     * @return string
490
     */
491
    protected function getOrganizerDeletedClassName()
492
    {
493
        return OrganizerDeleted::class;
494
    }
495
496
    protected function getBookingInfoUpdatedClassName()
497
    {
498
        return BookingInfoUpdated::class;
499
    }
500
501
    /**
502
     * @return string
503
     */
504
    protected function getPriceInfoUpdatedClassName()
505
    {
506
        return PriceInfoUpdated::class;
507
    }
508
509
    protected function getContactPointUpdatedClassName()
510
    {
511
        return ContactPointUpdated::class;
512
    }
513
514
    protected function getDescriptionUpdatedClassName()
515
    {
516
        return DescriptionUpdated::class;
517
    }
518
519
    protected function getCalendarUpdatedClassName()
520
    {
521
        return CalendarUpdated::class;
522
    }
523
524
    protected function getTypicalAgeRangeUpdatedClassName()
525
    {
526
        return TypicalAgeRangeUpdated::class;
527
    }
528
529
    protected function getTypicalAgeRangeDeletedClassName()
530
    {
531
        return TypicalAgeRangeDeleted::class;
532
    }
533
534
    protected function getPublishedClassName()
535
    {
536
        return Published::class;
537
    }
538
539
    protected function getApprovedClassName()
540
    {
541
        return Approved::class;
542
    }
543
544
    protected function getRejectedClassName()
545
    {
546
        return Rejected::class;
547
    }
548
549
    protected function getFlaggedAsDuplicateClassName()
550
    {
551
        return FlaggedAsDuplicate::class;
552
    }
553
554
    protected function getFlaggedAsInappropriateClassName()
555
    {
556
        return FlaggedAsInappropriate::class;
557
    }
558
559
    protected function getImagesImportedFromUdb2ClassName()
560
    {
561
        return ImagesImportedFromUDB2::class;
562
    }
563
564
    protected function getImagesUpdatedFromUdb2ClassName()
565
    {
566
        return ImagesUpdatedFromUDB2::class;
567
    }
568
569
    protected function getTitleUpdatedClassName()
570
    {
571
        return TitleUpdated::class;
572
    }
573
574
    protected function getTypeUpdatedClassName()
575
    {
576
        return TypeUpdated::class;
577
    }
578
579
    protected function getThemeUpdatedClassName()
580
    {
581
        return ThemeUpdated::class;
582
    }
583
584
    protected function getFacilitiesUpdatedClassName()
585
    {
586
        return FacilitiesUpdated::class;
587
    }
588
}
589