Completed
Pull Request — master (#336)
by Luc
04:39
created

PlaceLDProjector::getFacilitiesUpdatedClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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