Completed
Pull Request — master (#350)
by
unknown
05:43
created

Offer::createImageUpdatedEvent()

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
nc 1
1
<?php
2
3
namespace CultuurNet\UDB3\Offer;
4
5
use Broadway\EventSourcing\EventSourcedAggregateRoot;
6
use CultureFeed_Cdb_Item_Base;
7
use CultuurNet\Geocoding\Coordinate\Coordinates;
8
use CultuurNet\UDB3\BookingInfo;
9
use CultuurNet\UDB3\Calendar;
10
use CultuurNet\UDB3\ContactPoint;
11
use CultuurNet\UDB3\Description;
12
use CultuurNet\UDB3\Event\EventType;
13
use CultuurNet\UDB3\Facility;
14
use CultuurNet\UDB3\Label;
15
use CultuurNet\UDB3\LabelAwareAggregateRoot;
16
use CultuurNet\UDB3\LabelCollection;
17
use CultuurNet\UDB3\Media\Image;
18
use CultuurNet\UDB3\Media\ImageCollection;
19
use CultuurNet\UDB3\Media\Properties\CopyrightHolder;
20
use \CultuurNet\UDB3\Media\Properties\Description as ImageDescription;
21
use CultuurNet\UDB3\Offer\Commands\Image\AbstractUpdateImage;
22
use CultuurNet\UDB3\Language;
23
use CultuurNet\UDB3\Offer\Events\AbstractBookingInfoUpdated;
24
use CultuurNet\UDB3\Offer\Events\AbstractCalendarUpdated;
25
use CultuurNet\UDB3\Offer\Events\AbstractContactPointUpdated;
26
use CultuurNet\UDB3\Offer\Events\AbstractFacilitiesUpdated;
27
use CultuurNet\UDB3\Offer\Events\AbstractGeoCoordinatesUpdated;
28
use CultuurNet\UDB3\Offer\Events\AbstractThemeUpdated;
29
use CultuurNet\UDB3\Offer\Events\AbstractTitleTranslated;
30
use CultuurNet\UDB3\Offer\Events\AbstractTitleUpdated;
31
use CultuurNet\UDB3\Offer\Events\AbstractDescriptionTranslated;
32
use CultuurNet\UDB3\Offer\Events\AbstractDescriptionUpdated;
33
use CultuurNet\UDB3\Offer\Events\AbstractLabelAdded;
34
use CultuurNet\UDB3\Offer\Events\AbstractLabelRemoved;
35
use CultuurNet\UDB3\Offer\Events\AbstractOfferDeleted;
36
use CultuurNet\UDB3\Offer\Events\AbstractOrganizerDeleted;
37
use CultuurNet\UDB3\Offer\Events\AbstractOrganizerUpdated;
38
use CultuurNet\UDB3\Offer\Events\AbstractPriceInfoUpdated;
39
use CultuurNet\UDB3\Offer\Events\AbstractTypeUpdated;
40
use CultuurNet\UDB3\Offer\Events\AbstractTypicalAgeRangeDeleted;
41
use CultuurNet\UDB3\Offer\Events\AbstractTypicalAgeRangeUpdated;
42
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageAdded;
43
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageRemoved;
44
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesEvent;
45
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesImportedFromUDB2;
46
use CultuurNet\UDB3\Offer\Events\Image\AbstractImagesUpdatedFromUDB2;
47
use CultuurNet\UDB3\Offer\Events\Image\AbstractImageUpdated;
48
use CultuurNet\UDB3\Offer\Events\Image\AbstractMainImageSelected;
49
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractApproved;
50
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractFlaggedAsDuplicate;
51
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractFlaggedAsInappropriate;
52
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractPublished;
53
use CultuurNet\UDB3\Offer\Events\Moderation\AbstractRejected;
54
use CultuurNet\UDB3\PriceInfo\PriceInfo;
55
use CultuurNet\UDB3\Theme;
56
use CultuurNet\UDB3\Title;
57
use Exception;
58
use ValueObjects\Identity\UUID;
59
use ValueObjects\StringLiteral\StringLiteral;
60
61
abstract class Offer extends EventSourcedAggregateRoot implements LabelAwareAggregateRoot
62
{
63
    const DUPLICATE_REASON = 'duplicate';
64
    const INAPPROPRIATE_REASON = 'inappropriate';
65
66
    /**
67
     * @var LabelCollection
68
     */
69
    protected $labels;
70
71
    /**
72
     * @var ImageCollection
73
     */
74
    protected $images;
75
76
    /**
77
     * @var string
78
     *
79
     * Organizer ids can come from UDB2 which does not strictly use UUIDs.
80
     */
81
    protected $organizerId;
82
83
    /**
84
     * @var WorkflowStatus
85
     */
86
    protected $workflowStatus;
87
88
    /**
89
     * @var StringLiteral|null
90
     */
91
    protected $rejectedReason;
92
93
    /**
94
     * @var PriceInfo
95
     */
96
    protected $priceInfo;
97
98
    /**
99
     * @var StringLiteral[]
100
     */
101
    protected $titles;
102
103
    /**
104
     * @var Description[]
105
     */
106
    protected $descriptions;
107
108
    /**
109
     * @var Language
110
     */
111
    protected $mainLanguage;
112
113
    /**
114
     * @var string;
115
     */
116
    protected $typeId;
117
118
    /**
119
     * @var string;
120
     */
121
    protected $themeId;
122
123
    /**
124
     * @var array
125
     */
126
    protected $facilities;
127
128
    /**
129
     * @var ContactPoint
130
     */
131
    protected $contactPoint;
132
133
    /**
134
     * @var Calendar
135
     */
136
    protected $calendar;
137
138
    /**
139
     * @var AgeRange
140
     */
141
    protected $typicalAgeRange;
142
143
    /**
144
     * @var BookingInfo
145
     */
146
    protected $bookingInfo;
147
148
    /**
149
     * Offer constructor.
150
     */
151
    public function __construct()
152
    {
153
        $this->titles = [];
154
        $this->descriptions = [];
155
        $this->labels = new LabelCollection();
156
        $this->images = new ImageCollection();
157
        $this->facilities = [];
158
        $this->contactPoint = null;
159
        $this->calendar = null;
160
        $this->typicalAgeRange = null;
161
        $this->bookingInfo = null;
162
    }
163
164
    /**
165
     * @param EventType $type
166
     */
167
    public function updateType(EventType $type)
168
    {
169
        if (!$this->typeId || $this->typeId !== $type->getId()) {
170
            $this->apply($this->createTypeUpdatedEvent($type));
171
        }
172
    }
173
174
    /**
175
     * @param Theme $theme
176
     */
177
    public function updateTheme(Theme $theme)
178
    {
179
        if (!$this->themeId || $this->themeId !== $theme->getId()) {
180
            $this->apply($this->createThemeUpdatedEvent($theme));
181
        }
182
    }
183
184
    /**
185
     * @param array $facilities
186
     */
187
    public function updateFacilities(array $facilities)
188
    {
189
        if (empty($this->facilities) || !$this->sameFacilities($this->facilities, $facilities)) {
190
            $this->apply($this->createFacilitiesUpdatedEvent($facilities));
191
        }
192
    }
193
194
    /**
195
     * @param AbstractFacilitiesUpdated $facilitiesUpdated
196
     */
197
    protected function applyFacilitiesUpdated(AbstractFacilitiesUpdated $facilitiesUpdated)
198
    {
199
        $this->facilities = $facilitiesUpdated->getFacilities();
200
    }
201
202
    /**
203
     * @param array $facilities1
204
     * @param array $facilities2
205
     * @return bool
206
     */
207
    private function sameFacilities($facilities1, $facilities2)
208
    {
209
        if (count($facilities1) !== count($facilities2)) {
210
            return false;
211
        }
212
213
        $sameFacilities = array_uintersect(
214
            $facilities1,
215
            $facilities2,
216
            function (Facility $facility1, Facility $facility2) {
217
                return strcmp($facility1->getId(), $facility2->getId());
218
            }
219
        );
220
221
        return count($sameFacilities) === count($facilities2);
222
    }
223
224
    /**
225
     * Get the id of the main image if one is selected for this offer.
226
     *
227
     * @return UUID|null
228
     */
229
    protected function getMainImageId()
230
    {
231
        $mainImage = $this->images->getMain();
232
        return isset($mainImage) ? $mainImage->getMediaObjectId() : null;
233
    }
234
235
    /**
236
     * @inheritdoc
237
     */
238
    public function addLabel(Label $label)
239
    {
240
        if (!$this->labels->contains($label)) {
241
            $this->apply(
242
                $this->createLabelAddedEvent($label)
243
            );
244
        }
245
    }
246
247
    /**
248
     * @inheritdoc
249
     */
250
    public function removeLabel(Label $label)
251
    {
252
        if ($this->labels->contains($label)) {
253
            $this->apply(
254
                $this->createLabelRemovedEvent($label)
255
            );
256
        }
257
    }
258
259
    /**
260
     * @param Language $language
261
     * @param Title $title
262
     */
263
    public function updateTitle(Language $language, Title $title)
264
    {
265
        if ($this->isTitleChanged($title, $language)) {
266
            if ($language->getCode() !== $this->mainLanguage->getCode()) {
267
                $event = $this->createTitleTranslatedEvent($language, $title);
268
            } else {
269
                $event = $this->createTitleUpdatedEvent($title);
270
            }
271
272
            $this->apply($event);
273
        }
274
    }
275
276
    /**
277
     * @param Description $description
278
     * @param Language $language
279
     */
280
    public function updateDescription(Description $description, Language $language)
281
    {
282
        if ($this->isDescriptionChanged($description, $language)) {
283
            if ($language->getCode() !== $this->mainLanguage->getCode()) {
284
                $event = $this->createDescriptionTranslatedEvent($language, $description);
285
            } else {
286
                $event = $this->createDescriptionUpdatedEvent((string) $description);
287
            }
288
289
            $this->apply($event);
290
        }
291
    }
292
293
    /**
294
     * @param Calendar $calendar
295
     */
296
    public function updateCalendar(Calendar $calendar)
297
    {
298
        if (is_null($this->calendar) || !$this->calendar->sameAs($calendar)) {
299
            $this->apply(
300
                $this->createCalendarUpdatedEvent($calendar)
301
            );
302
        }
303
    }
304
305
    /**
306
     * @param AbstractCalendarUpdated $calendarUpdated
307
     */
308
    protected function applyCalendarUpdated(AbstractCalendarUpdated $calendarUpdated)
309
    {
310
        $this->calendar = $calendarUpdated->getCalendar();
311
    }
312
313
    /**
314
     * @param string $typicalAgeRange
315
     */
316
    public function updateTypicalAgeRange($typicalAgeRange)
317
    {
318
        $typicalAgeRangeUpdatedEvent = $this->createTypicalAgeRangeUpdatedEvent($typicalAgeRange);
319
320
        if (empty($this->typicalAgeRange) || !$this->typicalAgeRange->sameAs($typicalAgeRangeUpdatedEvent->getTypicalAgeRange())) {
321
            $this->apply($typicalAgeRangeUpdatedEvent);
322
        }
323
    }
324
325
    /**
326
     * @param AbstractTypicalAgeRangeUpdated $typicalAgeRangeUpdated
327
     */
328
    protected function applyTypicalAgeRangeUpdated(AbstractTypicalAgeRangeUpdated $typicalAgeRangeUpdated)
329
    {
330
        $this->typicalAgeRange = $typicalAgeRangeUpdated->getTypicalAgeRange();
331
    }
332
333
    public function deleteTypicalAgeRange()
334
    {
335
        if (!is_null($this->typicalAgeRange)) {
336
            $this->apply(
337
                $this->createTypicalAgeRangeDeletedEvent()
338
            );
339
        }
340
    }
341
342
    /**
343
     * @param AbstractTypicalAgeRangeDeleted $typicalAgeRangeDeleted
344
     */
345
    public function applyTypicalAgeRangeDeleted(AbstractTypicalAgeRangeDeleted $typicalAgeRangeDeleted)
0 ignored issues
show
Unused Code introduced by
The parameter $typicalAgeRangeDeleted is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
346
    {
347
        $this->typicalAgeRange = null;
348
    }
349
350
    /**
351
     * @param string $organizerId
352
     */
353
    public function updateOrganizer($organizerId)
354
    {
355
        if ($this->organizerId !== $organizerId) {
356
            $this->apply(
357
                $this->createOrganizerUpdatedEvent($organizerId)
358
            );
359
        }
360
    }
361
362
    /**
363
     * Delete the given organizer.
364
     *
365
     * @param string $organizerId
366
     */
367
    public function deleteOrganizer($organizerId)
368
    {
369
        if ($this->organizerId === $organizerId) {
370
            $this->apply(
371
                $this->createOrganizerDeletedEvent($organizerId)
372
            );
373
        }
374
    }
375
376
    /**
377
     * Delete the current organizer regardless of the id.
378
     */
379
    public function deleteCurrentOrganizer()
380
    {
381
        if (!is_null($this->organizerId)) {
382
            $this->apply(
383
                $this->createOrganizerDeletedEvent($this->organizerId)
384
            );
385
        }
386
    }
387
388
    /**
389
     * Updated the contact info.
390
     * @param ContactPoint $contactPoint
391
     */
392
    public function updateContactPoint(ContactPoint $contactPoint)
393
    {
394
        if (is_null($this->contactPoint) || !$this->contactPoint->sameAs($contactPoint)) {
395
            $this->apply(
396
                $this->createContactPointUpdatedEvent($contactPoint)
397
            );
398
        }
399
    }
400
401
    /**
402
     * @param AbstractContactPointUpdated $contactPointUpdated
403
     */
404
    protected function applyContactPointUpdated(AbstractContactPointUpdated $contactPointUpdated)
405
    {
406
        $this->contactPoint = $contactPointUpdated->getContactPoint();
407
    }
408
409
    /**
410
     * @param Coordinates $coordinates
411
     */
412
    public function updateGeoCoordinates(Coordinates $coordinates)
413
    {
414
        // Note: DON'T compare to previous coordinates and apply only on
415
        // changes. Various projectors expect GeoCoordinatesUpdated after
416
        // MajorInfoUpdated and PlaceUpdatedFromUDB2, even if the address
417
        // and thus the coordinates haven't actually changed.
418
        $this->apply(
419
            $this->createGeoCoordinatesUpdatedEvent($coordinates)
420
        );
421
    }
422
423
    /**
424
     * Updated the booking info.
425
     *
426
     * @param BookingInfo $bookingInfo
427
     */
428
    public function updateBookingInfo(BookingInfo $bookingInfo)
429
    {
430
        if (is_null($this->bookingInfo) || !$this->bookingInfo->sameAs($bookingInfo)) {
431
            $this->apply(
432
                $this->createBookingInfoUpdatedEvent($bookingInfo)
433
            );
434
        }
435
    }
436
437
    /**
438
     * @param AbstractBookingInfoUpdated $bookingInfoUpdated
439
     */
440
    public function applyBookingInfoUpdated(AbstractBookingInfoUpdated $bookingInfoUpdated)
441
    {
442
        $this->bookingInfo = $bookingInfoUpdated->getBookingInfo();
443
    }
444
445
    /**
446
     * @param PriceInfo $priceInfo
447
     */
448
    public function updatePriceInfo(PriceInfo $priceInfo)
449
    {
450
        if (is_null($this->priceInfo) || $priceInfo->serialize() !== $this->priceInfo->serialize()) {
451
            $this->apply(
452
                $this->createPriceInfoUpdatedEvent($priceInfo)
453
            );
454
        }
455
    }
456
457
    /**
458
     * @param AbstractPriceInfoUpdated $priceInfoUpdated
459
     */
460
    protected function applyPriceInfoUpdated(AbstractPriceInfoUpdated $priceInfoUpdated)
461
    {
462
        $this->priceInfo = $priceInfoUpdated->getPriceInfo();
463
    }
464
465
    /**
466
     * @param AbstractLabelAdded $labelAdded
467
     */
468
    protected function applyLabelAdded(AbstractLabelAdded $labelAdded)
469
    {
470
        $this->labels = $this->labels->with($labelAdded->getLabel());
471
    }
472
473
    /**
474
     * @param AbstractLabelRemoved $labelRemoved
475
     */
476
    protected function applyLabelRemoved(AbstractLabelRemoved $labelRemoved)
477
    {
478
        $this->labels = $this->labels->without($labelRemoved->getLabel());
479
    }
480
481
    /**
482
     * @param AbstractThemeUpdated $themeUpdated
483
     */
484
    protected function applyThemeUpdated(AbstractThemeUpdated $themeUpdated)
485
    {
486
        $this->themeId = $themeUpdated->getTheme()->getId();
487
    }
488
489
    /**
490
     * @param AbstractTypeUpdated $themeUpdated
491
     */
492
    protected function applyTypeUpdated(AbstractTypeUpdated $themeUpdated)
493
    {
494
        $this->typeId = $themeUpdated->getType()->getId();
495
    }
496
497
    protected function applyDescriptionUpdated(AbstractDescriptionUpdated $descriptionUpdated)
498
    {
499
        $mainLanguageCode = $this->mainLanguage->getCode();
500
        $this->descriptions[$mainLanguageCode] = new Description($descriptionUpdated->getDescription());
501
    }
502
503
    protected function applyDescriptionTranslated(AbstractDescriptionTranslated $descriptionTranslated)
504
    {
505
        $languageCode = $descriptionTranslated->getLanguage()->getCode();
506
        $this->descriptions[$languageCode] = $descriptionTranslated->getDescription();
507
    }
508
509
    /**
510
     * Add a new image.
511
     *
512
     * @param Image $image
513
     */
514
    public function addImage(Image $image)
515
    {
516
        if (!$this->images->contains($image)) {
517
            $this->apply(
518
                $this->createImageAddedEvent($image)
519
            );
520
        }
521
    }
522
523
    /**
524
     * @param AbstractUpdateImage $updateImageCommand
525
     */
526
    public function updateImage(AbstractUpdateImage $updateImageCommand)
527
    {
528
        if ($this->updateImageAllowed($updateImageCommand)) {
529
            $this->apply(
530
                $this->createImageUpdatedEvent($updateImageCommand)
531
            );
532
        }
533
    }
534
535
    /**
536
     * @param AbstractUpdateImage $updateImageCommand
537
     * @return bool
538
     */
539
    private function updateImageAllowed(AbstractUpdateImage $updateImageCommand)
540
    {
541
        $image = $this->images->findImageByUUID($updateImageCommand->getMediaObjectId());
542
543
        // Don't update if the image is not found based on UUID.
544
        if (!$image) {
545
            return false;
546
        }
547
548
        // Update when copyright or description is changed.
549
        return !$updateImageCommand->getCopyrightHolder()->sameValueAs($image->getCopyrightHolder()) ||
550
            !$updateImageCommand->getDescription()->sameValueAs($image->getDescription());
551
    }
552
553
    /**
554
     * Remove an image.
555
     *
556
     * @param Image $image
557
     */
558
    public function removeImage(Image $image)
559
    {
560
        if ($this->images->contains($image)) {
561
            $this->apply(
562
                $this->createImageRemovedEvent($image)
563
            );
564
        }
565
    }
566
567
    /**
568
     * Make an existing image of the item the main image.
569
     *
570
     * @param Image $image
571
     */
572
    public function selectMainImage(Image $image)
573
    {
574
        if (!$this->images->contains($image)) {
575
            throw new \InvalidArgumentException('You can not select a random image to be main, it has to be added to the item.');
576
        }
577
578
        $oldMainImage = $this->images->getMain();
579
580
        if (!isset($oldMainImage) || $oldMainImage->getMediaObjectId() !== $image->getMediaObjectId()) {
581
            $this->apply(
582
                $this->createMainImageSelectedEvent($image)
583
            );
584
        }
585
    }
586
587
    /**
588
     * Delete the offer.
589
     */
590
    public function delete()
591
    {
592
        $this->apply(
593
            $this->createOfferDeletedEvent()
594
        );
595
    }
596
597
    /**
598
     * @param CultureFeed_Cdb_Item_Base $cdbItem
599
     */
600
    protected function importWorkflowStatus(CultureFeed_Cdb_Item_Base $cdbItem)
601
    {
602
        try {
603
            $workflowStatus = WorkflowStatus::fromNative($cdbItem->getWfStatus());
604
        } catch (\InvalidArgumentException $exception) {
605
            $workflowStatus = WorkflowStatus::READY_FOR_VALIDATION();
606
        }
607
        $this->workflowStatus = $workflowStatus;
608
    }
609
610
    /**
611
     * Publish the offer when it has workflowstatus draft.
612
     * @param \DateTimeInterface $publicationDate
613
     */
614
    public function publish(\DateTimeInterface $publicationDate)
615
    {
616
        $this->guardPublish() ?: $this->apply(
617
            $this->createPublishedEvent($publicationDate)
618
        );
619
    }
620
621
    /**
622
     * @return bool
623
     * @throws Exception
624
     */
625 View Code Duplication
    private function guardPublish()
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...
626
    {
627
        if ($this->workflowStatus === WorkflowStatus::READY_FOR_VALIDATION()) {
628
            return true; // nothing left to do if the offer has already been published
629
        }
630
631
        if ($this->workflowStatus !== WorkflowStatus::DRAFT()) {
632
            throw new Exception('You can not publish an offer that is not draft');
633
        }
634
635
        return false;
636
    }
637
638
    /**
639
     * Approve the offer when it's waiting for validation.
640
     */
641
    public function approve()
642
    {
643
        $this->guardApprove() ?: $this->apply($this->createApprovedEvent());
644
    }
645
646
    /**
647
     * @return bool
648
     * @throws Exception
649
     */
650 View Code Duplication
    private function guardApprove()
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...
651
    {
652
        if ($this->workflowStatus === WorkflowStatus::APPROVED()) {
653
            return true; // nothing left to do if the offer has already been approved
654
        }
655
656
        if ($this->workflowStatus !== WorkflowStatus::READY_FOR_VALIDATION()) {
657
            throw new Exception('You can not approve an offer that is not ready for validation');
658
        }
659
660
        return false;
661
    }
662
663
    /**
664
     * Reject an offer that is waiting for validation with a given reason.
665
     * @param StringLiteral $reason
666
     */
667
    public function reject(StringLiteral $reason)
668
    {
669
        $this->guardRejection($reason) ?: $this->apply($this->createRejectedEvent($reason));
670
    }
671
672
    public function flagAsDuplicate()
673
    {
674
        $reason = new StringLiteral(self::DUPLICATE_REASON);
675
        $this->guardRejection($reason) ?: $this->apply($this->createFlaggedAsDuplicate());
676
    }
677
678
    public function flagAsInappropriate()
679
    {
680
        $reason = new StringLiteral(self::INAPPROPRIATE_REASON);
681
        $this->guardRejection($reason) ?: $this->apply($this->createFlaggedAsInappropriate());
682
    }
683
684
    /**
685
     * @param StringLiteral $reason
686
     * @return bool
687
     *  false when the offer can still be rejected, true when the offer is already rejected for the same reason
688
     * @throws Exception
689
     */
690
    private function guardRejection(StringLiteral $reason)
691
    {
692
        if ($this->workflowStatus === WorkflowStatus::REJECTED()) {
693
            if ($this->rejectedReason && $reason->sameValueAs($this->rejectedReason)) {
694
                return true; // nothing left to do if the offer has already been rejected for the same reason
695
            } else {
696
                throw new Exception('The offer has already been rejected for another reason: ' . $this->rejectedReason);
697
            }
698
        }
699
700
        if ($this->workflowStatus !== WorkflowStatus::READY_FOR_VALIDATION()) {
701
            throw new Exception('You can not reject an offer that is not ready for validation');
702
        }
703
704
        return false;
705
    }
706
707
    /**
708
     * @param Title $title
709
     * @param Language $language
710
     * @return bool
711
     */
712 View Code Duplication
    private function isTitleChanged(Title $title, Language $language)
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...
713
    {
714
        $languageCode = $language->getCode();
715
716
        return !isset($this->titles[$languageCode]) ||
717
            !$title->sameValueAs($this->titles[$languageCode]);
718
    }
719
720
    /**
721
     * @param Description $description
722
     * @param Language $language
723
     * @return bool
724
     */
725 View Code Duplication
    private function isDescriptionChanged(Description $description, Language $language)
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...
726
    {
727
        $languageCode = $language->getCode();
728
729
        return !isset($this->descriptions[$languageCode]) ||
730
            !$description->sameValueAs($this->descriptions[$languageCode]);
731
    }
732
733
    /**
734
     * Overwrites or resets the main image and all media objects
735
     * by importing a new collection of images from UDB2.
736
     *
737
     * @param ImageCollection $images
738
     */
739
    public function importImagesFromUDB2(ImageCollection $images)
740
    {
741
        $this->apply($this->createImagesImportedFromUDB2($images));
742
    }
743
744
    /**
745
     * Overwrites or resets the main image and all media objects
746
     * by updating with a new collection of images from UDB2.
747
     *
748
     * @param ImageCollection $images
749
     */
750
    public function updateImagesFromUDB2(ImageCollection $images)
751
    {
752
        $this->apply($this->createImagesUpdatedFromUDB2($images));
753
    }
754
755
    /**
756
     * @param AbstractPublished $published
757
     */
758
    protected function applyPublished(AbstractPublished $published)
0 ignored issues
show
Unused Code introduced by
The parameter $published is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
759
    {
760
        $this->workflowStatus = WorkflowStatus::READY_FOR_VALIDATION();
761
    }
762
763
    /**
764
     * @param AbstractApproved $approved
765
     */
766
    protected function applyApproved(AbstractApproved $approved)
0 ignored issues
show
Unused Code introduced by
The parameter $approved is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
767
    {
768
        $this->workflowStatus = WorkflowStatus::APPROVED();
769
    }
770
771
    /**
772
     * @param AbstractRejected $rejected
773
     */
774
    protected function applyRejected(AbstractRejected $rejected)
775
    {
776
        $this->rejectedReason = $rejected->getReason();
777
        $this->workflowStatus = WorkflowStatus::REJECTED();
778
    }
779
780
    /**
781
     * @param AbstractFlaggedAsDuplicate $flaggedAsDuplicate
782
     */
783
    protected function applyFlaggedAsDuplicate(AbstractFlaggedAsDuplicate $flaggedAsDuplicate)
0 ignored issues
show
Unused Code introduced by
The parameter $flaggedAsDuplicate is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
784
    {
785
        $this->rejectedReason = new StringLiteral(self::DUPLICATE_REASON);
786
        $this->workflowStatus = WorkflowStatus::REJECTED();
787
    }
788
789
    /**
790
     * @param AbstractFlaggedAsInappropriate $flaggedAsInappropriate
791
     */
792
    protected function applyFlaggedAsInappropriate(AbstractFlaggedAsInappropriate $flaggedAsInappropriate)
0 ignored issues
show
Unused Code introduced by
The parameter $flaggedAsInappropriate is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
793
    {
794
        $this->rejectedReason = new StringLiteral(self::INAPPROPRIATE_REASON);
795
        $this->workflowStatus = WorkflowStatus::REJECTED();
796
    }
797
798
    protected function applyImageAdded(AbstractImageAdded $imageAdded)
799
    {
800
        $this->images = $this->images->with($imageAdded->getImage());
801
    }
802
803
    protected function applyImageUpdated(AbstractImageUpdated $imageUpdated)
804
    {
805
        $image = $this->images->findImageByUUID($imageUpdated->getMediaObjectId());
806
807
        $updatedImage = new Image(
808
            $image->getMediaObjectId(),
809
            $image->getMimeType(),
810
            new ImageDescription($imageUpdated->getDescription()->toNative()),
811
            new CopyrightHolder($imageUpdated->getCopyrightHolder()->toNative()),
812
            $image->getSourceLocation(),
813
            $image->getLanguage()
814
        );
815
816
        // Currently no other option to update an item inside a collection.
817
        $this->images = $this->images->without($image);
818
        $this->images = $this->images->with($updatedImage);
819
    }
820
821
    protected function applyImageRemoved(AbstractImageRemoved $imageRemoved)
822
    {
823
        $this->images = $this->images->without($imageRemoved->getImage());
824
    }
825
826
    protected function applyMainImageSelected(AbstractMainImageSelected $mainImageSelected)
827
    {
828
        $this->images = $this->images->withMain($mainImageSelected->getImage());
829
    }
830
831
    protected function applyOrganizerUpdated(AbstractOrganizerUpdated $organizerUpdated)
832
    {
833
        $this->organizerId = $organizerUpdated->getOrganizerId();
834
    }
835
836
    protected function applyOrganizerDeleted(AbstractOrganizerDeleted $organizerDeleted)
0 ignored issues
show
Unused Code introduced by
The parameter $organizerDeleted is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
837
    {
838
        $this->organizerId = null;
839
    }
840
841
    /**
842
     * @param AbstractImagesImportedFromUDB2 $imagesImportedFromUDB2
843
     */
844
    protected function applyImagesImportedFromUDB2(AbstractImagesImportedFromUDB2 $imagesImportedFromUDB2)
845
    {
846
        $this->applyUdb2ImagesEvent($imagesImportedFromUDB2);
847
    }
848
849
    /**
850
     * @param AbstractImagesUpdatedFromUDB2 $imagesUpdatedFromUDB2
851
     */
852
    protected function applyImagesUpdatedFromUDB2(AbstractImagesUpdatedFromUDB2 $imagesUpdatedFromUDB2)
853
    {
854
        $this->applyUdb2ImagesEvent($imagesUpdatedFromUDB2);
855
    }
856
857
    /**
858
     * This indirect apply method can be called internally to deal with images coming from UDB2.
859
     * Imports from UDB2 only contain the native Dutch content.
860
     * @see https://github.com/cultuurnet/udb3-udb2-bridge/blob/db0a7ab2444f55bb3faae3d59b82b39aaeba253b/test/Media/ImageCollectionFactoryTest.php#L79-L103
861
     * Because of this we have to make sure translated images are left in place.
862
     *
863
     * @param AbstractImagesEvent $imagesEvent
864
     */
865
    protected function applyUdb2ImagesEvent(AbstractImagesEvent $imagesEvent)
866
    {
867
        $newMainImage = $imagesEvent->getImages()->getMain();
868
        $dutchImagesList = $imagesEvent->getImages()->toArray();
869
        $translatedImagesList = array_filter(
870
            $this->images->toArray(),
871
            function (Image $image) {
872
                return $image->getLanguage()->getCode() !== 'nl';
873
            }
874
        );
875
876
        $imagesList = array_merge($dutchImagesList, $translatedImagesList);
877
        $images = ImageCollection::fromArray($imagesList);
878
879
        $this->images = isset($newMainImage) ? $images->withMain($newMainImage) : $images;
880
    }
881
882
    /**
883
     * @param Label $label
884
     * @return AbstractLabelAdded
885
     */
886
    abstract protected function createLabelAddedEvent(Label $label);
887
888
    /**
889
     * @param Label $label
890
     * @return AbstractLabelRemoved
891
     */
892
    abstract protected function createLabelRemovedEvent(Label $label);
893
894
    /**
895
     * @param Language $language
896
     * @param StringLiteral $title
897
     * @return AbstractTitleTranslated
898
     */
899
    abstract protected function createTitleTranslatedEvent(Language $language, StringLiteral $title);
900
901
    /**
902
     * @param Language $language
903
     * @param StringLiteral $description
904
     * @return AbstractDescriptionTranslated
905
     */
906
    abstract protected function createDescriptionTranslatedEvent(Language $language, StringLiteral $description);
907
908
    /**
909
     * @param Image $image
910
     * @return AbstractImageAdded
911
     */
912
    abstract protected function createImageAddedEvent(Image $image);
913
914
    /**
915
     * @param Image $image
916
     * @return AbstractImageRemoved
917
     */
918
    abstract protected function createImageRemovedEvent(Image $image);
919
920
    /**
921
     * @param AbstractUpdateImage $updateImageCommand
922
     * @return AbstractImageUpdated
923
     */
924
    abstract protected function createImageUpdatedEvent(
925
        AbstractUpdateImage $updateImageCommand
926
    );
927
928
    /**
929
     * @param Image $image
930
     * @return AbstractMainImageSelected
931
     */
932
    abstract protected function createMainImageSelectedEvent(Image $image);
933
934
    /**
935
     * @return AbstractOfferDeleted
936
     */
937
    abstract protected function createOfferDeletedEvent();
938
939
    /**
940
     * @param Title $title
941
     * @return AbstractTitleUpdated
942
     */
943
    abstract protected function createTitleUpdatedEvent(Title $title);
944
945
    /**
946
     * @param string $description
947
     * @return AbstractDescriptionUpdated
948
     */
949
    abstract protected function createDescriptionUpdatedEvent($description);
950
951
    /**
952
     * @param Calendar $calendar
953
     * @return AbstractCalendarUpdated
954
     */
955
    abstract protected function createCalendarUpdatedEvent(Calendar $calendar);
956
957
    /**
958
     * @param string $typicalAgeRange
959
     * @return AbstractTypicalAgeRangeUpdated
960
     */
961
    abstract protected function createTypicalAgeRangeUpdatedEvent($typicalAgeRange);
962
963
    /**
964
     * @return AbstractTypicalAgeRangeDeleted
965
     */
966
    abstract protected function createTypicalAgeRangeDeletedEvent();
967
968
    /**
969
     * @param string $organizerId
970
     * @return AbstractOrganizerUpdated
971
     */
972
    abstract protected function createOrganizerUpdatedEvent($organizerId);
973
974
    /**
975
     * @param string $organizerId
976
     * @return AbstractOrganizerDeleted
977
     */
978
    abstract protected function createOrganizerDeletedEvent($organizerId);
979
980
    /**
981
     * @param ContactPoint $contactPoint
982
     * @return AbstractContactPointUpdated
983
     */
984
    abstract protected function createContactPointUpdatedEvent(ContactPoint $contactPoint);
985
986
    /**
987
     * @param Coordinates $coordinates
988
     * @return AbstractGeoCoordinatesUpdated
989
     */
990
    abstract protected function createGeoCoordinatesUpdatedEvent(Coordinates $coordinates);
991
992
    /**
993
     * @param BookingInfo $bookingInfo
994
     * @return AbstractBookingInfoUpdated
995
     */
996
    abstract protected function createBookingInfoUpdatedEvent(BookingInfo $bookingInfo);
997
998
    /**
999
     * @param PriceInfo $priceInfo
1000
     * @return AbstractPriceInfoUpdated
1001
     */
1002
    abstract protected function createPriceInfoUpdatedEvent(PriceInfo $priceInfo);
1003
1004
    /**
1005
     * @param \DateTimeInterface $publicationDate
1006
     * @return AbstractPublished
1007
     */
1008
    abstract protected function createPublishedEvent(\DateTimeInterface $publicationDate);
1009
1010
    /**
1011
     * @return AbstractApproved
1012
     */
1013
    abstract protected function createApprovedEvent();
1014
1015
    /**
1016
     * @param StringLiteral $reason
1017
     * @return AbstractRejected
1018
     */
1019
    abstract protected function createRejectedEvent(StringLiteral $reason);
1020
1021
    /**
1022
     * @return AbstractFlaggedAsDuplicate
1023
     */
1024
    abstract protected function createFlaggedAsDuplicate();
1025
1026
    /**
1027
     * @return AbstractFlaggedAsInappropriate
1028
     */
1029
    abstract protected function createFlaggedAsInappropriate();
1030
1031
    /**
1032
     * @param ImageCollection $images
1033
     * @return AbstractImagesImportedFromUDB2
1034
     */
1035
    abstract protected function createImagesImportedFromUDB2(ImageCollection $images);
1036
1037
    /**
1038
     * @param ImageCollection $images
1039
     * @return AbstractImagesUpdatedFromUDB2
1040
     */
1041
    abstract protected function createImagesUpdatedFromUDB2(ImageCollection $images);
1042
1043
    /**
1044
     * @param EventType $type
1045
     * @return AbstractTypeUpdated
1046
     */
1047
    abstract protected function createTypeUpdatedEvent(EventType $type);
1048
1049
    /**
1050
     * @param Theme $theme
1051
     * @return AbstractThemeUpdated
1052
     */
1053
    abstract protected function createThemeUpdatedEvent(Theme $theme);
1054
1055
    /**
1056
     * @param array $facilities
1057
     * @return AbstractFacilitiesUpdated
1058
     */
1059
    abstract protected function createFacilitiesUpdatedEvent(array $facilities);
1060
}
1061