Completed
Pull Request — master (#340)
by Luc
05:06
created

EventLDProjector::applyGeoCoordinatesUpdated()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 13
Ratio 100 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 13
loc 13
rs 9.4285
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3\Event\ReadModel\JSONLD;
4
5
use Broadway\Domain\DomainMessage;
6
use Broadway\Domain\Metadata;
7
use Broadway\EventHandling\EventListenerInterface;
8
use CultuurNet\UDB3\Cdb\EventItemFactory;
9
use CultuurNet\UDB3\EntityNotFoundException;
10
use CultuurNet\UDB3\Event\Events\AudienceUpdated;
11
use CultuurNet\UDB3\Event\Events\BookingInfoUpdated;
12
use CultuurNet\UDB3\Event\Events\CalendarUpdated;
13
use CultuurNet\UDB3\Event\Events\ContactPointUpdated;
14
use CultuurNet\UDB3\Event\Events\DescriptionTranslated;
15
use CultuurNet\UDB3\Event\Events\DescriptionUpdated;
16
use CultuurNet\UDB3\Event\Events\EventCopied;
17
use CultuurNet\UDB3\Event\Events\EventCreated;
18
use CultuurNet\UDB3\Event\Events\EventDeleted;
19
use CultuurNet\UDB3\Event\Events\EventImportedFromUDB2;
20
use CultuurNet\UDB3\Event\Events\EventUpdatedFromUDB2;
21
use CultuurNet\UDB3\Event\Events\FacilitiesUpdated;
22
use CultuurNet\UDB3\Event\Events\GeoCoordinatesUpdated;
23
use CultuurNet\UDB3\Event\Events\ImageAdded;
24
use CultuurNet\UDB3\Event\Events\ImageRemoved;
25
use CultuurNet\UDB3\Event\Events\Image\ImagesImportedFromUDB2;
26
use CultuurNet\UDB3\Event\Events\Image\ImagesUpdatedFromUDB2;
27
use CultuurNet\UDB3\Event\Events\ImageUpdated;
28
use CultuurNet\UDB3\Event\Events\LabelAdded;
29
use CultuurNet\UDB3\Event\Events\LabelRemoved;
30
use CultuurNet\UDB3\Event\Events\LocationUpdated;
31
use CultuurNet\UDB3\Event\Events\MainImageSelected;
32
use CultuurNet\UDB3\Event\Events\MajorInfoUpdated;
33
use CultuurNet\UDB3\Event\Events\Moderation\Approved;
34
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsDuplicate;
35
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsInappropriate;
36
use CultuurNet\UDB3\Event\Events\Moderation\Published;
37
use CultuurNet\UDB3\Event\Events\Moderation\Rejected;
38
use CultuurNet\UDB3\Event\Events\OrganizerDeleted;
39
use CultuurNet\UDB3\Event\Events\OrganizerUpdated;
40
use CultuurNet\UDB3\Event\Events\PriceInfoUpdated;
41
use CultuurNet\UDB3\Event\Events\ThemeUpdated;
42
use CultuurNet\UDB3\Event\Events\TitleTranslated;
43
use CultuurNet\UDB3\Event\Events\TitleUpdated;
44
use CultuurNet\UDB3\Event\Events\TypeUpdated;
45
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted;
46
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated;
47
use CultuurNet\UDB3\Event\EventType;
48
use CultuurNet\UDB3\Event\ReadModel\DocumentGoneException;
49
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
50
use CultuurNet\UDB3\Event\EventServiceInterface;
51
use CultuurNet\UDB3\Event\ValueObjects\Audience;
52
use CultuurNet\UDB3\Event\ValueObjects\AudienceType;
53
use CultuurNet\UDB3\EventListener\EventSpecification;
54
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
55
use CultuurNet\UDB3\Language;
56
use CultuurNet\UDB3\Offer\AvailableTo;
57
use CultuurNet\UDB3\Offer\IriOfferIdentifierFactoryInterface;
58
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferLDProjector;
59
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferUpdate;
60
use CultuurNet\UDB3\Offer\WorkflowStatus;
61
use CultuurNet\UDB3\Organizer\OrganizerProjectedToJSONLD;
62
use CultuurNet\UDB3\OrganizerService;
63
use CultuurNet\UDB3\Place\Events\PlaceProjectedToJSONLD;
64
use CultuurNet\UDB3\PlaceService;
65
use CultuurNet\UDB3\ReadModel\JsonDocument;
66
use CultuurNet\UDB3\ReadModel\JsonDocumentMetaDataEnricherInterface;
67
use CultuurNet\UDB3\RecordedOn;
68
use CultuurNet\UDB3\Theme;
69
use Symfony\Component\Serializer\SerializerInterface;
70
use ValueObjects\StringLiteral\StringLiteral;
71
use ValueObjects\Web\Url;
72
73
/**
74
 * Projects state changes on Event entities to a JSON-LD read model in a
75
 * document repository.
76
 *
77
 * Implements PlaceServiceInterface and OrganizerServiceInterface to do a double
78
 * dispatch with CdbXMLImporter.
79
 */
80
class EventLDProjector extends OfferLDProjector implements
81
    EventListenerInterface,
82
    PlaceServiceInterface,
83
    OrganizerServiceInterface
84
{
85
    /**
86
     * @var PlaceService
87
     */
88
    protected $placeService;
89
90
    /**
91
     * @var EventServiceInterface
92
     */
93
    protected $eventService;
94
95
    /**
96
     * @var IriOfferIdentifierFactoryInterface
97
     */
98
    protected $iriOfferIdentifierFactory;
99
100
    /**
101
     * @var CdbXMLImporter
102
     */
103
    protected $cdbXMLImporter;
104
105
    /**
106
     * @param DocumentRepositoryInterface $repository
107
     * @param IriGeneratorInterface $iriGenerator
108
     * @param EventServiceInterface $eventService
109
     * @param PlaceService $placeService
110
     * @param OrganizerService $organizerService
111
     * @param SerializerInterface $mediaObjectSerializer
112
     * @param IriOfferIdentifierFactoryInterface $iriOfferIdentifierFactory
113
     * @param CdbXMLImporter $cdbXMLImporter
114
     * @param JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
115
     * @param EventSpecification $eventsNotTriggeringUpdateModified
116
     */
117
    public function __construct(
118
        DocumentRepositoryInterface $repository,
119
        IriGeneratorInterface $iriGenerator,
120
        EventServiceInterface $eventService,
121
        PlaceService $placeService,
122
        OrganizerService $organizerService,
123
        SerializerInterface $mediaObjectSerializer,
124
        IriOfferIdentifierFactoryInterface $iriOfferIdentifierFactory,
125
        CdbXMLImporter $cdbXMLImporter,
126
        JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher,
127
        EventSpecification $eventsNotTriggeringUpdateModified
128
    ) {
129
        parent::__construct(
130
            $repository,
131
            $iriGenerator,
132
            $organizerService,
133
            $mediaObjectSerializer,
134
            $jsonDocumentMetaDataEnricher,
135
            $eventsNotTriggeringUpdateModified
136
        );
137
138
        $this->placeService = $placeService;
139
        $this->eventService = $eventService;
140
        $this->cdbXMLImporter = $cdbXMLImporter;
141
142
        $this->iriOfferIdentifierFactory = $iriOfferIdentifierFactory;
143
    }
144
145
    /**
146
     * @param string $id
147
     * @return JsonDocument
148
     */
149 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...
150
    {
151
        $document = new JsonDocument($id);
152
153
        $offerLd = $document->getBody();
154
        $offerLd->{'@id'} = $this->iriGenerator->iri($id);
155
        $offerLd->{'@context'} = '/contexts/event';
156
157
        return $document->withBody($offerLd);
158
    }
159
160
    protected function applyOrganizerProjectedToJSONLD(OrganizerProjectedToJSONLD $organizerProjectedToJSONLD)
161
    {
162
        $eventIds = $this->eventsOrganizedByOrganizer(
163
            $organizerProjectedToJSONLD->getId()
164
        );
165
166
        $organizer = $this->organizerService->getEntity(
167
            $organizerProjectedToJSONLD->getId()
168
        );
169
170
        $documents = [];
171
172 View Code Duplication
        foreach ($eventIds as $eventId) {
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
            $document = $this->loadDocumentFromRepositoryByItemId(
174
                $eventId
175
            );
176
            $eventLD = $document->getBody();
177
178
            $newEventLD = clone $eventLD;
179
            $newEventLD->organizer = json_decode($organizer);
180
181
            if ($newEventLD != $eventLD) {
182
                $documents[] = $document->withBody($newEventLD);
183
            }
184
        }
185
186
        return $documents;
187
    }
188
189
    protected function applyPlaceProjectedToJSONLD(
190
        PlaceProjectedToJSONLD $placeProjectedToJSONLD
191
    ) {
192
        $identifier = $this->iriOfferIdentifierFactory->fromIri(
193
            Url::fromNative($placeProjectedToJSONLD->getIri())
194
        );
195
196
        $eventsLocatedAtPlace = $this->eventsLocatedAtPlace(
197
            $identifier->getId()
198
        );
199
200
        $placeJSONLD = $this->placeService->getEntity(
201
            $identifier->getId()
202
        );
203
204
        $documents = [];
205
206 View Code Duplication
        foreach ($eventsLocatedAtPlace as $eventId) {
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...
207
            $document = $this->loadDocumentFromRepositoryByItemId(
208
                $eventId
209
            );
210
            $eventLD = $document->getBody();
211
212
            $newEventLD = clone $eventLD;
213
            $newEventLD->location = json_decode($placeJSONLD);
214
215
            if ($newEventLD != $eventLD) {
216
                $documents[] = $document->withBody($newEventLD);
217
            }
218
        }
219
220
        return $documents;
221
    }
222
223
    /**
224
     * @param string $organizerId
225
     * @return string[]
226
     */
227
    protected function eventsOrganizedByOrganizer($organizerId)
228
    {
229
        return $this->eventService->eventsOrganizedByOrganizer(
230
            $organizerId
231
        );
232
    }
233
234
    /**
235
     * @param string $placeId
236
     * @return string[]
237
     */
238
    protected function eventsLocatedAtPlace($placeId)
239
    {
240
        return $this->eventService->eventsLocatedAtPlace(
241
            $placeId
242
        );
243
    }
244
245
    /**
246
     * @param EventImportedFromUDB2 $eventImportedFromUDB2
247
     * @return JsonDocument
248
     */
249
    protected function applyEventImportedFromUDB2(
250
        EventImportedFromUDB2 $eventImportedFromUDB2
251
    ) {
252
        return $this->applyEventCdbXmlFromUDB2(
253
            $eventImportedFromUDB2->getEventId(),
254
            $eventImportedFromUDB2->getCdbXmlNamespaceUri(),
255
            $eventImportedFromUDB2->getCdbXml()
256
        );
257
    }
258
259
    /**
260
     * @param EventUpdatedFromUDB2 $eventUpdatedFromUDB2
261
     * @return JsonDocument
262
     */
263
    protected function applyEventUpdatedFromUDB2(
264
        EventUpdatedFromUDB2 $eventUpdatedFromUDB2
265
    ) {
266
        return $this->applyEventCdbXmlFromUDB2(
267
            $eventUpdatedFromUDB2->getEventId(),
268
            $eventUpdatedFromUDB2->getCdbXmlNamespaceUri(),
269
            $eventUpdatedFromUDB2->getCdbXml()
270
        );
271
    }
272
273
    /**
274
     * Helper function to save JSONLD document from entryapi cdbxml.
275
     *
276
     * @param string $eventId
277
     * @param string $cdbXmlNamespaceUri
278
     * @param string $cdbXml
279
     * @param DomainMessage $domainMessage
280
     * @return JsonDocument
281
     */
282
    protected function applyEventFromCdbXml(
283
        $eventId,
284
        $cdbXmlNamespaceUri,
285
        $cdbXml,
286
        $domainMessage
287
    ) {
288
        $document = $this->newDocument($eventId);
289
290
        $eventLd = $this->projectEventCdbXmlToObject(
291
            $document->getBody(),
292
            $eventId,
293
            $cdbXmlNamespaceUri,
294
            $cdbXml
295
        );
296
297
        // Add creation date and update date from domain message.
298
        $created = RecordedOn::fromDomainMessage($domainMessage);
299
        $eventLd->created = $created->toString();
300
        $eventLd->modified = $created->toString();
301
302
        // Add creator.
303
        $eventLd->creator = $this->getAuthorFromMetadata($domainMessage->getMetadata())->toNative();
304
305
        // Add publisher, which is the consumer name.
306
        $eventLd->publisher = $this->getConsumerFromMetadata($domainMessage->getMetadata())->toNative();
307
308
        return $document->withBody($eventLd);
309
    }
310
311
    /**
312
     * Helper function to save a JSON-LD document from cdbxml coming from UDB2.
313
     *
314
     * @param string $eventId
315
     * @param string $cdbXmlNamespaceUri
316
     * @param string $cdbXml
317
     *
318
     * @return JsonDocument
319
     */
320
    protected function applyEventCdbXmlFromUDB2(
321
        $eventId,
322
        $cdbXmlNamespaceUri,
323
        $cdbXml
324
    ) {
325
        $document = $this->newDocument($eventId);
326
327
        $eventLd = $this->projectEventCdbXmlToObject(
328
            $document->getBody(),
329
            $eventId,
330
            $cdbXmlNamespaceUri,
331
            $cdbXml
332
        );
333
334
        return $document->withBody($eventLd);
335
    }
336
337
    /**
338
     * @param \stdClass $jsonLd
339
     * @param string $eventId
340
     * @param string $cdbXmlNamespaceUri
341
     * @param string $cdbXml
342
     *
343
     * @return \stdClass
344
     */
345
    protected function projectEventCdbXmlToObject(
346
        \stdClass $jsonLd,
347
        $eventId,
348
        $cdbXmlNamespaceUri,
349
        $cdbXml
350
    ) {
351
        $udb2Event = EventItemFactory::createEventFromCdbXml(
352
            $cdbXmlNamespaceUri,
353
            $cdbXml
354
        );
355
356
        $jsonLd = $this->cdbXMLImporter->documentWithCdbXML(
357
            $jsonLd,
358
            $udb2Event,
359
            $this,
360
            $this,
361
            $this->slugger
362
        );
363
364
        $this->setMainLanguage($jsonLd, new Language('nl'));
365
366
        // Because we can not properly track media coming from UDB2 we simply
367
        // ignore it and give priority to content added through UDB3.
368
        // It's possible that an event has been deleted in udb3, but never
369
        // in udb2. If an update comes for that event from udb2, it should
370
        // be imported again. This is intended by design.
371
        // @see https://jira.uitdatabank.be/browse/III-1092
372
        try {
373
            $document = $this->loadDocumentFromRepositoryByItemId($eventId);
374
        } catch (DocumentGoneException $documentGoneException) {
375
            $document = $this->newDocument($eventId);
376
        }
377
378
        $media = $this->UDB3Media($document);
379
        if (!empty($media)) {
380
            $jsonLd->mediaObject = $media;
381
        }
382
383
        // Because UDB2 cannot keep track of UDB3 places as a location
384
        // ignore it and give priority to content added through UDB3.
385
        $location = $this->UDB3Location($document);
386
        if (!empty($location)) {
387
            $jsonLd->location = $location;
388
        }
389
390
        return $jsonLd;
391
    }
392
393
    /**
394
     * Return the media of an event if it already exists.
395
     *
396
     * @param JsonDocument $document The JsonDocument.
397
     *
398
     * @return array
399
     *  A list of media objects.
400
     */
401
    private function UDB3Media($document)
402
    {
403
        $media = [];
404
405
        if ($document) {
406
            $item = $document->getBody();
407
            // At the moment we do not include any media coming from UDB2.
408
            // If the mediaObject property contains data it's coming from UDB3.
409
            $item->mediaObject = isset($item->mediaObject) ? $item->mediaObject : [];
410
        }
411
412
        return $media;
413
    }
414
415
    /**
416
     * Return the location of an event if it already exists.
417
     *
418
     * @param JsonDocument $document The JsonDocument.
419
     *
420
     * @return array|null
421
     *  The location
422
     */
423
    private function UDB3Location($document)
424
    {
425
        $location = null;
426
427
        if ($document) {
428
            $item = $document->getBody();
429
            $location = isset($item->location) ? $item->location : null;
430
        }
431
432
        return $location;
433
    }
434
435
    /**
436
     * @param EventCreated $eventCreated
437
     * @param DomainMessage $domainMessage
438
     * @return JsonDocument
439
     */
440
    protected function applyEventCreated(
441
        EventCreated $eventCreated,
442
        DomainMessage $domainMessage
443
    ) {
444
        $document = $this->newDocument($eventCreated->getEventId());
445
        $jsonLD = $document->getBody();
446
447
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
448
            $eventCreated->getEventId()
449
        );
450
451
        $this->setMainLanguage($jsonLD, new Language('nl'));
452
453
        $jsonLD->name['nl'] = $eventCreated->getTitle();
454
        $jsonLD->location = array(
455
                '@type' => 'Place',
456
            ) + (array)$this->placeJSONLD(
457
                $eventCreated->getLocation()->getCdbid()
458
            );
459
460
        $calendarJsonLD = $eventCreated->getCalendar()->toJsonLd();
461
        $jsonLD = (object)array_merge((array)$jsonLD, $calendarJsonLD);
462
463
        $availableTo = AvailableTo::createFromCalendar($eventCreated->getCalendar());
464
        $jsonLD->availableTo = (string)$availableTo;
465
466
        // Same as.
467
        $jsonLD->sameAs = $this->generateSameAs(
468
            $eventCreated->getEventId(),
469
            reset($jsonLD->name)
470
        );
471
472
        $eventType = $eventCreated->getEventType();
473
        $jsonLD->terms = [
474
            $eventType->toJsonLd(),
475
        ];
476
477
        $theme = $eventCreated->getTheme();
478
        if (!empty($theme)) {
479
            $jsonLD->terms[] = $theme->toJsonLd();
480
        }
481
482
        $created = RecordedOn::fromDomainMessage($domainMessage);
483
        $jsonLD->created = $created->toString();
484
        $jsonLD->modified = $created->toString();
485
486
        $metaData = $domainMessage->getMetadata()->serialize();
487 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...
488
            $jsonLD->creator = $metaData['user_email'];
489
        } elseif (isset($metaData['user_nick'])) {
490
            $jsonLD->creator = $metaData['user_nick'];
491
        }
492
493
        $jsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
494
495
        $defaultAudience = new Audience(AudienceType::EVERYONE());
496
        $jsonLD->audience = $defaultAudience->serialize();
497
498
        return $document->withBody($jsonLD);
499
    }
