Completed
Push — master ( d7130a...41d031 )
by Luc
10:22
created

OfferLDProjector::applyDescriptionUpdated()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 2
eloc 8
nc 2
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3\Offer\ReadModel\JSONLD;
4
5
use Broadway\Domain\DomainMessage;
6
use CultuurNet\UDB3\CulturefeedSlugger;
7
use CultuurNet\UDB3\EntityNotFoundException;
8
use CultuurNet\UDB3\EntityServiceInterface;
9
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
10
use CultuurNet\UDB3\Event\ReadModel\JSONLD\OrganizerServiceInterface;
11
use CultuurNet\UDB3\EventHandling\DelegateEventHandlingToSpecificMethodTrait;
12
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
13
use CultuurNet\UDB3\Label;
14
use CultuurNet\UDB3\Media\Image;
15
use CultuurNet\UDB3\Offer\Events\AbstractBookingInfoUpdated;
16
use CultuurNet\UDB3\Offer\Events\AbstractContactPointUpdated;
17
use CultuurNet\UDB3\Offer\Events\AbstractDescriptionTranslated;
18
use CultuurNet\UDB3\Offer\Events\AbstractDescriptionUpdated;
19
use CultuurNet\UDB3\Offer\Events\AbstractEvent;
20
use CultuurNet\UDB3\Offer\Events\AbstractLabelAdded;
21
use CultuurNet\UDB3\Offer\Events\AbstractLabelRemoved;
22
use CultuurNet\UDB3\Offer\Events\AbstractOrganizerDeleted;
23
use CultuurNet\UDB3\Offer\Events\AbstractOrganizerUpdated;
24
use CultuurNet\UDB3\Offer\Events\AbstractPriceInfoUpdated;
25
use CultuurNet\UDB3\Offer\Events\AbstractTitleTranslated;
26
use CultuurNet\UDB3\Offer\Events\AbstractTypicalAgeRangeDeleted;
27
use CultuurNet\UDB3\Offer\Events\AbstractTypicalAgeRangeUpdated;
28
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageAdded;
29
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageRemoved;
30
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesEvent;
31
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesImportedFromUDB2;
32
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesUpdatedFromUDB2;
33
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageUpdated;
34
use CultuurNet\UDB3\Offer\Events\Image\AbstractMainImageSelected;
35
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractApproved;
36
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractFlaggedAsDuplicate;
37
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractFlaggedAsInappropriate;
38
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractPublished;
39
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractRejected;
40
use CultuurNet\UDB3\Offer\WorkflowStatus;
41
use CultuurNet\UDB3\ReadModel\JsonDocument;
42
use CultuurNet\UDB3\ReadModel\JsonDocumentMetaDataEnricherInterface;
43
use CultuurNet\UDB3\ReadModel\MultilingualJsonLDProjectorTrait;
44
use CultuurNet\UDB3\SluggerInterface;
45
use Symfony\Component\Serializer\SerializerInterface;
46
use ValueObjects\Identity\UUID;
47
48
abstract class OfferLDProjector implements OrganizerServiceInterface
49
{
50
    use MultilingualJsonLDProjectorTrait;
51
    use DelegateEventHandlingToSpecificMethodTrait {
52
        DelegateEventHandlingToSpecificMethodTrait::handle as handleUnknownEvents;
53
    }
54
55
    /**
56
     * @var DocumentRepositoryInterface
57
     */
58
    protected $repository;
59
60
    /**
61
     * @var IriGeneratorInterface
62
     */
63
    protected $iriGenerator;
64
65
    /**
66
     * @var EntityServiceInterface
67
     */
68
    protected $organizerService;
69
70
    /**
71
     * @var JsonDocumentMetaDataEnricherInterface
72
     */
73
    protected $jsonDocumentMetaDataEnricher;
74
75
    /**
76
     * @var SerializerInterface
77
     */
78
    protected $mediaObjectSerializer;
79
80
    /**
81
     * @var SluggerInterface
82
     */
83
    protected $slugger;
84
85
    /**
86
     * @param DocumentRepositoryInterface $repository
87
     * @param IriGeneratorInterface $iriGenerator
88
     * @param EntityServiceInterface $organizerService
89
     * @param SerializerInterface $mediaObjectSerializer
90
     * @param JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
91
     */
92
    public function __construct(
93
        DocumentRepositoryInterface $repository,
94
        IriGeneratorInterface $iriGenerator,
95
        EntityServiceInterface $organizerService,
96
        SerializerInterface $mediaObjectSerializer,
97
        JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
98
    ) {
99
        $this->repository = $repository;
100
        $this->iriGenerator = $iriGenerator;
101
        $this->organizerService = $organizerService;
102
        $this->jsonDocumentMetaDataEnricher = $jsonDocumentMetaDataEnricher;
103
        $this->mediaObjectSerializer = $mediaObjectSerializer;
104
105
        $this->slugger = new CulturefeedSlugger();
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function handle(DomainMessage $domainMessage)
112
    {
113
        $event = $domainMessage->getPayload();
114
115
        $eventName = get_class($event);
116
        $eventHandlers = $this->getEventHandlers();
117
118
        if (isset($eventHandlers[$eventName])) {
119
            $handler = $eventHandlers[$eventName];
120
            $jsonDocuments = call_user_func(array($this, $handler), $event, $domainMessage);
121
        } elseif ($methodName = $this->getHandleMethodName($event)) {
122
            $jsonDocuments = $this->{$methodName}($event, $domainMessage);
123
        } else {
124
            return;
125
        }
126
127
        if (!$jsonDocuments) {
128
            return;
129
        }
130
131
        if (!is_array($jsonDocuments)) {
132
            $jsonDocuments = [$jsonDocuments];
133
        }
134
135
        foreach ($jsonDocuments as $jsonDocument) {
136
            $jsonDocument = $this->jsonDocumentMetaDataEnricher->enrich($jsonDocument, $domainMessage->getMetadata());
137
            $this->repository->save($jsonDocument);
138
        }
139
    }
140
141
    /**
142
     * @return string[]
143
     *   An associative array of commands and their handler methods.
144
     */
145 View Code Duplication
    private function getEventHandlers()
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...
146
    {
147
        $events = [];
148
149
        foreach (get_class_methods($this) as $method) {
150
            $matches = [];
151
152
            if (preg_match('/^apply(.+)$/', $method, $matches)) {
153
                $event = $matches[1];
154
                $classNameMethod = 'get' . $event . 'ClassName';
155
156
                if (method_exists($this, $classNameMethod)) {
157
                    $eventFullClassName = call_user_func(array($this, $classNameMethod));
158
                    $events[$eventFullClassName] = $method;
159
                }
160
            }
161
        }
162
163
        return $events;
164
    }
165
166
    /**
167
     * @return string
168
     */
169
    abstract protected function getLabelAddedClassName();
170
171
    /**
172
     * @return string
173
     */
174
    abstract protected function getLabelRemovedClassName();
175
176
    /**
177
     * @return string
178
     */
179
    abstract protected function getImageAddedClassName();
180
181
    /**
182
     * @return string
183
     */
184
    abstract protected function getImageRemovedClassName();
185
186
    /**
187
     * @return string
188
     */
189
    abstract protected function getImageUpdatedClassName();
190
191
    /**
192
     * @return string
193
     */
194
    abstract protected function getMainImageSelectedClassName();
195
196
    /**
197
     * @return string
198
     */
199
    abstract protected function getTitleTranslatedClassName();
200
201
    /**
202
     * @return string
203
     */
204
    abstract protected function getDescriptionTranslatedClassName();
205
206
    /**
207
     * @return string
208
     */
209
    abstract protected function getOrganizerUpdatedClassName();
210
211
    /**
212
     * @return string
213
     */
214
    abstract protected function getOrganizerDeletedClassName();
215
216
    /**
217
     * @return string
218
     */
219
    abstract protected function getBookingInfoUpdatedClassName();
220
221
    /**
222
     * @return string
223
     */
224
    abstract protected function getPriceInfoUpdatedClassName();
225
226
    /**
227
     * @return string
228
     */
229
    abstract protected function getContactPointUpdatedClassName();
230
231
    /**
232
     * @return string
233
     */
234
    abstract protected function getDescriptionUpdatedClassName();
235
236
    /**
237
     * @return string
238
     */
239
    abstract protected function getTypicalAgeRangeUpdatedClassName();
240
241
    /**
242
     * @return string
243
     */
244
    abstract protected function getTypicalAgeRangeDeletedClassName();
245
246
    /**
247
     * @return string
248
     */
249
    abstract protected function getPublishedClassName();
250
251
    /**
252
     * @return string
253
     */
254
    abstract protected function getApprovedClassName();
255
256
    /**
257
     * @return string
258
     */
259
    abstract protected function getRejectedClassName();
260
261
    /**
262
     * @return string
263
     */
264
    abstract protected function getFlaggedAsDuplicateClassName();
265
266
    /**
267
     * @return string
268
     */
269
    abstract protected function getFlaggedAsInappropriateClassName();
270
271
    /**
272
     * @return string
273
     */
274
    abstract protected function getImagesImportedFromUdb2ClassName();
275
276
    /**
277
     * @return string
278
     */
279
    abstract protected function getImagesUpdatedFromUdb2ClassName();
280
281
    /**
282
     * @param AbstractLabelAdded $labelAdded
283
     * @return JsonDocument
284
     */
285
    protected function applyLabelAdded(AbstractLabelAdded $labelAdded)
286
    {
287
        $document = $this->loadDocumentFromRepository($labelAdded);
288
289
        $offerLd = $document->getBody();
290
291
        // Check the visibility of the label to update the right property.
292
        $labelsProperty = $labelAdded->getLabel()->isVisible() ? 'labels' : 'hiddenLabels';
293
294
        $labels = isset($offerLd->{$labelsProperty}) ? $offerLd->{$labelsProperty} : [];
295
        $label = (string) $labelAdded->getLabel();
296
297
        $labels[] = $label;
298
        $offerLd->{$labelsProperty} = array_unique($labels);
299
300
        return $document->withBody($offerLd);
301
    }
302
303
    /**
304
     * @param AbstractLabelRemoved $labelRemoved
305
     * @return JsonDocument
306
     */
307 View Code Duplication
    protected function applyLabelRemoved(AbstractLabelRemoved $labelRemoved)
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...
308
    {
309
        $document = $this->loadDocumentFromRepository($labelRemoved);
310
311
        $offerLd = $document->getBody();
312
313
        // Don't presume that the label visibility is correct when removing.
314
        // So iterate over both the visible and invisible labels.
315
        $labelsProperties = ['labels', 'hiddenLabels'];
316
317
        foreach ($labelsProperties as $labelsProperty) {
318
            if (isset($offerLd->{$labelsProperty}) && is_array($offerLd->{$labelsProperty})) {
319
                $offerLd->{$labelsProperty} = array_filter(
320
                    $offerLd->{$labelsProperty},
321
                    function ($label) use ($labelRemoved) {
322
                        return !$labelRemoved->getLabel()->equals(
323
                            new Label($label)
324
                        );
325
                    }
326
                );
327
                // Ensure array keys start with 0 so json_encode() does encode it
328
                // as an array and not as an object.
329
                if (count($offerLd->{$labelsProperty}) > 0) {
330
                    $offerLd->{$labelsProperty} = array_values($offerLd->{$labelsProperty});
331
                } else {
332
                    unset($offerLd->{$labelsProperty});
333
                }
334
            }
335
        }
336
337
        return $document->withBody($offerLd);
338
    }
339
340
    /**
341
     * Apply the imageAdded event to the item repository.
342
     *
343
     * @param AbstractImageAdded $imageAdded
344
     * @return JsonDocument
345
     */
346
    protected function applyImageAdded(AbstractImageAdded $imageAdded)
347
    {
348
        $document = $this->loadDocumentFromRepository($imageAdded);
349
350
        $offerLd = $document->getBody();
351
        $offerLd->mediaObject = isset($offerLd->mediaObject) ? $offerLd->mediaObject : [];
352
353
        $imageData = $this->mediaObjectSerializer
354
            ->serialize($imageAdded->getImage(), 'json-ld');
355
        $offerLd->mediaObject[] = $imageData;
356
357
        if (count($offerLd->mediaObject) === 1) {
358
            $offerLd->image = $imageData['contentUrl'];
359
        }
360
361
        return $document->withBody($offerLd);
362
    }
363
364
    /**
365
     * Apply the ImageUpdated event to the item repository.
366
     *
367
     * @param AbstractImageUpdated $imageUpdated
368
     * @return JsonDocument
369
     * @throws \Exception
370
     */
371
    protected function applyImageUpdated(AbstractImageUpdated $imageUpdated)
372
    {
373
        $document = $this->loadDocumentFromRepository($imageUpdated);
374
375
        $offerLd = $document->getBody();
376
377
        if (!isset($offerLd->mediaObject)) {
378
            throw new \Exception('The image to update could not be found.');
379
        }
380
381
        $updatedMediaObjects = [];
382
383
        foreach ($offerLd->mediaObject as $mediaObject) {
384
            $mediaObjectMatches = (
385
                strpos(
386
                    $mediaObject->{'@id'},
387
                    (string)$imageUpdated->getMediaObjectId()
388
                ) > 0
389
            );
390
391
            if ($mediaObjectMatches) {
392
                $mediaObject->description = (string)$imageUpdated->getDescription();
393
                $mediaObject->copyrightHolder = (string)$imageUpdated->getCopyrightHolder();
394
395
                $updatedMediaObjects[] = $mediaObject;
396
            }
397
        };
398
399
        if (empty($updatedMediaObjects)) {
400
            throw new \Exception('The image to update could not be found.');
401
        }
402
403
        return $document->withBody($offerLd);
404
    }
405
406
    /**
407
     * @param AbstractImageRemoved $imageRemoved
408
     * @return JsonDocument
409
     */
410
    protected function applyImageRemoved(AbstractImageRemoved $imageRemoved)
411
    {
412
        $document = $this->loadDocumentFromRepository($imageRemoved);
413
414
        $offerLd = $document->getBody();
415
416
        // Nothing to remove if there are no media objects!
417
        if (!isset($offerLd->mediaObject)) {
418
            return;
419
        }
420
421
        $imageId = (string) $imageRemoved->getImage()->getMediaObjectId();
422
423
        /**
424
         * Matches any object that is not the removed image.
425
         *
426
         * @param Object $mediaObject
427
         *  An existing projection of a media object.
428
         *
429
         * @return bool
430
         *  Returns true when the media object does not match the image to remove.
431
         */
432
        $shouldNotBeRemoved = function ($mediaObject) use ($imageId) {
433
            $containsId = !!strpos($mediaObject->{'@id'}, $imageId);
434
            return !$containsId;
435
        };
436
437
        // Remove any media objects that match the image.
438
        $filteredMediaObjects = array_filter(
439
            $offerLd->mediaObject,
440
            $shouldNotBeRemoved
441
        );
442
443
        // Unset the main image if it matches the removed image
444
        if (isset($offerLd->image) && strpos($offerLd->{'image'}, $imageId)) {
445
            unset($offerLd->{"image"});
446
        }
447
448
        if (!isset($offerLd->image) && count($filteredMediaObjects) > 0) {
449
            $offerLd->image = array_values($filteredMediaObjects)[0]->contentUrl;
450
        }
451
452
        // If no media objects are left remove the attribute.
453
        if (empty($filteredMediaObjects)) {
454
            unset($offerLd->{"mediaObject"});
455
        } else {
456
            $offerLd->mediaObject = array_values($filteredMediaObjects);
457
        }
458
459
        return $document->withBody($offerLd);
460
    }
461
462
    /**
463
     * @param AbstractMainImageSelected $mainImageSelected
464
     * @return JsonDocument
465
     */
466
    protected function applyMainImageSelected(AbstractMainImageSelected $mainImageSelected)
467
    {
468
        $document = $this->loadDocumentFromRepository($mainImageSelected);
469
        $offerLd = $document->getBody();
470
        $imageId = $mainImageSelected->getImage()->getMediaObjectId();
471
        $mediaObjectMatcher = function ($matchingMediaObject, $currentMediaObject) use ($imageId) {
472
            if (!$matchingMediaObject && $this->mediaObjectMatchesId($currentMediaObject, $imageId)) {
473
                $matchingMediaObject = $currentMediaObject;
474
            }
475
476
            return $matchingMediaObject;
477
        };
478
        $mediaObject = array_reduce(
479
            $offerLd->mediaObject,
480
            $mediaObjectMatcher
481
        );
482
483
        $offerLd->image = $mediaObject->contentUrl;
484
485
        return $document->withBody($offerLd);
486
    }
487
488
    /**
489
     * @param Object $mediaObject
490
     * @param UUID $mediaObjectId
491
     *
492
     * @return bool
493
     */
494
    protected function mediaObjectMatchesId($mediaObject, UUID $mediaObjectId)
495
    {
496
        return strpos($mediaObject->{'@id'}, (string) $mediaObjectId) > 0;
497
    }
498
499
    /**
500
     * @param AbstractTitleTranslated $titleTranslated
501
     * @return JsonDocument
502
     */
503
    protected function applyTitleTranslated(AbstractTitleTranslated $titleTranslated)
504
    {
505
        $document = $this->loadDocumentFromRepository($titleTranslated);
506
507
        $offerLd = $document->getBody();
508
        $offerLd->name->{$titleTranslated->getLanguage()->getCode(
509
        )} = $titleTranslated->getTitle()->toNative();
510
511
        return $document->withBody($offerLd);
512
    }
513
514
    /**
515
     * @param AbstractDescriptionTranslated $descriptionTranslated
516
     * @return JsonDocument
517
     */
518
    protected function applyDescriptionTranslated(
519
        AbstractDescriptionTranslated $descriptionTranslated
520
    ) {
521
        $document = $this->loadDocumentFromRepository($descriptionTranslated);
522
523
        $offerLd = $document->getBody();
524
        $languageCode = $descriptionTranslated->getLanguage()->getCode();
525
        $description = $descriptionTranslated->getDescription()->toNative();
0 ignored issues
show
Bug introduced by
The method toNative cannot be called on $descriptionTranslated->getDescription() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
526
        if (empty($offerLd->description)) {
527
            $offerLd->description = new \stdClass();
528
        }
529
        $offerLd->description->{$languageCode} = $description;
530
531
        return $document->withBody($offerLd);
532
    }
533
534
    /**
535
     * Apply the organizer updated event to the offer repository.
536
     * @param AbstractOrganizerUpdated $organizerUpdated
537
     * @return JsonDocument
538
     */
539
    protected function applyOrganizerUpdated(AbstractOrganizerUpdated $organizerUpdated)
540
    {
541
        $document = $this->loadDocumentFromRepository($organizerUpdated);
542
543
        $offerLd = $document->getBody();
544
545
        $offerLd->organizer = array(
546
                '@type' => 'Organizer',
547
            ) + (array)$this->organizerJSONLD($organizerUpdated->getOrganizerId());
548
549
        return $document->withBody($offerLd);
550
    }
551
552
    /**
553
     * Apply the organizer delete event to the offer repository.
554
     * @param AbstractOrganizerDeleted $organizerDeleted
555
     * @return JsonDocument
556
     */
557
    protected function applyOrganizerDeleted(AbstractOrganizerDeleted $organizerDeleted)
558
    {
559
        $document = $this->loadDocumentFromRepository($organizerDeleted);
560
561
        $offerLd = $document->getBody();
562
563
        unset($offerLd->organizer);
564
565
        return $document->withBody($offerLd);
566
    }
567
568
    /**
569
     * Apply the booking info updated event to the offer repository.
570
     * @param AbstractBookingInfoUpdated $bookingInfoUpdated
571
     * @return JsonDocument
572
     */
573
    protected function applyBookingInfoUpdated(AbstractBookingInfoUpdated $bookingInfoUpdated)
574
    {
575
        $document = $this->loadDocumentFromRepository($bookingInfoUpdated);
576
577
        $offerLd = $document->getBody();
578
        $offerLd->bookingInfo = $bookingInfoUpdated->getBookingInfo()->toJsonLd();
579
580
        return $document->withBody($offerLd);
581
    }
582
583
    /**
584
     * @param AbstractPriceInfoUpdated $priceInfoUpdated
585
     * @return JsonDocument
586
     */
587
    protected function applyPriceInfoUpdated(AbstractPriceInfoUpdated $priceInfoUpdated)
588
    {
589
        $document = $this->loadDocumentFromRepository($priceInfoUpdated);
590
591
        $offerLd = $document->getBody();
592
        $offerLd->priceInfo = [];
593
594
        $basePrice = $priceInfoUpdated->getPriceInfo()->getBasePrice();
595
596
        $offerLd->priceInfo[] = [
597
            'category' => 'base',
598
            'name' => 'Basistarief',
599
            'price' => $basePrice->getPrice()->toFloat(),
600
            'priceCurrency' => $basePrice->getCurrency()->getCode()->toNative(),
601
        ];
602
603
        foreach ($priceInfoUpdated->getPriceInfo()->getTariffs() as $tariff) {
604
            $offerLd->priceInfo[] = [
605
                'category' => 'tariff',
606
                'name' => $tariff->getName()->toNative(),
607
                'price' => $tariff->getPrice()->toFloat(),
608
                'priceCurrency' => $tariff->getCurrency()->getCode()->toNative(),
609
            ];
610
        }
611
612
        return $document->withBody($offerLd);
613
    }
614
615
    /**
616
     * Apply the contact point updated event to the offer repository.
617
     * @param AbstractContactPointUpdated $contactPointUpdated
618
     * @return JsonDocument
619
     */
620
    protected function applyContactPointUpdated(AbstractContactPointUpdated $contactPointUpdated)
621
    {
622
        $document = $this->loadDocumentFromRepository($contactPointUpdated);
623
624
        $offerLd = $document->getBody();
625
        $offerLd->contactPoint = $contactPointUpdated->getContactPoint()->toJsonLd();
626
627
        return $document->withBody($offerLd);
628
    }
629
630
    /**
631
     * Apply the description updated event to the offer repository.
632
     * @param AbstractDescriptionUpdated $descriptionUpdated
633
     * @return JsonDocument
634
     */
635
    protected function applyDescriptionUpdated(
636
        AbstractDescriptionUpdated $descriptionUpdated
637
    ) {
638
        $document = $this->loadDocumentFromRepository($descriptionUpdated);
639
640
        $offerLd = $document->getBody();
641
        if (empty($offerLd->description)) {
642
            $offerLd->description = new \stdClass();
643
        }
644
        $offerLd->description->{'nl'} = $descriptionUpdated->getDescription();
645
646
        return $document->withBody($offerLd);
647
    }
648
649
    /**
650
     * Apply the typical age range updated event to the offer repository.
651
     * @param AbstractTypicalAgeRangeUpdated $typicalAgeRangeUpdated
652
     * @return JsonDocument
653
     */
654
    protected function applyTypicalAgeRangeUpdated(
655
        AbstractTypicalAgeRangeUpdated $typicalAgeRangeUpdated
656
    ) {
657
        $document = $this->loadDocumentFromRepository($typicalAgeRangeUpdated);
658
659
        $offerLd = $document->getBody();
660
        $offerLd->typicalAgeRange = (string) $typicalAgeRangeUpdated->getTypicalAgeRange();
661
662
        return $document->withBody($offerLd);
663
    }
664
665
    /**
666
     * Apply the typical age range deleted event to the offer repository.
667
     * @param AbstractTypicalAgeRangeDeleted $typicalAgeRangeDeleted
668
     * @return JsonDocument
669
     */
670
    protected function applyTypicalAgeRangeDeleted(
671
        AbstractTypicalAgeRangeDeleted $typicalAgeRangeDeleted
672
    ) {
673
        $document = $this->loadDocumentFromRepository($typicalAgeRangeDeleted);
674
675
        $offerLd = $document->getBody();
676
677
        unset($offerLd->typicalAgeRange);
678
679
        return $document->withBody($offerLd);
680
    }
681
682
    /**
683
     * @param AbstractPublished $published
684
     * @return JsonDocument
685
     */
686
    protected function applyPublished(AbstractPublished $published)
687
    {
688
        $document = $this->loadDocumentFromRepository($published);
689
690
        $offerLd = $document->getBody();
691
692
        $offerLd->workflowStatus = WorkflowStatus::READY_FOR_VALIDATION()->getName();
693
694
        $publicationDate = $published->getPublicationDate();
695
        $offerLd->availableFrom = $publicationDate->format(\DateTime::ATOM);
696
697
        return $document->withBody($offerLd);
698
    }
699
700
    /**
701
     * @param AbstractApproved $approved
702
     * @return JsonDocument
703
     */
704
    protected function applyApproved(AbstractApproved $approved)
705
    {
706
        $document = $this->loadDocumentFromRepository($approved);
707
        $offerLd = $document->getBody();
708
        $offerLd->workflowStatus = WorkflowStatus::APPROVED()->getName();
709
        return $document->withBody($offerLd);
710
    }
711
712
    /**
713
     * @param AbstractRejected $rejected
714
     * @return JsonDocument
715
     */
716 View Code Duplication
    protected function applyRejected(AbstractRejected $rejected)
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...
717
    {
718
        $document = $this->loadDocumentFromRepository($rejected);
719
        $offerLd = $document->getBody();
720
        $offerLd->workflowStatus = WorkflowStatus::REJECTED()->getName();
721
        return $document->withBody($offerLd);
722
    }
723
724
    /**
725
     * @param AbstractFlaggedAsDuplicate $flaggedAsDuplicate
726
     * @return JsonDocument
727
     */
728 View Code Duplication
    protected function applyFlaggedAsDuplicate(
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...
729
        AbstractFlaggedAsDuplicate $flaggedAsDuplicate
730
    ) {
731
        $document = $this->loadDocumentFromRepository($flaggedAsDuplicate);
732
        $offerLd = $document->getBody();
733
        $offerLd->workflowStatus = WorkflowStatus::REJECTED()->getName();
734
        return $document->withBody($offerLd);
735
    }
736
737
    /**
738
     * @param AbstractFlaggedAsInappropriate $flaggedAsInappropriate
739
     * @return JsonDocument
740
     */
741 View Code Duplication
    protected function applyFlaggedAsInappropriate(
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...
742
        AbstractFlaggedAsInappropriate $flaggedAsInappropriate
743
    ) {
744
        $document = $this->loadDocumentFromRepository($flaggedAsInappropriate);
745
        $offerLd = $document->getBody();
746
        $offerLd->workflowStatus = WorkflowStatus::REJECTED()->getName();
747
        return $document->withBody($offerLd);
748
    }
749
750
    /**
751
     * @param AbstractImagesImportedFromUDB2 $imagesImportedFromUDB2
752
     * @return JsonDocument
753
     */
754 View Code Duplication
    protected function applyImagesImportedFromUdb2(AbstractImagesImportedFromUDB2 $imagesImportedFromUDB2)
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...
755
    {
756
        $document = $this->loadDocumentFromRepository($imagesImportedFromUDB2);
757
        $offerLd = $document->getBody();
758
        $this->applyImagesEvent($offerLd, $imagesImportedFromUDB2);
759
        return $document->withBody($offerLd);
760
    }
761
762
    /**
763
     * @param AbstractImagesUpdatedFromUDB2 $imagesUpdatedFromUDB2
764
     * @return JsonDocument
765
     */
766 View Code Duplication
    protected function applyImagesUpdatedFromUdb2(AbstractImagesUpdatedFromUDB2 $imagesUpdatedFromUDB2)
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...
767
    {
768
        $document = $this->loadDocumentFromRepository($imagesUpdatedFromUDB2);
769
        $offerLd = $document->getBody();
770
        $this->applyImagesEvent($offerLd, $imagesUpdatedFromUDB2);
771
        return $document->withBody($offerLd);
772
    }
773
774
    /**
775
     * @param \stdClass $offerLd
776
     * @param AbstractImagesEvent $imagesEvent
777
     */
778
    private function applyImagesEvent(\stdClass $offerLd, AbstractImagesEvent $imagesEvent)
779
    {
780
        $images = $imagesEvent->getImages();
781
        $jsonMediaObjects = array_map(
782
            function (Image $image) {
783
                return $this->mediaObjectSerializer->serialize($image, 'json-ld');
784
            },
785
            $images->toArray()
786
        );
787
        $mainImage = $images->getMain();
788
789
        unset($offerLd->mediaObject, $offerLd->image);
790
791
        if (!empty($jsonMediaObjects)) {
792
            $offerLd->mediaObject = $jsonMediaObjects;
793
        }
794
795
        if (isset($mainImage)) {
796
            $offerLd->image = (string) $mainImage->getSourceLocation();
797
        }
798
    }
799
800
    /**
801
     * @param string $id
802
     * @return JsonDocument
803
     */
804 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...
805
    {
806
        $document = new JsonDocument($id);
807
808
        $offerLd = $document->getBody();
809
        $offerLd->{'@id'} = $this->iriGenerator->iri($id);
810
811
        return $document->withBody($offerLd);
812
    }
813
814
    /**
815
     * @param AbstractEvent $event
816
     * @return JsonDocument
817
     */
818
    protected function loadDocumentFromRepository(AbstractEvent $event)
819
    {
820
        return $this->loadDocumentFromRepositoryByItemId($event->getItemId());
821
    }
822
823
    /**
824
     * @param string $itemId
825
     * @return JsonDocument
826
     */
827
    protected function loadDocumentFromRepositoryByItemId($itemId)
828
    {
829
        $document = $this->repository->get($itemId);
830
831
        if (!$document) {
832
            return $this->newDocument($itemId);
833
        }
834
835
        return $document;
836
    }
837
838
    /**
839
     * @inheritdoc
840
     */
841
    public function organizerJSONLD($organizerId)
842
    {
843
        try {
844
            $organizerJSONLD = $this->organizerService->getEntity(
845
                $organizerId
846
            );
847
848
            return json_decode($organizerJSONLD);
849
        } catch (EntityNotFoundException $e) {
850
            // In case the place can not be found at the moment, just add its ID
851
            return array(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('@id' => $t...ce->iri($organizerId)); (array) is incompatible with the return type declared by the interface CultuurNet\UDB3\Event\Re...erface::organizerJSONLD 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...
852
                '@id' => $this->organizerService->iri($organizerId)
853
            );
854
        }
855
    }
856
}
857