Completed
Pull Request — master (#414)
by
unknown
03:33
created

Event::createBookingInfoUpdatedEvent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3\Event;
4
5
use Broadway\EventSourcing\EventSourcedAggregateRoot;
6
use CultuurNet\Geocoding\Coordinate\Coordinates;
7
use CultuurNet\UDB3\BookingInfo;
8
use CultuurNet\UDB3\Calendar;
9
use CultuurNet\UDB3\CalendarInterface;
10
use CultuurNet\UDB3\Cdb\EventItemFactory;
11
use CultuurNet\UDB3\Cdb\UpdateableWithCdbXmlInterface;
12
use CultuurNet\UDB3\ContactPoint;
13
use CultuurNet\UDB3\Description;
14
use CultuurNet\UDB3\Event\Events\AudienceUpdated;
15
use CultuurNet\UDB3\Event\Events\BookingInfoUpdated;
16
use CultuurNet\UDB3\Event\Events\CalendarUpdated;
17
use CultuurNet\UDB3\Event\Events\Concluded;
18
use CultuurNet\UDB3\Event\Events\ContactPointUpdated;
19
use CultuurNet\UDB3\Event\Events\DescriptionTranslated;
20
use CultuurNet\UDB3\Event\Events\DescriptionUpdated;
21
use CultuurNet\UDB3\Event\Events\EventCdbXMLInterface;
22
use CultuurNet\UDB3\Event\Events\EventCopied;
23
use CultuurNet\UDB3\Event\Events\EventCreated;
24
use CultuurNet\UDB3\Event\Events\EventDeleted;
25
use CultuurNet\UDB3\Event\Events\EventImportedFromUDB2;
26
use CultuurNet\UDB3\Event\Events\EventUpdatedFromUDB2;
27
use CultuurNet\UDB3\Event\Events\FacilitiesUpdated;
28
use CultuurNet\UDB3\Event\Events\GeoCoordinatesUpdated;
29
use CultuurNet\UDB3\Event\Events\ImageAdded;
30
use CultuurNet\UDB3\Event\Events\ImageRemoved;
31
use CultuurNet\UDB3\Event\Events\Image\ImagesImportedFromUDB2;
32
use CultuurNet\UDB3\Event\Events\Image\ImagesUpdatedFromUDB2;
33
use CultuurNet\UDB3\Event\Events\ImageUpdated;
34
use CultuurNet\UDB3\Event\Events\LabelAdded;
35
use CultuurNet\UDB3\Event\Events\LabelRemoved;
36
use CultuurNet\UDB3\Event\Events\LabelsImported;
37
use CultuurNet\UDB3\Event\Events\LocationUpdated;
38
use CultuurNet\UDB3\Event\Events\MainImageSelected;
39
use CultuurNet\UDB3\Event\Events\MajorInfoUpdated;
40
use CultuurNet\UDB3\Event\Events\Moderation\Approved;
41
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsDuplicate;
42
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsInappropriate;
43
use CultuurNet\UDB3\Event\Events\Moderation\Published;
44
use CultuurNet\UDB3\Event\Events\Moderation\Rejected;
45
use CultuurNet\UDB3\Event\Events\OrganizerDeleted;
46
use CultuurNet\UDB3\Event\Events\OrganizerUpdated;
47
use CultuurNet\UDB3\Event\Events\PriceInfoUpdated;
48
use CultuurNet\UDB3\Event\Events\ThemeUpdated;
49
use CultuurNet\UDB3\Event\Events\TitleTranslated;
50
use CultuurNet\UDB3\Event\Events\TitleUpdated;
51
use CultuurNet\UDB3\Event\Events\TypeUpdated;
52
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted;
53
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated;
54
use CultuurNet\UDB3\Event\ValueObjects\Audience;
55
use CultuurNet\UDB3\Event\ValueObjects\AudienceType;
56
use CultuurNet\UDB3\Label;
57
use CultuurNet\UDB3\LabelCollection;
58
use CultuurNet\UDB3\Language;
59
use CultuurNet\UDB3\Event\ValueObjects\LocationId;
60
use CultuurNet\UDB3\Media\ImageCollection;
61
use CultuurNet\UDB3\Media\Image;
62
use CultuurNet\UDB3\Model\ValueObject\Taxonomy\Label\Labels;
63
use CultuurNet\UDB3\Offer\AgeRange;
64
use CultuurNet\UDB3\Offer\Offer;
65
use CultuurNet\UDB3\Offer\WorkflowStatus;
66
use CultuurNet\UDB3\PriceInfo\PriceInfo;
67
use CultuurNet\UDB3\Theme;
68
use CultuurNet\UDB3\Title;
69
use ValueObjects\Identity\UUID;
70
use ValueObjects\Person\Age;
71
use ValueObjects\StringLiteral\StringLiteral;
72
73
class Event extends Offer implements UpdateableWithCdbXmlInterface
74
{
75
    /**
76
     * @var string
77
     */
78
    protected $eventId;
79
80
    /**
81
     * @var Audience
82
     */
83
    private $audience;
84
85
    /**
86
     * @var LocationId
87
     */
88
    private $locationId;
89
90
    /**
91
     * @var boolean
92
     */
93
    private $concluded = false;
94
95
    public function __construct()
96
    {
97
        parent::__construct();
98
    }
99
100
    /**
101
     * Factory method to create a new event.
102
     *
103
     * @param $eventId
104
     * @param Language $mainLanguage
105
     * @param Title $title
106
     * @param EventType $eventType
107
     * @param LocationId $location
108
     * @param CalendarInterface $calendar
109
     * @param Theme|null $theme
110
     * @param \DateTimeImmutable|null $publicationDate
111
     * @return Event
112
     */
113
    public static function create(
114
        $eventId,
115
        Language $mainLanguage,
116
        Title $title,
117
        EventType $eventType,
118
        LocationId $location,
119
        CalendarInterface $calendar,
120
        Theme $theme = null,
121
        \DateTimeImmutable $publicationDate = null
122
    ) {
123
        $event = new self();
124
125
        $event->apply(
126
            new EventCreated(
127
                $eventId,
128
                $mainLanguage,
129
                $title,
130
                $eventType,
131
                $location,
132
                $calendar,
133
                $theme,
134
                $publicationDate
135
            )
136
        );
137
138
        if ($location->isDummyPlaceForEducation()) {
139
            // Bookable education events should get education as their audience type. We record this explicitly so we
140
            // don't have to handle this edge case in every read model projector.
141
            $event->apply(
142
                new AudienceUpdated($eventId, new Audience(AudienceType::EDUCATION()))
143
            );
144
        }
145
146
        return $event;
147
    }
148
149
    /**
150
     * @param string $newEventId
151
     * @param CalendarInterface $calendar
152
     *
153
     * @return Event
154
     */
155
    public function copy($newEventId, CalendarInterface $calendar)
156
    {
157
        if ($this->hasUncommittedEvents()) {
158
            throw new \RuntimeException('I refuse to copy, there are uncommitted events present.');
159
        }
160
161
        // The copied event will have a playhead of the original event + 1
162
        $copy = clone $this;
163
164
        $copy->apply(
165
            new EventCopied(
166
                $newEventId,
167
                $this->eventId,
168
                $calendar
169
            )
170
        );
171
172
        return $copy;
173
    }
174
175
    /**
176
     * @param string $eventId
177
     * @param string $cdbXml
178
     * @param string $cdbXmlNamespaceUri
179
     * @return Event
180
     */
181
    public static function importFromUDB2(
182
        $eventId,
183
        $cdbXml,
184
        $cdbXmlNamespaceUri
185
    ) {
186
        $event = new self();
187
        $event->apply(
188
            new EventImportedFromUDB2(
189
                $eventId,
190
                $cdbXml,
191
                $cdbXmlNamespaceUri
192
            )
193
        );
194
195
        return $event;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function getAggregateRootId()
202
    {
203
        return $this->eventId;
204
    }
205
206 View Code Duplication
    protected function applyEventCreated(EventCreated $eventCreated)
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...
207
    {
208
        $this->eventId = $eventCreated->getEventId();
209
        $this->titles[$eventCreated->getMainLanguage()->getCode()] = $eventCreated->getTitle();
210
        $this->calendar = $eventCreated->getCalendar();
211
        $this->audience = new Audience(AudienceType::EVERYONE());
212
        $this->contactPoint = new ContactPoint();
213
        $this->bookingInfo = new BookingInfo();
214
        $this->typeId = $eventCreated->getEventType()->getId();
215
        $this->themeId = $eventCreated->getTheme() ? $eventCreated->getTheme()->getId() : null;
216
        $this->locationId = $eventCreated->getLocation();
217
        $this->mainLanguage = $eventCreated->getMainLanguage();
218
        $this->workflowStatus = WorkflowStatus::DRAFT();
219
    }
220
221
    /**
222
     * @param EventCopied $eventCopied
223
     */
224
    protected function applyEventCopied(EventCopied $eventCopied)
225
    {
226
        $this->eventId = $eventCopied->getItemId();
227
        $this->workflowStatus = WorkflowStatus::DRAFT();
228
        $this->labels = new LabelCollection();
229
    }
230
231
    protected function applyEventImportedFromUDB2(
232
        EventImportedFromUDB2 $eventImported
233
    ) {
234
        $this->eventId = $eventImported->getEventId();
235
        // When importing from UDB2 the default main language is always 'nl'.
236
        $this->mainLanguage = new Language('nl');
237
        $this->setUDB2Data($eventImported);
238
    }
239
240
    /**
241
     * @param EventUpdatedFromUDB2 $eventUpdated
242
     */
243
    protected function applyEventUpdatedFromUDB2(
244
        EventUpdatedFromUDB2 $eventUpdated
245
    ) {
246
        // Note: when updating from UDB2 never change the main language.
247
        $this->setUDB2Data($eventUpdated);
248
    }
249
250
    protected function applyEventDeleted(EventDeleted $event): void
0 ignored issues
show
Unused Code introduced by
The parameter $event 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...
251
    {
252
        $this->isDeleted = true;
253
    }
254
255
    /**
256
     * @param EventCdbXMLInterface $eventCdbXML
257
     */
258
    protected function setUDB2Data(
259
        EventCdbXMLInterface $eventCdbXML
260
    ) {
261
        $udb2Event = EventItemFactory::createEventFromCdbXml(
262
            $eventCdbXML->getCdbXmlNamespaceUri(),
263
            $eventCdbXML->getCdbXml()
264
        );
265
266
        // Just clear the facilities.
267
        $this->facilities = [];
268
269
        // Just clear the location id after an import or update.
270
        $this->locationId = null;
271
272
        // Just clear the contact point.
273
        $this->contactPoint = null;
274
275
        // Just clear the calendar.
276
        $this->calendar = null;
277
278
        // Correctly set the age range to avoid issues with deleting age range.
279
        // after an update from UDB2.
280
        $this->typicalAgeRange = new AgeRange(
281
            $udb2Event->getAgeFrom() ? new Age($udb2Event->getAgeFrom()) : null,
282
            $udb2Event->getAgeTo() ? new Age($udb2Event->getAgeTo()) : null
283
        );
284
285
        // Just clear the booking info.
286
        $this->bookingInfo = null;
287
288
        // Just clear the price info.
289
        $this->priceInfo = null;
290
291
        $this->importWorkflowStatus($udb2Event);
292
        $this->labels = LabelCollection::fromKeywords($udb2Event->getKeywords(true));
293
    }
294
295
    /**
296
     * Update the major info.
297
     *
298
     * @param Title $title
299
     * @param EventType $eventType
300
     * @param LocationId $location
301
     * @param CalendarInterface $calendar
302
     * @param Theme|null $theme
303
     */
304
    public function updateMajorInfo(
305
        Title $title,
306
        EventType $eventType,
307
        LocationId $location,
308
        CalendarInterface $calendar,
309
        Theme $theme = null
310
    ) {
311
        $this->apply(new MajorInfoUpdated($this->eventId, $title, $eventType, $location, $calendar, $theme));
312
    }
313
314
    /**
315
     * @param LocationId $locationId
316
     */
317
    public function updateLocation(LocationId $locationId)
318
    {
319
        if (!is_null($this->locationId) && $this->locationId->sameValueAs($locationId)) {
320
            return;
321
        }
322
323
        $this->apply(new LocationUpdated($this->eventId, $locationId));
324
325
        if ($locationId->isDummyPlaceForEducation()) {
326
            // Bookable education events should get education as their audience type. We record this explicitly so we
327
            // don't have to handle this edge case in every read model projector.
328
            $this->apply(
329
                new AudienceUpdated($this->eventId, new Audience(AudienceType::EDUCATION()))
330
            );
331
        }
332
    }
333
334
    /**
335
     * @param LocationUpdated $locationUpdated
336
     */
337
    public function applyLocationUpdated(LocationUpdated $locationUpdated)
338
    {
339
        $this->locationId = $locationUpdated->getLocationId();
340
    }
341
342
    /**
343
     * @param Audience $audience
344
     */
345
    public function updateAudience(
346
        Audience $audience
347
    ) {
348
        $audienceType = $audience->getAudienceType();
349
        if ($this->locationId->isDummyPlaceForEducation() && !$audienceType->sameValueAs(AudienceType::EDUCATION())) {
350
            throw IncompatibleAudienceType::forEvent($this->eventId, $audienceType);
351
        }
352
353
        if (is_null($this->audience) || !$this->audience->equals($audience)) {
354
            $this->apply(new AudienceUpdated(
355
                $this->eventId,
356
                $audience
357
            ));
358
        }
359
    }
360
361
    /**
362
     * @param AudienceUpdated $audienceUpdated
363
     */
364
    public function applyAudienceUpdated(AudienceUpdated $audienceUpdated)
365
    {
366
        $this->audience= $audienceUpdated->getAudience();
367
    }
368
369
    /**
370
     * @inheritDoc
371
     * @return ImagesImportedFromUDB2
372
     */
373
    protected function createImagesImportedFromUDB2(ImageCollection $images)
374
    {
375
        return new ImagesImportedFromUDB2($this->eventId, $images);
376
    }
377
378
    /**
379
     * @inheritDoc
380
     * @return ImagesUpdatedFromUDB2
381
     */
382
    protected function createImagesUpdatedFromUDB2(ImageCollection $images)
383
    {
384
        return new ImagesUpdatedFromUDB2($this->eventId, $images);
385
    }
386
387
    /**
388
     * @inheritdoc
389
     */
390
    public function updateWithCdbXml($cdbXml, $cdbXmlNamespaceUri)
391
    {
392
        $this->apply(
393
            new EventUpdatedFromUDB2(
394
                $this->eventId,
395
                $cdbXml,
396
                $cdbXmlNamespaceUri
397
            )
398
        );
399
    }
400
401
    /**
402
     * @param Label $label
403
     * @return LabelAdded
404
     */
405
    protected function createLabelAddedEvent(Label $label)
406
    {
407
        return new LabelAdded($this->eventId, $label);
408
    }
409
410
    /**
411
     * @param Label $label
412
     * @return LabelRemoved
413
     */
414
    protected function createLabelRemovedEvent(Label $label)
415
    {
416
        return new LabelRemoved($this->eventId, $label);
417
    }
418
419
    /**
420
     * @inheritdoc
421
     */
422
    protected function createLabelsImportedEvent(Labels $labels)
423
    {
424
        return new LabelsImported($this->eventId, $labels);
425
    }
426
427
    /**
428
     * @param Image $image
429
     * @return ImageAdded
430
     */
431
    protected function createImageAddedEvent(Image $image)
432
    {
433
        return new ImageAdded($this->eventId, $image);
434
    }
435
436
    /**
437
     * @param Image $image
438
     * @return ImageRemoved
439
     */
440
    protected function createImageRemovedEvent(Image $image)
441
    {
442
        return new ImageRemoved($this->eventId, $image);
443
    }
444
445
    /**
446
     * @param UUID $mediaObjectId
447
     * @param StringLiteral $description
448
     * @param StringLiteral $copyrightHolder
449
     * @return ImageUpdated
450
     */
451
    protected function createImageUpdatedEvent(
452
        UUID $mediaObjectId,
453
        StringLiteral $description,
454
        StringLiteral $copyrightHolder
455
    ) {
456
        return new ImageUpdated(
457
            $this->eventId,
458
            $mediaObjectId,
459
            $description,
460
            $copyrightHolder
461
        );
462
    }
463
464
    /**
465
     * @param Image $image
466
     * @return MainImageSelected
467
     */
468
    protected function createMainImageSelectedEvent(Image $image)
469
    {
470
        return new MainImageSelected($this->eventId, $image);
471
    }
472
473
    /**
474
     * @inheritdoc
475
     */
476
    protected function createTitleTranslatedEvent(Language $language, Title $title)
477
    {
478
        return new TitleTranslated($this->eventId, $language, $title);
479
    }
480
481
    /**
482
     * @param Title $title
483
     * @return TitleUpdated
484
     */
485
    protected function createTitleUpdatedEvent(Title $title)
486
    {
487
        return new TitleUpdated($this->eventId, $title);
488
    }
489
490
    /**
491
     * @inheritdoc
492
     */
493
    protected function createDescriptionTranslatedEvent(Language $language, Description $description)
494
    {
495
        return new DescriptionTranslated($this->eventId, $language, $description);
496
    }
497
498
    /**
499
     * @inheritdoc
500
     */
501
    protected function createDescriptionUpdatedEvent(Description $description)
502
    {
503
        return new DescriptionUpdated($this->eventId, $description);
504
    }
505
506
    /**
507
     * @inheritdoc
508
     */
509
    protected function createCalendarUpdatedEvent(Calendar $calendar)
510
    {
511
        return new CalendarUpdated($this->eventId, $calendar);
512
    }
513
514
    /**
515
     * @param AgeRange $typicalAgeRange
516
     * @return TypicalAgeRangeUpdated
517
     */
518
    protected function createTypicalAgeRangeUpdatedEvent($typicalAgeRange)
519
    {
520
        return new TypicalAgeRangeUpdated($this->eventId, $typicalAgeRange);
521
    }
522
523
    /**
524
     * @return TypicalAgeRangeDeleted
525
     */
526
    protected function createTypicalAgeRangeDeletedEvent()
527
    {
528
        return new TypicalAgeRangeDeleted($this->eventId);
529
    }
530
531
    /**
532
     * @param string $organizerId
533
     * @return OrganizerUpdated
534
     */
535
    protected function createOrganizerUpdatedEvent($organizerId)
536
    {
537
        return new OrganizerUpdated($this->eventId, $organizerId);
538
    }
539
540
    /**
541
     * @param string $organizerId
542
     * @return OrganizerDeleted
543
     */
544
    protected function createOrganizerDeletedEvent($organizerId)
545
    {
546
        return new OrganizerDeleted($this->eventId, $organizerId);
547
    }
548
549
    /**
550
     * @param ContactPoint $contactPoint
551
     * @return ContactPointUpdated
552
     */
553
    protected function createContactPointUpdatedEvent(ContactPoint $contactPoint)
554
    {
555
        return new ContactPointUpdated($this->eventId, $contactPoint);
556
    }
557
558
    /**
559
     * @inheritdoc
560
     */
561
    protected function createGeoCoordinatesUpdatedEvent(Coordinates $coordinates)
562
    {
563
        return new GeoCoordinatesUpdated($this->eventId, $coordinates);
564
    }
565
566
    /**
567
     * @param BookingInfo $bookingInfo
568
     * @return BookingInfoUpdated
569
     */
570
    protected function createBookingInfoUpdatedEvent(BookingInfo $bookingInfo)
571
    {
572
        return new BookingInfoUpdated($this->eventId, $bookingInfo);
573
    }
574
575
    /**
576
     * @param PriceInfo $priceInfo
577
     * @return PriceInfoUpdated
578
     */
579
    protected function createPriceInfoUpdatedEvent(PriceInfo $priceInfo)
580
    {
581
        return new PriceInfoUpdated($this->eventId, $priceInfo);
582
    }
583
584
    /**
585
     * @return EventDeleted
586
     */
587
    protected function createOfferDeletedEvent()
588
    {
589
        return new EventDeleted($this->eventId);
590
    }
591
592
    /**
593
     * @inheritdoc
594
     */
595
    protected function createPublishedEvent(\DateTimeInterface $publicationDate)
596
    {
597
        return new Published($this->eventId, $publicationDate);
598
    }
599
600
    /**
601
     * @inheritdoc
602
     */
603
    protected function createApprovedEvent()
604
    {
605
        return new Approved($this->eventId);
606
    }
607
608
    /**
609
     * @inheritdoc
610
     */
611
    protected function createRejectedEvent(StringLiteral $reason)
612
    {
613
        return new Rejected($this->eventId, $reason);
614
    }
615
616
    /**
617
     * @inheritDoc
618
     */
619
    protected function createFlaggedAsDuplicate()
620
    {
621
        return new FlaggedAsDuplicate($this->eventId);
622
    }
623
624
    /**
625
     * @inheritDoc
626
     */
627
    protected function createFlaggedAsInappropriate()
628
    {
629
        return new FlaggedAsInappropriate($this->eventId);
630
    }
631
632
    /**
633
     * @inheritdoc
634
     */
635
    protected function createTypeUpdatedEvent(EventType $type)
636
    {
637
        return new TypeUpdated($this->eventId, $type);
638
    }
639
640
    /**
641
     * @inheritdoc
642
     */
643
    protected function createThemeUpdatedEvent(Theme $theme)
644
    {
645
        return new ThemeUpdated($this->eventId, $theme);
646
    }
647
648
    /**
649
     * @inheritdoc
650
     */
651
    protected function createFacilitiesUpdatedEvent(array $facilities)
652
    {
653
        return new FacilitiesUpdated($this->eventId, $facilities);
654
    }
655
656
    /**
657
     * Use reflection to get check if the aggregate has uncommitted events.
658
     * @return bool
659
     */
660
    private function hasUncommittedEvents()
661
    {
662
        $reflector = new \ReflectionClass(EventSourcedAggregateRoot::class);
663
        $property = $reflector->getProperty('uncommittedEvents');
664
665
        $property->setAccessible(true);
666
        $uncommittedEvents = $property->getValue($this);
667
668
        return !empty($uncommittedEvents);
669
    }
670
671
    public function conclude()
672
    {
673
        if (!$this->concluded) {
674
            $this->apply(new Concluded($this->eventId));
675
        }
676
    }
677
678
    /**
679
     * @param Concluded $concluded
680
     */
681
    protected function applyConcluded(Concluded $concluded)
0 ignored issues
show
Unused Code introduced by
The parameter $concluded 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...
682
    {
683
        $this->concluded = true;
684
    }
685
}
686