500
501
    /**
502
     * @param EventCopied $eventCopied
503
     * @param DomainMessage $domainMessage
504
     * @return JsonDocument
505
     */
506
    protected function applyEventCopied(
507
        EventCopied $eventCopied,
508
        DomainMessage $domainMessage
509
    ) {
510
        $originalDocument = $this->repository->get($eventCopied->getOriginalEventId());
511
        $eventJsonLD = $originalDocument->getBody();
512
513
        // Set the created and modified date.
514
        $created = RecordedOn::fromDomainMessage($domainMessage);
515
        $eventJsonLD->created = $created->toString();
516
        $eventJsonLD->modified = $created->toString();
517
518
        // Set the creator.
519
        $eventJsonLD->creator = $this->getAuthorFromMetadata($domainMessage->getMetadata())->toNative();
520
521
        // Set the id.
522
        $eventJsonLD->{'@id'} = $this->iriGenerator->iri($eventCopied->getItemId());
523
524
        // Set the new calendar.
525
        $eventJsonLD = (object) array_merge(
526
            (array) $eventJsonLD,
527
            $eventCopied->getCalendar()->toJsonLd()
528
        );
529
530
        // Set workflow status.
531
        $eventJsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
532
533
        // Remove labels.
534
        unset($eventJsonLD->labels);
535
        unset($eventJsonLD->hiddenLabels);
536
537
        // Set available to and from.
538
        $availableTo = AvailableTo::createFromCalendar($eventCopied->getCalendar());
539
        $eventJsonLD->availableTo = (string) $availableTo;
540
        unset($eventJsonLD->availableFrom);
541
542
        $newDocument = new JsonDocument($eventCopied->getItemId());
543
        $newDocument = $newDocument->withBody($eventJsonLD);
544
        return $newDocument;
545
    }
