Completed
Pull Request — master (#321)
by
unknown
04:34
created

OfferLDProjector::applyTitleUpdated()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
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\AbstractTitleUpdated;
27
use CultuurNet\UDB3\Offer\Events\AbstractTypicalAgeRangeDeleted;
28
use CultuurNet\UDB3\Offer\Events\AbstractTypicalAgeRangeUpdated;
29
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageAdded;
30
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageRemoved;
31
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesEvent;
32
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesImportedFromUDB2;
33
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesUpdatedFromUDB2;
34
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageUpdated;
35
use CultuurNet\UDB3\Offer\Events\Image\AbstractMainImageSelected;
36
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractApproved;
37
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractFlaggedAsDuplicate;
38
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractFlaggedAsInappropriate;
39
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractPublished;
40
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractRejected;
41
use CultuurNet\UDB3\Offer\WorkflowStatus;
42
use CultuurNet\UDB3\ReadModel\JsonDocument;
43
use CultuurNet\UDB3\ReadModel\JsonDocumentMetaDataEnricherInterface;
44
use CultuurNet\UDB3\ReadModel\MultilingualJsonLDProjectorTrait;
45
use CultuurNet\UDB3\SluggerInterface;
46
use Symfony\Component\Serializer\SerializerInterface;
47
use ValueObjects\Identity\UUID;
48
49
abstract class OfferLDProjector implements OrganizerServiceInterface
50
{
51
    use MultilingualJsonLDProjectorTrait;
52
    use DelegateEventHandlingToSpecificMethodTrait {
53
        DelegateEventHandlingToSpecificMethodTrait::handle as handleUnknownEvents;
54
    }
55
56
    /**
57
     * @var DocumentRepositoryInterface
58
     */
59
    protected $repository;
60
61
    /**
62
     * @var IriGeneratorInterface
63
     */
64
    protected $iriGenerator;
65
66
    /**
67
     * @var EntityServiceInterface
68
     */
69
    protected $organizerService;
70
71
    /**
72
     * @var JsonDocumentMetaDataEnricherInterface
73
     */
74
    protected $jsonDocumentMetaDataEnricher;
75
76
    /**
77
     * @var SerializerInterface
78
     */
79
    protected $mediaObjectSerializer;
80
81
    /**
82
     * @var SluggerInterface
83
     */
84
    protected $slugger;
85
86
    /**
87
     * @param DocumentRepositoryInterface $repository
88
     * @param IriGeneratorInterface $iriGenerator
89
     * @param EntityServiceInterface $organizerService
90
     * @param SerializerInterface $mediaObjectSerializer
91
     * @param JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
92
     */
93
    public function __construct(
94
        DocumentRepositoryInterface $repository,
95
        IriGeneratorInterface $iriGenerator,
96
        EntityServiceInterface $organizerService,
97
        SerializerInterface $mediaObjectSerializer,
98
        JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
99
    ) {
100
        $this->repository = $repository;
101
        $this->iriGenerator = $iriGenerator;
102
        $this->organizerService = $organizerService;
103
        $this->jsonDocumentMetaDataEnricher = $jsonDocumentMetaDataEnricher;
104
        $this->mediaObjectSerializer = $mediaObjectSerializer;
105
106
        $this->slugger = new CulturefeedSlugger();
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function handle(DomainMessage $domainMessage)
113
    {
114
        $event = $domainMessage->getPayload();
115
116
        $eventName = get_class($event);
117
        $eventHandlers = $this->getEventHandlers();
118
119
        if (isset($eventHandlers[$eventName])) {
120
            $handler = $eventHandlers[$eventName];
121
            $jsonDocuments = call_user_func(array($this, $handler), $event, $domainMessage);
122
        } elseif ($methodName = $this->getHandleMethodName($event)) {
123
            $jsonDocuments = $this->{$methodName}($event, $domainMessage);
124
        } else {
125
            return;
126
        }
127
128
        if (!$jsonDocuments) {
129
            return;
130
        }
131
132
        if (!is_array($jsonDocuments)) {
133
            $jsonDocuments = [$jsonDocuments];
134
        }
135
136
        foreach ($jsonDocuments as $jsonDocument) {
137
            $jsonDocument = $this->jsonDocumentMetaDataEnricher->enrich($jsonDocument, $domainMessage->getMetadata());
138
            $this->repository->save($jsonDocument);
139
        }
140
    }
141
142
    /**
143
     * @return string[]
144
     *   An associative array of commands and their handler methods.
145
     */
146 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...
147
    {
148
        $events = [];
149
150
        foreach (get_class_methods($this) as $method) {
151
            $matches = [];
152
153
            if (preg_match('/^apply(.+)$/', $method, $matches)) {
154
                $event = $matches[1];
155
                $classNameMethod = 'get' . $event . 'ClassName';
156
157
                if (method_exists($this, $classNameMethod)) {
158
                    $eventFullClassName = call_user_func(array($this, $classNameMethod));
159
                    $events[$eventFullClassName] = $method;
160
                }
161
            }
162
        }
163
164
        return $events;
165
    }
166
167
    /**
168
     * @return string
169
     */
170
    abstract protected function getLabelAddedClassName();
171
172
    /**
173
     * @return string
174
     */
175
    abstract protected function getLabelRemovedClassName();
176
177
    /**
178
     * @return string
179
     */
180
    abstract protected function getImageAddedClassName();
181
182
    /**
183
     * @return string
184
     */
185
    abstract protected function getImageRemovedClassName();
186
187
    /**
188
     * @return string
189
     */
190
    abstract protected function getImageUpdatedClassName();
191
192
    /**
193
     * @return string
194
     */
195
    abstract protected function getMainImageSelectedClassName();
196
197
    /**
198
     * @return string
199
     */
200
    abstract protected function getTitleTranslatedClassName();
201
202
    /**
203
     * @return string
204
     */
205
    abstract protected function getTitleUpdatedClassName();
206
207
    /**
208
     * @return string
209
     */
210
    abstract protected function getDescriptionTranslatedClassName();
211
212
    /**
213
     * @return string
214
     */
215
    abstract protected function getOrganizerUpdatedClassName();
216
217
    /**
218
     * @return string
219
     */
220
    abstract protected function getOrganizerDeletedClassName();
221
222
    /**
223
     * @return string
224
     */
225
    abstract protected function getBookingInfoUpdatedClassName();
226
227
    /**
228
     * @return string
229
     */
230
    abstract protected function getPriceInfoUpdatedClassName();
231
232
    /**
233
     * @return string
234
     */
235
    abstract protected function getContactPointUpdatedClassName();
236
237
    /**
238
     * @return string
239
     */
240
    abstract protected function getDescriptionUpdatedClassName();
241
242
    /**
243
     * @return string
244
     */
245
    abstract protected function getTypicalAgeRangeUpdatedClassName();
246
247
    /**
248
     * @return string
249
     */
250
    abstract protected function getTypicalAgeRangeDeletedClassName();
251
252
    /**
253
     * @return string
254
     */
255
    abstract protected function getPublishedClassName();
256
257
    /**
258
     * @return string
259
     */
260
    abstract protected function getApprovedClassName();
261
262
    /**
263
     * @return string
264
     */
265
    abstract protected function getRejectedClassName();
266
267
    /**
268
     * @return string
269
     */
270
    abstract protected function getFlaggedAsDuplicateClassName();
271
272
    /**
273
     * @return string
274
     */
275
    abstract protected function getFlaggedAsInappropriateClassName();
276
277
    /**
278
     * @return string
279
     */
280
    abstract protected function getImagesImportedFromUdb2ClassName();
281
282
    /**
283
     * @return string
284
     */
285
    abstract protected function getImagesUpdatedFromUdb2ClassName();
286
287
    /**
288
     * @param AbstractLabelAdded $labelAdded
289
     * @return JsonDocument
290
     */
291
    protected function applyLabelAdded(AbstractLabelAdded $labelAdded)
292
    {
293
        $document = $this->loadDocumentFromRepository($labelAdded);
294
295
        $offerLd = $document->getBody();
296
297
        // Check the visibility of the label to update the right property.
298
        $labelsProperty = $labelAdded->getLabel()->isVisible() ? 'labels' : 'hiddenLabels';
299
300
        $labels = isset($offerLd->{$labelsProperty}) ? $offerLd->{$labelsProperty} : [];
301
        $label = (string) $labelAdded->getLabel();
302
303
        $labels[] = $label;
304
        $offerLd->{$labelsProperty} = array_unique($labels);
305
306
        return $document->withBody($offerLd);
307
    }
308
309
    /**
310
     * @param AbstractLabelRemoved $labelRemoved
311
     * @return JsonDocument
312
     */
313 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...
314
    {
315
        $document = $this->loadDocumentFromRepository($labelRemoved);
316
317
        $offerLd = $document->getBody();
318
319
        // Don't presume that the label visibility is correct when removing.
320
        // So iterate over both the visible and invisible labels.
321
        $labelsProperties = ['labels', 'hiddenLabels'];
322
323
        foreach ($labelsProperties as $labelsProperty) {
324
            if (isset($offerLd->{$labelsProperty}) && is_array($offerLd->{$labelsProperty})) {
325
                $offerLd->{$labelsProperty} = array_filter(
326
                    $offerLd->{$labelsProperty},
327
                    function ($label) use ($labelRemoved) {
328
                        return !$labelRemoved->getLabel()->equals(
329
                            new Label($label)
330
                        );
331
                    }
332
                );
333
                // Ensure array keys start with 0 so json_encode() does encode it
334
                // as an array and not as an object.
335
                if (count($offerLd->{$labelsProperty}) > 0) {
336
                    $offerLd->{$labelsProperty} = array_values($offerLd->{$labelsProperty});
337
                } else {
338
                    unset($offerLd->{$labelsProperty});
339
                }
340
            }
341
        }
342
343
        return $document->withBody($offerLd);
344
    }
345
346
    /**
347
     * Apply the imageAdded event to the item repository.
348
     *
349
     * @param AbstractImageAdded $imageAdded
350
     * @return JsonDocument
351
     */
352
    protected function applyImageAdded(AbstractImageAdded $imageAdded)
353
    {
354
        $document = $this->loadDocumentFromRepository($imageAdded);
355
356
        $offerLd = $document->getBody();
357
        $offerLd->mediaObject = isset($offerLd->mediaObject) ? $offerLd->mediaObject : [];
358
359
        $imageData = $this->mediaObjectSerializer
360
            ->serialize($imageAdded->getImage(), 'json-ld');
361
        $offerLd->mediaObject[] = $imageData;
362
363
        if (count($offerLd->mediaObject) === 1) {
364
            $offerLd->image = $imageData['contentUrl'];
365
        }
366
367
        return $document->withBody($offerLd);
368
    }
369
370
    /**
371
     * Apply the ImageUpdated event to the item repository.
372
     *
373
     * @param AbstractImageUpdated $imageUpdated
374
     * @return JsonDocument
375
     * @throws \Exception
376
     */
377
    protected function applyImageUpdated(AbstractImageUpdated $imageUpdated)
378
    {
379
        $document = $this->loadDocumentFromRepository($imageUpdated);
380
381
        $offerLd = $document->getBody();
382
383
        if (!isset($offerLd->mediaObject)) {
384
            throw new \Exception('The image to update could not be found.');
385
        }
386
387
        $updatedMediaObjects = [];
388
389
        foreach ($offerLd->mediaObject as $mediaObject) {
390
            $mediaObjectMatches = (
391
                strpos(
392
                    $mediaObject->{'@id'},
393
                    (string)$imageUpdated->getMediaObjectId()
394
                ) > 0
395
            );
396
397
            if ($mediaObjectMatches) {
398
                $mediaObject->description = (string)$imageUpdated->getDescription();
399
                $mediaObject->copyrightHolder = (string)$imageUpdated->getCopyrightHolder();
400
401
                $updatedMediaObjects[] = $mediaObject;
402
            }
403
        };
404
405
        if (empty($updatedMediaObjects)) {
406
            throw new \Exception('The image to update could not be found.');
407
        }
408
409
        return $document->withBody($offerLd);
410
    }
411
412
    /**
413
     * @param AbstractImageRemoved $imageRemoved
414
     * @return JsonDocument
415
     */
416
    protected function applyImageRemoved(AbstractImageRemoved $imageRemoved)
417
    {
418
        $document = $this->loadDocumentFromRepository($imageRemoved);
419
420
        $offerLd = $document->getBody();
421
422
        // Nothing to remove if there are no media objects!
423
        if (!isset($offerLd->mediaObject)) {
424
            return;
425
        }
426
427
        $imageId = (string) $imageRemoved->getImage()->getMediaObjectId();
428
429
        /**
430
         * Matches any object that is not the removed image.
431
         *
432
         * @param Object $mediaObject
433
         *  An existing projection of a media object.
434
         *
435
         * @return bool
436
         *  Returns true when the media object does not match the image to remove.
437
         */
438
        $shouldNotBeRemoved = function ($mediaObject) use ($imageId) {
439
            $containsId = !!strpos($mediaObject->{'@id'}, $imageId);
440
            return !$containsId;
441
        };
442
443
        // Remove any media objects that match the image.
444
        $filteredMediaObjects = array_filter(
445
            $offerLd->mediaObject,
446
            $shouldNotBeRemoved
447
        );
448
449
        // Unset the main image if it matches the removed image
450
        if (isset($offerLd->image) && strpos($offerLd->{'image'}, $imageId)) {
451
            unset($offerLd->{"image"});
452
        }
453
454
        if (!isset($offerLd->image) && count($filteredMediaObjects) > 0) {
455
            $offerLd->image = array_values($filteredMediaObjects)[0]->contentUrl;
456
        }
457
458
        // If no media objects are left remove the attribute.
459
        if (empty($filteredMediaObjects)) {
460
            unset($offerLd->{"mediaObject"});
461
        } else {
462
            $offerLd->mediaObject = array_values($filteredMediaObjects);
463
        }
464
465
        return $document->withBody($offerLd);
466
    }
467
468
    /**
469
     * @param AbstractMainImageSelected $mainImageSelected
470
     * @return JsonDocument
471
     */
472
    protected function applyMainImageSelected(AbstractMainImageSelected $mainImageSelected)
473
    {
474
        $document = $this->loadDocumentFromRepository($mainImageSelected);
475
        $offerLd = $document->getBody();
476
        $imageId = $mainImageSelected->getImage()->getMediaObjectId();
477
        $mediaObjectMatcher = function ($matchingMediaObject, $currentMediaObject) use ($imageId) {
478
            if (!$matchingMediaObject && $this->mediaObjectMatchesId($currentMediaObject, $imageId)) {
479
                $matchingMediaObject = $currentMediaObject;
480
            }
481
482
            return $matchingMediaObject;
483
        };
484
        $mediaObject = array_reduce(
485
            $offerLd->mediaObject,
486
            $mediaObjectMatcher
487
        );
488
489
        $offerLd->image = $mediaObject->contentUrl;
490
491
        return $document->withBody($offerLd);
492
    }
493
494
    /**
495
     * @param Object $mediaObject
496
     * @param UUID $mediaObjectId
497
     *
498
     * @return bool
499
     */
500
    protected function mediaObjectMatchesId($mediaObject, UUID $mediaObjectId)
501
    {
502
        return strpos($mediaObject->{'@id'}, (string) $mediaObjectId) > 0;
503
    }
504
505
    /**
506
     * @param AbstractTitleTranslated $titleTranslated
507
     * @return JsonDocument
508
     */
509
    protected function applyTitleTranslated(AbstractTitleTranslated $titleTranslated)
510
    {
511
        $document = $this->loadDocumentFromRepository($titleTranslated);
512
513
        $offerLd = $document->getBody();
514
        $offerLd->name->{$titleTranslated->getLanguage()->getCode(
515
        )} = $titleTranslated->getTitle()->toNative();
516
517
        return $document->withBody($offerLd);
518
    }
519
520
    /**
521
     * @param AbstractTitleUpdated $titleUpdated
522
     * @return JsonDocument
523
     */
524
    protected function applyTitleUpdated(AbstractTitleUpdated $titleUpdated)
525
    {
526
        $document = $this->loadDocumentFromRepository($titleUpdated);
527
        $offerLd = $document->getBody();
528
        $mainLanguage = isset($offerLd->mainLanguage) ? $offerLd->mainLanguage : 'nl';
529
530
        $offerLd->name->{$mainLanguage} = $titleUpdated->getTitle()->toNative();
531
532
        return $document->withBody($offerLd);
533
    }
534
535
    /**
536
     * @param AbstractDescriptionTranslated $descriptionTranslated
537
     * @return JsonDocument
538
     */
539
    protected function applyDescriptionTranslated(
540
        AbstractDescriptionTranslated $descriptionTranslated
541
    ) {
542
        $document = $this->loadDocumentFromRepository($descriptionTranslated);
543
544
        $offerLd = $document->getBody();
545
        $languageCode = $descriptionTranslated->getLanguage()->getCode();
546
        $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...
547
        if (empty($offerLd->description)) {
548
            $offerLd->description = new \stdClass();
549
        }
550
        $offerLd->description->{$languageCode} = $description;
551
552
        return $document->withBody($offerLd);
553
    }
554
555
    /**
556
     * Apply the organizer updated event to the offer repository.
557
     * @param AbstractOrganizerUpdated $organizerUpdated
558
     * @return JsonDocument
559
     */
560
    protected function applyOrganizerUpdated(AbstractOrganizerUpdated $organizerUpdated)
561
    {
562
        $document = $this->loadDocumentFromRepository($organizerUpdated);
563
564
        $offerLd = $document->getBody();
565
566
        $offerLd->organizer = array(
567
                '@type' => 'Organizer',
568
            ) + (array)$this->organizerJSONLD($organizerUpdated->getOrganizerId());
569
570
        return $document->withBody($offerLd);
571
    }
572
573
    /**
574
     * Apply the organizer delete event to the offer repository.
575
     * @param AbstractOrganizerDeleted $organizerDeleted
576
     * @return JsonDocument
577
     */
578
    protected function applyOrganizerDeleted(AbstractOrganizerDeleted $organizerDeleted)
579
    {
580
        $document = $this->loadDocumentFromRepository($organizerDeleted);
581
582
        $offerLd = $document->getBody();
583
584
        unset($offerLd->organizer);
585
586
        return $document->withBody($offerLd);
587
    }
588
589
    /**
590
     * Apply the booking info updated event to the offer repository.
591
     * @param AbstractBookingInfoUpdated $bookingInfoUpdated
592
     * @return JsonDocument
593
     */
594
    protected function applyBookingInfoUpdated(AbstractBookingInfoUpdated $bookingInfoUpdated)
595
    {
596
        $document = $this->loadDocumentFromRepository($bookingInfoUpdated);
597
598
        $offerLd = $document->getBody();
599
        $offerLd->bookingInfo = $bookingInfoUpdated->getBookingInfo()->toJsonLd();
600
601
        return $document->withBody($offerLd);
602
    }
603
604
    /**
605
     * @param AbstractPriceInfoUpdated $priceInfoUpdated
606
     * @return JsonDocument
607
     */
608
    protected function applyPriceInfoUpdated(AbstractPriceInfoUpdated $priceInfoUpdated)
609
    {
610
        $document = $this->loadDocumentFromRepository($priceInfoUpdated);
611
612
        $offerLd = $document->getBody();
613
        $offerLd->priceInfo = [];
614
615
        $basePrice = $priceInfoUpdated->getPriceInfo()->getBasePrice();
616
617
        $offerLd->priceInfo[] = [
618
            'category' => 'base',
619
            'name' => 'Basistarief',
620
            'price' => $basePrice->getPrice()->toFloat(),
621
            'priceCurrency' => $basePrice->getCurrency()->getCode()->toNative(),
622
        ];
623
624
        foreach ($priceInfoUpdated->getPriceInfo()->getTariffs() as $tariff) {
625
            $offerLd->priceInfo[] = [
626
                'category' => 'tariff',
627
                'name' => $tariff->getName()->toNative(),
628
                'price' => $tariff->getPrice()->toFloat(),
629
                'priceCurrency' => $tariff->getCurrency()->getCode()->toNative(),
630
            ];
631
        }
632
633
        return $document->withBody($offerLd);
634
    }
635
636
    /**
637
     * Apply the contact point updated event to the offer repository.
638
     * @param AbstractContactPointUpdated $contactPointUpdated
639
     * @return JsonDocument
640
     */
641
    protected function applyContactPointUpdated(AbstractContactPointUpdated $contactPointUpdated)
642
    {
643
        $document = $this->loadDocumentFromRepository($contactPointUpdated);
644
645
        $offerLd = $document->getBody();
646
        $offerLd->contactPoint = $contactPointUpdated->getContactPoint()->toJsonLd();
647
648
        return $document->withBody($offerLd);
649
    }
650
651
    /**
652
     * Apply the description updated event to the offer repository.
653
     * @param AbstractDescriptionUpdated $descriptionUpdated
654
     * @return JsonDocument
655
     */
656
    protected function applyDescriptionUpdated(
657
        AbstractDescriptionUpdated $descriptionUpdated
658
    ) {
659
        $document = $this->loadDocumentFromRepository($descriptionUpdated);
660
661
        $offerLd = $document->getBody();
662
        if (empty($offerLd->description)) {
663
            $offerLd->description = new \stdClass();
664
        }
665
        $offerLd->description->{'nl'} = $descriptionUpdated->getDescription();
666
667
        return $document->withBody($offerLd);
668
    }
669
670
    /**
671
     * Apply the typical age range updated event to the offer repository.
672
     * @param AbstractTypicalAgeRangeUpdated $typicalAgeRangeUpdated
673
     * @return JsonDocument
674
     */
675
    protected function applyTypicalAgeRangeUpdated(
676
        AbstractTypicalAgeRangeUpdated $typicalAgeRangeUpdated
677
    ) {
678
        $document = $this->loadDocumentFromRepository($typicalAgeRangeUpdated);
679
680
        $offerLd = $document->getBody();
681
        $offerLd->typicalAgeRange = (string) $typicalAgeRangeUpdated->getTypicalAgeRange();
682
683
        return $document->withBody($offerLd);
684
    }
685
686
    /**
687
     * Apply the typical age range deleted event to the offer repository.
688
     * @param AbstractTypicalAgeRangeDeleted $typicalAgeRangeDeleted
689
     * @return JsonDocument
690
     */
691
    protected function applyTypicalAgeRangeDeleted(
692
        AbstractTypicalAgeRangeDeleted $typicalAgeRangeDeleted
693
    ) {
694
        $document = $this->loadDocumentFromRepository($typicalAgeRangeDeleted);
695
696
        $offerLd = $document->getBody();
697
698
        unset($offerLd->typicalAgeRange);
699
700
        return $document->withBody($offerLd);
701
    }
702
703
    /**
704
     * @param AbstractPublished $published
705
     * @return JsonDocument
706
     */
707
    protected function applyPublished(AbstractPublished $published)
708
    {
709
        $document = $this->loadDocumentFromRepository($published);
710
711
        $offerLd = $document->getBody();
712
713
        $offerLd->workflowStatus = WorkflowStatus::READY_FOR_VALIDATION()->getName();
714
715
        $publicationDate = $published->getPublicationDate();
716
        $offerLd->availableFrom = $publicationDate->format(\DateTime::ATOM);
717
718
        return $document->withBody($offerLd);
719
    }
720
721
    /**
722
     * @param AbstractApproved $approved
723
     * @return JsonDocument
724
     */
725
    protected function applyApproved(AbstractApproved $approved)
726
    {
727
        $document = $this->loadDocumentFromRepository($approved);
728
        $offerLd = $document->getBody();
729
        $offerLd->workflowStatus = WorkflowStatus::APPROVED()->getName();
730
        return $document->withBody($offerLd);
731
    }
732
733
    /**
734
     * @param AbstractRejected $rejected
735
     * @return JsonDocument
736
     */
737 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...
738
    {
739
        $document = $this->loadDocumentFromRepository($rejected);
740
        $offerLd = $document->getBody();
741
        $offerLd->workflowStatus = WorkflowStatus::REJECTED()->getName();
742
        return $document->withBody($offerLd);
743
    }
744
745
    /**
746
     * @param AbstractFlaggedAsDuplicate $flaggedAsDuplicate
747
     * @return JsonDocument
748
     */
749 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...
750
        AbstractFlaggedAsDuplicate $flaggedAsDuplicate
751
    ) {
752
        $document = $this->loadDocumentFromRepository($flaggedAsDuplicate);
753
        $offerLd = $document->getBody();
754
        $offerLd->workflowStatus = WorkflowStatus::REJECTED()->getName();
755
        return $document->withBody($offerLd);
756
    }
757
758
    /**
759
     * @param AbstractFlaggedAsInappropriate $flaggedAsInappropriate
760
     * @return JsonDocument
761
     */
762 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...
763
        AbstractFlaggedAsInappropriate $flaggedAsInappropriate
764
    ) {
765
        $document = $this->loadDocumentFromRepository($flaggedAsInappropriate);
766
        $offerLd = $document->getBody();
767
        $offerLd->workflowStatus = WorkflowStatus::REJECTED()->getName();
768
        return $document->withBody($offerLd);
769
    }
770
771
    /**
772
     * @param AbstractImagesImportedFromUDB2 $imagesImportedFromUDB2
773
     * @return JsonDocument
774
     */
775 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...
776
    {
777
        $document = $this->loadDocumentFromRepository($imagesImportedFromUDB2);
778
        $offerLd = $document->getBody();
779
        $this->applyUdb2ImagesEvent($offerLd, $imagesImportedFromUDB2);
780
        return $document->withBody($offerLd);
781
    }
782
783
    /**
784
     * @param AbstractImagesUpdatedFromUDB2 $imagesUpdatedFromUDB2
785
     * @return JsonDocument
786
     */
787 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...
788
    {
789
        $document = $this->loadDocumentFromRepository($imagesUpdatedFromUDB2);
790
        $offerLd = $document->getBody();
791
        $this->applyUdb2ImagesEvent($offerLd, $imagesUpdatedFromUDB2);
792
        return $document->withBody($offerLd);
793
    }
794
795
    /**
796
     * This indirect apply method can be called internally to deal with images coming from UDB2.
797
     * Imports from UDB2 only contain the native Dutch content.
798
     * @see https://github.com/cultuurnet/udb3-udb2-bridge/blob/db0a7ab2444f55bb3faae3d59b82b39aaeba253b/test/Media/ImageCollectionFactoryTest.php#L79-L103
799
     * Because of this we have to make sure translated images are left in place.
800
     *
801
     * @param \stdClass $offerLd
802
     * @param AbstractImagesEvent $imagesEvent
803
     */
804
    private function applyUdb2ImagesEvent(\stdClass $offerLd, AbstractImagesEvent $imagesEvent)
805
    {
806
        $images = $imagesEvent->getImages();
807
        $currentMediaObjects = isset($offerLd->mediaObject) ? $offerLd->mediaObject : [];
808
        $dutchMediaObjects = array_map(
809
            function (Image $image) {
810
                return $this->mediaObjectSerializer->serialize($image, 'json-ld');
811
            },
812
            $images->toArray()
813
        );
814
        $translatedMediaObjects = array_filter(
815
            $currentMediaObjects,
816
            function ($image) {
817
                return $image->inLanguage !== 'nl';
818
            }
819
        );
820
        $mainImage = $images->getMain();
821
822
        unset($offerLd->mediaObject, $offerLd->image);
823
824
        if (!empty($dutchMediaObjects) || !empty($translatedMediaObjects)) {
825
            $offerLd->mediaObject = array_merge($dutchMediaObjects, $translatedMediaObjects);
826
        }
827
828
        if (isset($mainImage)) {
829
            $offerLd->image = (string) $mainImage->getSourceLocation();
830
        }
831
    }
832
833
    /**
834
     * @param string $id
835
     * @return JsonDocument
836
     */
837 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...
838
    {
839
        $document = new JsonDocument($id);
840
841
        $offerLd = $document->getBody();
842
        $offerLd->{'@id'} = $this->iriGenerator->iri($id);
843
844
        return $document->withBody($offerLd);
845
    }
846
847
    /**
848
     * @param AbstractEvent $event
849
     * @return JsonDocument
850
     */
851
    protected function loadDocumentFromRepository(AbstractEvent $event)
852
    {
853
        return $this->loadDocumentFromRepositoryByItemId($event->getItemId());
854
    }
855
856
    /**
857
     * @param string $itemId
858
     * @return JsonDocument
859
     */
860
    protected function loadDocumentFromRepositoryByItemId($itemId)
861
    {
862
        $document = $this->repository->get($itemId);
863
864
        if (!$document) {
865
            return $this->newDocument($itemId);
866
        }
867
868
        return $document;
869
    }
870
871
    /**
872
     * @inheritdoc
873
     */
874
    public function organizerJSONLD($organizerId)
875
    {
876
        try {
877
            $organizerJSONLD = $this->organizerService->getEntity(
878
                $organizerId
879
            );
880
881
            return json_decode($organizerJSONLD);
882
        } catch (EntityNotFoundException $e) {
883
            // In case the place can not be found at the moment, just add its ID
884
            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...
885
                '@id' => $this->organizerService->iri($organizerId),
886
            );
887
        }
888
    }
889
}
890