Completed
Pull Request — master (#336)
by Luc
04:29
created

Event::createMainImageSelectedEvent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3\Event;
4
5
use Broadway\EventSourcing\EventSourcedAggregateRoot;
6
use CultuurNet\UDB3\BookingInfo;
7
use CultuurNet\UDB3\Calendar;
8
use CultuurNet\UDB3\CalendarInterface;
9
use CultuurNet\UDB3\Cdb\EventItemFactory;
10
use CultuurNet\UDB3\Cdb\UpdateableWithCdbXmlInterface;
11
use CultuurNet\UDB3\ContactPoint;
12
use CultuurNet\UDB3\Event\Events\AudienceUpdated;
13
use CultuurNet\UDB3\Event\Events\BookingInfoUpdated;
14
use CultuurNet\UDB3\Event\Events\CalendarUpdated;
15
use CultuurNet\UDB3\Event\Events\Concluded;
16
use CultuurNet\UDB3\Event\Events\ContactPointUpdated;
17
use CultuurNet\UDB3\Event\Events\DescriptionTranslated;
18
use CultuurNet\UDB3\Event\Events\DescriptionUpdated;
19
use CultuurNet\UDB3\Event\Events\EventCdbXMLInterface;
20
use CultuurNet\UDB3\Event\Events\EventCopied;
21
use CultuurNet\UDB3\Event\Events\EventCreated;
22
use CultuurNet\UDB3\Event\Events\EventDeleted;
23
use CultuurNet\UDB3\Event\Events\EventImportedFromUDB2;
24
use CultuurNet\UDB3\Event\Events\EventUpdatedFromUDB2;
25
use CultuurNet\UDB3\Event\Events\FacilitiesUpdated;
26
use CultuurNet\UDB3\Event\Events\ImageAdded;
27
use CultuurNet\UDB3\Event\Events\ImageRemoved;
28
use CultuurNet\UDB3\Event\Events\Image\ImagesImportedFromUDB2;
29
use CultuurNet\UDB3\Event\Events\Image\ImagesUpdatedFromUDB2;
30
use CultuurNet\UDB3\Event\Events\ImageUpdated;
31
use CultuurNet\UDB3\Event\Events\LabelAdded;
32
use CultuurNet\UDB3\Event\Events\LabelRemoved;
33
use CultuurNet\UDB3\Event\Events\LocationUpdated;
34
use CultuurNet\UDB3\Event\Events\MainImageSelected;
35
use CultuurNet\UDB3\Event\Events\MajorInfoUpdated;
36
use CultuurNet\UDB3\Event\Events\Moderation\Approved;
37
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsDuplicate;
38
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsInappropriate;
39
use CultuurNet\UDB3\Event\Events\Moderation\Published;
40
use CultuurNet\UDB3\Event\Events\Moderation\Rejected;
41
use CultuurNet\UDB3\Event\Events\OrganizerDeleted;
42
use CultuurNet\UDB3\Event\Events\OrganizerUpdated;
43
use CultuurNet\UDB3\Event\Events\PriceInfoUpdated;
44
use CultuurNet\UDB3\Event\Events\ThemeUpdated;
45
use CultuurNet\UDB3\Event\Events\TitleTranslated;
46
use CultuurNet\UDB3\Event\Events\TitleUpdated;
47
use CultuurNet\UDB3\Event\Events\TypeUpdated;
48
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted;
49
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated;
50
use CultuurNet\UDB3\Event\ValueObjects\Audience;
51
use CultuurNet\UDB3\Label;
52
use CultuurNet\UDB3\LabelCollection;
53
use CultuurNet\UDB3\Language;
54
use CultuurNet\UDB3\Location\Location;
55
use CultuurNet\UDB3\Location\LocationId;
56
use CultuurNet\UDB3\Media\ImageCollection;
57
use CultuurNet\UDB3\Media\Image;
58
use CultuurNet\UDB3\Offer\Commands\Image\AbstractUpdateImage;
59
use CultuurNet\UDB3\Offer\Offer;
60
use CultuurNet\UDB3\Offer\WorkflowStatus;
61
use CultuurNet\UDB3\PriceInfo\PriceInfo;
62
use CultuurNet\UDB3\Theme;
63
use CultuurNet\UDB3\Title;
64
use ValueObjects\Identity\UUID;
65
use ValueObjects\StringLiteral\StringLiteral;
66
67
class Event extends Offer implements UpdateableWithCdbXmlInterface
68
{
69
    /**
70
     * @var string
71
     */
72
    protected $eventId;
73
74
    /**
75
     * @var Audience
76
     */
77
    private $audience;
78
79
    /**
80
     * @var boolean
81
     */
82
    private $concluded = false;
83
84
    const MAIN_LANGUAGE_CODE = 'nl';
85
86
    public function __construct()
87
    {
88
        parent::__construct();
89
    }
90
91
    /**
92
     * Factory method to create a new event.
93
     *
94
     * @param $eventId
95
     * @param Title $title
96
     * @param EventType $eventType
97
     * @param Location $location
98
     * @param CalendarInterface $calendar
99
     * @param Theme|null $theme
100
     * @param \DateTimeImmutable|null $publicationDate
101
     * @return Event
102
     */
103 View Code Duplication
    public static function create(
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...
104
        $eventId,
105
        Title $title,
106
        EventType $eventType,
107
        Location $location,
108
        CalendarInterface $calendar,
109
        Theme $theme = null,
110
        \DateTimeImmutable $publicationDate = null
111
    ) {
112
        $event = new self();
113
114
        $event->apply(
115
            new EventCreated(
116
                $eventId,
117
                $title,
118
                $eventType,
119
                $location,
120
                $calendar,
121
                $theme,
122
                $publicationDate
123
            )
124
        );
125
126
        return $event;
127
    }
128
129
    /**
130
     * @param string $newEventId
131
     * @param CalendarInterface $calendar
132
     *
133
     * @return Event
134
     */
135
    public function copy($newEventId, CalendarInterface $calendar)
136
    {
137
        if ($this->hasUncommittedEvents()) {
138
            throw new \RuntimeException('I refuse to copy, there are uncommitted events present.');
139
        }
140
141
        // The copied event will have a playhead of the original event + 1
142
        $copy = clone $this;
143
144
        $copy->apply(
145
            new EventCopied(
146
                $newEventId,
147
                $this->eventId,
148
                $calendar
149
            )
150
        );
151
152
        return $copy;
153
    }
154
155
    /**
156
     * @param string $eventId
157
     * @param string $cdbXml
158
     * @param string $cdbXmlNamespaceUri
159
     * @return Event
160
     */
161
    public static function importFromUDB2(
162
        $eventId,
163
        $cdbXml,
164
        $cdbXmlNamespaceUri
165
    ) {
166
        $event = new self();
167
        $event->apply(
168
            new EventImportedFromUDB2(
169
                $eventId,
170
                $cdbXml,
171
                $cdbXmlNamespaceUri
172
            )
173
        );
174
175
        return $event;
176
    }
177
178
    /**
179
     * @param ImageCollection $images
180
     */
181
    public function updateImagesFromUDB2(ImageCollection $images)
182
    {
183
        $this->apply(new ImagesUpdatedFromUDB2($this->eventId, $images));
184
    }
185
186
    /**
187
     * @param ImageCollection $images
188
     */
189
    public function importImagesFromUDB2(ImageCollection $images)
190
    {
191
        $this->apply(new ImagesImportedFromUDB2($this->eventId, $images));
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197
    public function getAggregateRootId()
198
    {
199
        return $this->eventId;
200
    }
201
202
    /**
203
     * @return UUID[]
204
     */
205
    public function getMediaObjects()
206
    {
207
        return $this->mediaObjects;
0 ignored issues
show
Bug introduced by
The property mediaObjects does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
208
    }
209
210
    protected function applyEventCreated(EventCreated $eventCreated)
211
    {
212
        $this->eventId = $eventCreated->getEventId();
213
        $this->workflowStatus = WorkflowStatus::DRAFT();
214
    }
215
216
    /**
217
     * @param EventCopied $eventCopied
218
     */
219
    protected function applyEventCopied(EventCopied $eventCopied)
220
    {
221
        $this->eventId = $eventCopied->getItemId();
222
        $this->workflowStatus = WorkflowStatus::DRAFT();
223
        $this->labels = new LabelCollection();
224
    }
225
226
    protected function applyEventImportedFromUDB2(
227
        EventImportedFromUDB2 $eventImported
228
    ) {
229
        $this->eventId = $eventImported->getEventId();
230
        $this->setUDB2Data($eventImported);
231
    }
232
233
    /**
234
     * @param EventUpdatedFromUDB2 $eventUpdated
235
     */
236
    protected function applyEventUpdatedFromUDB2(
237
        EventUpdatedFromUDB2 $eventUpdated
238
    ) {
239
        $this->setUDB2Data($eventUpdated);
240
    }
241
242
    /**
243
     * @param EventCdbXMLInterface $eventCdbXML
244
     */
245
    protected function setUDB2Data(
246
        EventCdbXMLInterface $eventCdbXML
247
    ) {
248
        $udb2Event = EventItemFactory::createEventFromCdbXml(
249
            $eventCdbXML->getCdbXmlNamespaceUri(),
250
            $eventCdbXML->getCdbXml()
251
        );
252
253
        $this->importWorkflowStatus($udb2Event);
254
        $this->labels = LabelCollection::fromKeywords($udb2Event->getKeywords(true));
255
    }
256
257
    /**
258
     * Update the major info.
259
     *
260
     * @param Title $title
261
     * @param EventType $eventType
262
     * @param Location $location
263
     * @param CalendarInterface $calendar
264
     * @param Theme|null $theme
265
     */
266
    public function updateMajorInfo(
267
        Title $title,
268
        EventType $eventType,
269
        Location $location,
270
        CalendarInterface $calendar,
271
        Theme $theme = null
272
    ) {
273
        $this->apply(new MajorInfoUpdated($this->eventId, $title, $eventType, $location, $calendar, $theme));
274
    }
275
276
    /**
277
     * @param LocationId $locationId
278
     */
279
    public function updateLocation(LocationId $locationId)
280
    {
281
        // For now no special business rules for updating the location of an event.
282
        $this->apply(new LocationUpdated($this->eventId, $locationId));
283
    }
284
285
    /**
286
     * @param Audience $audience
287
     */
288
    public function updateAudience(
289
        Audience $audience
290
    ) {
291
        if (is_null($this->audience) || !$this->audience->equals($audience)) {
292
            $this->apply(new AudienceUpdated(
293
                $this->eventId,
294
                $audience
295
            ));
296
        }
297
    }
298
299
    /**
300
     * @param AudienceUpdated $audienceUpdated
301
     */
302
    public function applyAudienceUpdated(AudienceUpdated $audienceUpdated)
303
    {
304
        $this->audience= $audienceUpdated->getAudience();
305
    }
306
307
    /**
308
     * @inheritDoc
309
     * @return ImagesImportedFromUDB2
310
     */
311
    protected function createImagesImportedFromUDB2(ImageCollection $images)
312
    {
313
        return new ImagesImportedFromUDB2($this->eventId, $images);
314
    }
315
316
    /**
317
     * @inheritDoc
318
     * @return ImagesUpdatedFromUDB2
319
     */
320
    protected function createImagesUpdatedFromUDB2(ImageCollection $images)
321
    {
322
        return new ImagesUpdatedFromUDB2($this->eventId, $images);
323
    }
324
325
    /**
326
     * @inheritdoc
327
     */
328
    public function updateWithCdbXml($cdbXml, $cdbXmlNamespaceUri)
329
    {
330
        $this->apply(
331
            new EventUpdatedFromUDB2(
332
                $this->eventId,
333
                $cdbXml,
334
                $cdbXmlNamespaceUri
335
            )
336
        );
337
    }
338
339
    /**
340
     * @param Label $label
341
     * @return LabelAdded
342
     */
343
    protected function createLabelAddedEvent(Label $label)
344
    {
345
        return new LabelAdded($this->eventId, $label);
346
    }
347
348
    /**
349
     * @param Label $label
350
     * @return LabelRemoved
351
     */
352
    protected function createLabelRemovedEvent(Label $label)
353
    {
354
        return new LabelRemoved($this->eventId, $label);
355
    }
356
357
    /**
358
     * @param Image $image
359
     * @return ImageAdded
360
     */
361
    protected function createImageAddedEvent(Image $image)
362
    {
363
        return new ImageAdded($this->eventId, $image);
364
    }
365
366
    /**
367
     * @param Image $image
368
     * @return ImageRemoved
369
     */
370
    protected function createImageRemovedEvent(Image $image)
371
    {
372
        return new ImageRemoved($this->eventId, $image);
373
    }
374
375
    /**
376
     * @param AbstractUpdateImage $updateImageCommand
377
     * @return ImageUpdated
378
     */
379
    protected function createImageUpdatedEvent(
380
        AbstractUpdateImage $updateImageCommand
381
    ) {
382
        return new ImageUpdated(
383
            $this->eventId,
384
            $updateImageCommand->getMediaObjectId(),
385
            $updateImageCommand->getDescription(),
386
            $updateImageCommand->getCopyrightHolder()
387
        );
388
    }
389
390
    /**
391
     * @param Image $image
392
     * @return MainImageSelected
393
     */
394
    protected function createMainImageSelectedEvent(Image $image)
395
    {
396
        return new MainImageSelected($this->eventId, $image);
397
    }
398
399
    /**
400
     * @param Language $language
401
     * @param StringLiteral $title
402
     * @return TitleTranslated
403
     */
404
    protected function createTitleTranslatedEvent(Language $language, StringLiteral $title)
405
    {
406
        return new TitleTranslated($this->eventId, $language, $title);
407
    }
408
409
    /**
410
     * @param Title $title
411
     * @return TitleUpdated
412
     */
413
    protected function createTitleUpdatedEvent(Title $title)
414
    {
415
        return new TitleUpdated($this->eventId, $title);
416
    }
417
418
    /**
419
     * @param Language $language
420
     * @param StringLiteral $description
421
     * @return DescriptionTranslated
422
     */
423
    protected function createDescriptionTranslatedEvent(Language $language, StringLiteral $description)
424
    {
425
        return new DescriptionTranslated($this->eventId, $language, $description);
426
    }
427
428
    /**
429
     * @param string $description
430
     * @return DescriptionUpdated
431
     */
432
    protected function createDescriptionUpdatedEvent($description)
433
    {
434
        return new DescriptionUpdated($this->eventId, $description);
435
    }
436
437
    /**
438
     * @inheritdoc
439
     */
440
    protected function createCalendarUpdatedEvent(Calendar $calendar)
441
    {
442
        return new CalendarUpdated($this->eventId, $calendar);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \CultuurNet\U...s->eventId, $calendar); (CultuurNet\UDB3\Event\Events\CalendarUpdated) is incompatible with the return type declared by the abstract method CultuurNet\UDB3\Offer\Of...ateCalendarUpdatedEvent of type CultuurNet\UDB3\Offer\AbstractCalendarUpdated.

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...
443
    }
444
445
    /**
446
     * @param string $typicalAgeRange
447
     * @return TypicalAgeRangeUpdated
448
     */
449
    protected function createTypicalAgeRangeUpdatedEvent($typicalAgeRange)
450
    {
451
        return new TypicalAgeRangeUpdated($this->eventId, $typicalAgeRange);
0 ignored issues
show
Documentation introduced by
$typicalAgeRange is of type string, but the function expects a object<CultuurNet\UDB3\Offer\AgeRange>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
452
    }
453
454
    /**
455
     * @return TypicalAgeRangeDeleted
456
     */
457
    protected function createTypicalAgeRangeDeletedEvent()
458
    {
459
        return new TypicalAgeRangeDeleted($this->eventId);
460
    }
461
462
    /**
463
     * @param string $organizerId
464
     * @return OrganizerUpdated
465
     */
466
    protected function createOrganizerUpdatedEvent($organizerId)
467
    {
468
        return new OrganizerUpdated($this->eventId, $organizerId);
469
    }
470
471
    /**
472
     * @param string $organizerId
473
     * @return OrganizerDeleted
474
     */
475
    protected function createOrganizerDeletedEvent($organizerId)
476
    {
477
        return new OrganizerDeleted($this->eventId, $organizerId);
478
    }
479
480
    /**
481
     * @param ContactPoint $contactPoint
482
     * @return ContactPointUpdated
483
     */
484
    protected function createContactPointUpdatedEvent(ContactPoint $contactPoint)
485
    {
486
        return new ContactPointUpdated($this->eventId, $contactPoint);
487
    }
488
489
    /**
490
     * @param BookingInfo $bookingInfo
491
     * @return BookingInfoUpdated
492
     */
493
    protected function createBookingInfoUpdatedEvent(BookingInfo $bookingInfo)
494
    {
495
        return new BookingInfoUpdated($this->eventId, $bookingInfo);
496
    }
497
498
    /**
499
     * @param PriceInfo $priceInfo
500
     * @return PriceInfoUpdated
501
     */
502
    protected function createPriceInfoUpdatedEvent(PriceInfo $priceInfo)
503
    {
504
        return new PriceInfoUpdated($this->eventId, $priceInfo);
505
    }
506
507
    /**
508
     * @return EventDeleted
509
     */
510
    protected function createOfferDeletedEvent()
511
    {
512
        return new EventDeleted($this->eventId);
513
    }
514
515
    /**
516
     * @inheritdoc
517
     */
518
    protected function createPublishedEvent(\DateTimeInterface $publicationDate)
519
    {
520
        return new Published($this->eventId, $publicationDate);
521
    }
522
523
    /**
524
     * @inheritdoc
525
     */
526
    protected function createApprovedEvent()
527
    {
528
        return new Approved($this->eventId);
529
    }
530
531
    /**
532
     * @inheritdoc
533
     */
534
    protected function createRejectedEvent(StringLiteral $reason)
535
    {
536
        return new Rejected($this->eventId, $reason);
537
    }
538
539
    /**
540
     * @inheritDoc
541
     */
542
    protected function createFlaggedAsDuplicate()
543
    {
544
        return new FlaggedAsDuplicate($this->eventId);
545
    }
546
547
    /**
548
     * @inheritDoc
549
     */
550
    protected function createFlaggedAsInappropriate()
551
    {
552
        return new FlaggedAsInappropriate($this->eventId);
553
    }
554
555
    /**
556
     * @inheritdoc
557
     */
558
    protected function createTypeUpdatedEvent(EventType $type)
559
    {
560
        return new TypeUpdated($this->eventId, $type);
561
    }
562
563
    /**
564
     * @inheritdoc
565
     */
566
    protected function createThemeUpdatedEvent(Theme $theme)
567
    {
568
        return new ThemeUpdated($this->eventId, $theme);
569
    }
570
571
    /**
572
     * @inheritdoc
573
     */
574
    protected function createFacilitiesUpdatedEvent(array $facilities)
575
    {
576
        return new FacilitiesUpdated($this->eventId, $facilities);
577
    }
578
579
    /**
580
     * Use reflection to get check if the aggregate has uncommitted events.
581
     * @return bool
582
     */
583
    private function hasUncommittedEvents()
584
    {
585
        $reflector = new \ReflectionClass(EventSourcedAggregateRoot::class);
586
        $property = $reflector->getProperty('uncommittedEvents');
587
588
        $property->setAccessible(true);
589
        $uncommittedEvents = $property->getValue($this);
590
591
        return !empty($uncommittedEvents);
592
    }
593
594
    public function conclude()
595
    {
596
        if (!$this->concluded) {
597
            $this->apply(new Concluded($this->eventId));
598
        }
599
    }
600
601
    /**
602
     * @param Concluded $concluded
603
     */
604
    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...
605
    {
606
        $this->concluded = true;
607
    }
608
}
609