546
547
    /**
548
     * @param EventDeleted $eventDeleted
549
     * @return null
550
     */
551 View Code Duplication
    protected function applyEventDeleted(EventDeleted $eventDeleted)
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...
552
    {
553
        $document = $this->loadDocumentFromRepository($eventDeleted);
554
555
        $jsonLD = $document->getBody();
556
557
        $jsonLD->workflowStatus = WorkflowStatus::DELETED()->getName();
558
559
        return $document->withBody($jsonLD);
560
    }
561
562
    /**
563
     * Apply the major info updated command to the projector.
564
     * @param MajorInfoUpdated $majorInfoUpdated
565
     * @return JsonDocument
566
     */
567
    protected function applyMajorInfoUpdated(MajorInfoUpdated $majorInfoUpdated)
568
    {
569
        $document = $this
570
            ->loadDocumentFromRepository($majorInfoUpdated)
571
            ->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...
572
573
        $jsonLD = $document->getBody();
574
575
        $jsonLD->name->nl = $majorInfoUpdated->getTitle();
576
        $jsonLD->location = array(
577
          '@type' => 'Place',
578
        ) + (array)$this->placeJSONLD($majorInfoUpdated->getLocation()->getCdbid());
579
580
        $availableTo = AvailableTo::createFromCalendar($majorInfoUpdated->getCalendar());
581
        $jsonLD->availableTo = (string)$availableTo;
582
583
        // Remove old theme and event type.
584
        $jsonLD->terms = array_filter($jsonLD->terms, function ($term) {
585
            return $term->domain !== EventType::DOMAIN &&  $term->domain !== Theme::DOMAIN;
586
        });
587
        $jsonLD->terms = array_values($jsonLD->terms);
588
589
        $eventType = $majorInfoUpdated->getEventType();
590
        $jsonLD->terms[] = $eventType->toJsonLd();
591
592
        $theme = $majorInfoUpdated->getTheme();
593
        if (!empty($theme)) {
594
            $jsonLD->terms[] = $theme->toJsonLd();
595
        }
596
597
        return $document->withBody($jsonLD);
598
    }
599
600
    /**
601
     * @param LocationUpdated $locationUpdated
602
     *
603
     * @return JsonDocument
604
     */
605
    public function applyLocationUpdated(LocationUpdated $locationUpdated)
606
    {
607
        $document = $this->loadDocumentFromRepository($locationUpdated);
608
609
        $jsonLD = $document->getBody();
610
611
        $jsonLD->location = [
612
            '@type' => 'Place',
613
         ] + (array) $this->placeJSONLD($locationUpdated->getLocationId()->toNative());
614
615
        return $document->withBody($jsonLD);
616
    }
617
618
    /**
619
     * @param GeoCoordinatesUpdated $geoCoordinatesUpdated
620
     * @return JsonDocument
621
     */
622 View Code Duplication
    protected function applyGeoCoordinatesUpdated(GeoCoordinatesUpdated $geoCoordinatesUpdated)
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...
623
    {
624
        $document = $this->loadDocumentFromRepositoryByItemId($geoCoordinatesUpdated->getItemId());
625
626
        $placeLd = $document->getBody();
627
628
        $placeLd->geo = (object) [
629
            'latitude' => $geoCoordinatesUpdated->getCoordinates()->getLatitude()->toDouble(),
630
            'longitude' => $geoCoordinatesUpdated->getCoordinates()->getLongitude()->toDouble(),
631
        ];
632
633
        return $document->withBody($placeLd);
634
    }
635
636
    /**
637
     * @param AudienceUpdated $audienceUpdated
638
     * @return JsonDocument
639
     */
640
    protected function applyAudienceUpdated(AudienceUpdated $audienceUpdated)
641
    {
642
        $document = $this->loadDocumentFromRepository($audienceUpdated);
643
        $jsonLD = $document->getBody();
644
645
        $jsonLD->audience = $audienceUpdated->getAudience()->serialize();
646
647
        return $document->withBody($jsonLD);
648
    }
649
650
    /**
651
     * @inheritdoc
652
     */
653
    public function placeJSONLD($placeId)
654
    {
655
        if (empty($placeId)) {
656
            return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type declared by the interface CultuurNet\UDB3\Event\Re...eInterface::placeJSONLD of type stdClass.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
657
        }
658
659
        try {
660
            $placeJSONLD = $this->placeService->getEntity(
661
                $placeId
662
            );
663
664
            return json_decode($placeJSONLD);
665
        } catch (EntityNotFoundException $e) {
666
            // In case the place can not be found at the moment, just add its ID
667
            return array(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('@id' => $t...ervice->iri($placeId)); (array<string,string>) is incompatible with the return type declared by the interface CultuurNet\UDB3\Event\Re...eInterface::placeJSONLD of type stdClass.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
668
                '@id' => $this->placeService->iri($placeId),
669
            );
670
        } catch (DocumentGoneException $e) {
671
            // In case the place can not be found at the moment, just add its ID
672
            return array(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('@id' => $t...ervice->iri($placeId)); (array<string,string>) is incompatible with the return type declared by the interface CultuurNet\UDB3\Event\Re...eInterface::placeJSONLD of type stdClass.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
673
                '@id' => $this->placeService->iri($placeId),
674
            );
675
        }
676
    }
677
678
    private function generateSameAs($eventId, $name)
679
    {
680
        $eventSlug = $this->slugger->slug($name);
681
        return array(
682
            'http://www.uitinvlaanderen.be/agenda/e/' . $eventSlug . '/' . $eventId,
683
        );
684
    }
685
686 View Code Duplication
    private function getAuthorFromMetadata(Metadata $metadata)
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...
687
    {
688
        $properties = $metadata->serialize();
689
690
        if (isset($properties['user_nick'])) {
691
            return new StringLiteral($properties['user_nick']);
692
        }
693
    }
694
695 View Code Duplication
    private function getConsumerFromMetadata(Metadata $metadata)
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...
696
    {
697
        $properties = $metadata->serialize();
698
699
        if (isset($properties['consumer']['name'])) {
700
            return new StringLiteral($properties['consumer']['name']);
701
        }
702
    }
703
704
    /**
705
     * @return string
706
     */
707
    protected function getLabelAddedClassName()
708
    {
709
        return LabelAdded::class;
710
    }
711
712
    /**
713
     * @return string
714
     */
715
    protected function getLabelRemovedClassName()
716
    {
717
        return LabelRemoved::class;
718
    }
719
720
    /**
721
     * @return string
722
     */
723
    protected function getImageAddedClassName()
724
    {
725
        return ImageAdded::class;
726
    }
727
728
    /**
729
     * @return string
730
     */
731
    protected function getImageRemovedClassName()
732
    {
733
        return ImageRemoved::class;
734
    }
735
736
    /**
737
     * @return string
738
     */
739
    protected function getImageUpdatedClassName()
740
    {
741
        return ImageUpdated::class;
742
    }
743
744
    protected function getMainImageSelectedClassName()
745
    {
746
        return MainImageSelected::class;
747
    }
748
749
    /**
750
     * @return string
751
     */
752
    protected function getTitleTranslatedClassName()
753
    {
754
        return TitleTranslated::class;
755
    }
756
757
    /**
758
     * @return string
759
     */
760
    protected function getDescriptionTranslatedClassName()
761
    {
762
        return DescriptionTranslated::class;
763
    }
764
765
    /**
766
     * @return string
767
     */
768
    protected function getOrganizerUpdatedClassName()
769
    {
770
        return OrganizerUpdated::class;
771
    }
772
773
    /**
774
     * @return string
775
     */
776
    protected function getOrganizerDeletedClassName()
777
    {
778
        return OrganizerDeleted::class;
779
    }
780
781
    protected function getBookingInfoUpdatedClassName()
782
    {
783
        return BookingInfoUpdated::class;
784
    }
785
786
    /**
787
     * @return string
788
     */
789
    protected function getPriceInfoUpdatedClassName()
790
    {
791
        return PriceInfoUpdated::class;
792
    }
793
794
    protected function getContactPointUpdatedClassName()
795
    {
796
        return ContactPointUpdated::class;
797
    }
798
799
    protected function getDescriptionUpdatedClassName()
800
    {
801
        return DescriptionUpdated::class;
802
    }
803
804
    protected function getCalendarUpdatedClassName()
805
    {
806
        return CalendarUpdated::class;
807
    }
808
809
    protected function getTypicalAgeRangeUpdatedClassName()
810
    {
811
        return TypicalAgeRangeUpdated::class;
812
    }
813
814
    protected function getTypicalAgeRangeDeletedClassName()
815
    {
816
        return TypicalAgeRangeDeleted::class;
817
    }
818
819
    protected function getPublishedClassName()
820
    {
821
        return Published::class;
822
    }
823
824
    protected function getApprovedClassName()
825
    {
826
        return Approved::class;
827
    }
828
829
    protected function getRejectedClassName()
830
    {
831
        return Rejected::class;
832
    }
833
834
    protected function getFlaggedAsDuplicateClassName()
835
    {
836
        return FlaggedAsDuplicate::class;
837
    }
838
839
    protected function getFlaggedAsInappropriateClassName()
840
    {
841
        return FlaggedAsInappropriate::class;
842
    }
843
844
    protected function getImagesImportedFromUdb2ClassName()
845
    {
846
        return ImagesImportedFromUDB2::class;
847
    }
848
849
    protected function getImagesUpdatedFromUdb2ClassName()
850
    {
851
        return ImagesUpdatedFromUDB2::class;
852
    }
853
854
    protected function getTitleUpdatedClassName()
855
    {
856
        return TitleUpdated::class;
857
    }
858
859
    protected function getTypeUpdatedClassName()
860
    {
861
        return TypeUpdated::class;
862
    }
863
864
    protected function getThemeUpdatedClassName()
865
    {
866
        return ThemeUpdated::class;
867
    }
868
869
    protected function getFacilitiesUpdatedClassName()
870
    {
871
        return FacilitiesUpdated::class;
872
    }
873
}
874