Completed
Pull Request — master (#322)
by Luc
04:49
created

Event::createCalendarUpdatedEvent()   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\ImageAdded;
26
use CultuurNet\UDB3\Event\Events\ImageRemoved;
27
use CultuurNet\UDB3\Event\Events\Image\ImagesImportedFromUDB2;
28
use CultuurNet\UDB3\Event\Events\Image\ImagesUpdatedFromUDB2;
29
use CultuurNet\UDB3\Event\Events\ImageUpdated;
30
use CultuurNet\UDB3\Event\Events\LabelAdded;
31
use CultuurNet\UDB3\Event\Events\LabelRemoved;
32
use CultuurNet\UDB3\Event\Events\MainImageSelected;
33
use CultuurNet\UDB3\Event\Events\MajorInfoUpdated;
34
use CultuurNet\UDB3\Event\Events\Moderation\Approved;
35
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsDuplicate;
36
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsInappropriate;
37
use CultuurNet\UDB3\Event\Events\Moderation\Published;
38
use CultuurNet\UDB3\Event\Events\Moderation\Rejected;
39
use CultuurNet\UDB3\Event\Events\OrganizerDeleted;
40
use CultuurNet\UDB3\Event\Events\OrganizerUpdated;
41
use CultuurNet\UDB3\Event\Events\PriceInfoUpdated;
42
use CultuurNet\UDB3\Event\Events\TitleTranslated;
43
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted;
44
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated;
45
use CultuurNet\UDB3\Event\ValueObjects\Audience;
46
use CultuurNet\UDB3\Label;
47
use CultuurNet\UDB3\LabelCollection;
48
use CultuurNet\UDB3\Language;
49
use CultuurNet\UDB3\Location\Location;
50
use CultuurNet\UDB3\Media\ImageCollection;
51
use CultuurNet\UDB3\Media\Image;
52
use CultuurNet\UDB3\Offer\AbstractCalendarUpdated;
53
use CultuurNet\UDB3\Offer\Commands\Image\AbstractUpdateImage;
54
use CultuurNet\UDB3\Offer\Offer;
55
use CultuurNet\UDB3\Offer\WorkflowStatus;
56
use CultuurNet\UDB3\PriceInfo\PriceInfo;
57
use CultuurNet\UDB3\Theme;
58
use CultuurNet\UDB3\Title;
59
use ValueObjects\Identity\UUID;
60
use ValueObjects\StringLiteral\StringLiteral;
61
62
class Event extends Offer implements UpdateableWithCdbXmlInterface
63
{
64
    /**
65
     * @var string
66
     */
67
    protected $eventId;
68
69
    /**
70
     * @var Audience
71
     */
72
    private $audience;
73
74
    /**
75
     * @var boolean
76
     */
77
    private $concluded = false;
78
79
    const MAIN_LANGUAGE_CODE = 'nl';
80
81
    public function __construct()
82
    {
83
        parent::__construct();
84
    }
85
86
    /**
87
     * Factory method to create a new event.
88
     *
89
     * @param $eventId
90
     * @param Title $title
91
     * @param EventType $eventType
92
     * @param Location $location
93
     * @param CalendarInterface $calendar
94
     * @param Theme|null $theme
95
     * @param \DateTimeImmutable|null $publicationDate
96
     * @return Event
97
     */
98 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...
99
        $eventId,
100
        Title $title,
101
        EventType $eventType,
102
        Location $location,
103
        CalendarInterface $calendar,
104
        Theme $theme = null,
105
        \DateTimeImmutable $publicationDate = null
106
    ) {
107
        $event = new self();
108
109
        $event->apply(
110
            new EventCreated(
111
                $eventId,
112
                $title,
113
                $eventType,
114
                $location,
115
                $calendar,
116
                $theme,
117
                $publicationDate
118
            )
119
        );
120
121
        return $event;
122
    }
123
124
    /**
125
     * @param string $newEventId
126
     * @param CalendarInterface $calendar
127
     *
128
     * @return Event
129
     */
130
    public function copy($newEventId, CalendarInterface $calendar)
131
    {
132
        if ($this->hasUncommittedEvents()) {
133
            throw new \RuntimeException('I refuse to copy, there are uncommitted events present.');
134
        }
135
136
        // The copied event will have a playhead of the original event + 1
137
        $copy = clone $this;
138
139
        $copy->apply(
140
            new EventCopied(
141
                $newEventId,
142
                $this->eventId,
143
                $calendar
144
            )
145
        );
146
147
        return $copy;
148
    }
149
150
    /**
151
     * @param string $eventId
152
     * @param string $cdbXml
153
     * @param string $cdbXmlNamespaceUri
154
     * @return Event
155
     */
156
    public static function importFromUDB2(
157
        $eventId,
158
        $cdbXml,
159
        $cdbXmlNamespaceUri
160
    ) {
161
        $event = new self();
162
        $event->apply(
163
            new EventImportedFromUDB2(
164
                $eventId,
165
                $cdbXml,
166
                $cdbXmlNamespaceUri
167
            )
168
        );
169
170
        return $event;
171
    }
172
173
    /**
174
     * @param ImageCollection $images
175
     */
176
    public function updateImagesFromUDB2(ImageCollection $images)
177
    {
178
        $this->apply(new ImagesUpdatedFromUDB2($this->eventId, $images));
179
    }
180
181
    /**
182
     * @param ImageCollection $images
183
     */
184
    public function importImagesFromUDB2(ImageCollection $images)
185
    {
186
        $this->apply(new ImagesImportedFromUDB2($this->eventId, $images));
187
    }
188
189
    /**
190
     * {@inheritdoc}
191
     */
192
    public function getAggregateRootId()
193
    {
194
        return $this->eventId;
195
    }
196
197
    /**
198
     * @return UUID[]
199
     */
200
    public function getMediaObjects()
201
    {
202
        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...
203
    }
204
205
    protected function applyEventCreated(EventCreated $eventCreated)
206
    {
207
        $this->eventId = $eventCreated->getEventId();
208
        $this->workflowStatus = WorkflowStatus::DRAFT();
209
    }
210
211
    /**
212
     * @param EventCopied $eventCopied
213
     */
214
    protected function applyEventCopied(EventCopied $eventCopied)
215
    {
216
        $this->eventId = $eventCopied->getItemId();
217
        $this->workflowStatus = WorkflowStatus::DRAFT();
218
        $this->labels = new LabelCollection();
219
    }
220
221
    protected function applyEventImportedFromUDB2(
222
        EventImportedFromUDB2 $eventImported
223
    ) {
224
        $this->eventId = $eventImported->getEventId();
225
        $this->setUDB2Data($eventImported);
226
    }
227
228
    /**
229
     * @param EventUpdatedFromUDB2 $eventUpdated
230
     */
231
    protected function applyEventUpdatedFromUDB2(
232
        EventUpdatedFromUDB2 $eventUpdated
233
    ) {
234
        $this->setUDB2Data($eventUpdated);
235
    }
236
237
    /**
238
     * @param EventCdbXMLInterface $eventCdbXML
239
     */
240
    protected function setUDB2Data(
241
        EventCdbXMLInterface $eventCdbXML
242
    ) {
243
        $udb2Event = EventItemFactory::createEventFromCdbXml(
244
            $eventCdbXML->getCdbXmlNamespaceUri(),
245
            $eventCdbXML->getCdbXml()
246
        );
247
248
        $this->importWorkflowStatus($udb2Event);
249
        $this->labels = LabelCollection::fromKeywords($udb2Event->getKeywords(true));
250
    }
251
252
    /**
253
     * Update the major info.
254
     *
255
     * @param Title $title
256
     * @param EventType $eventType
257
     * @param Location $location
258
     * @param CalendarInterface $calendar
259
     * @param Theme|null $theme
260
     */
261
    public function updateMajorInfo(
262
        Title $title,
263
        EventType $eventType,
264
        Location $location,
265
        CalendarInterface $calendar,
266
        Theme $theme = null
267
    ) {
268
        $this->apply(new MajorInfoUpdated($this->eventId, $title, $eventType, $location, $calendar, $theme));
269
    }
270
271
    /**
272
     * @param Audience $audience
273
     */
274
    public function updateAudience(
275
        Audience $audience
276
    ) {
277
        if (is_null($this->audience) || !$this->audience->equals($audience)) {
278
            $this->apply(new AudienceUpdated(
279
                $this->eventId,
280
                $audience
281
            ));
282
        }
283
    }
284
285
    /**
286
     * @param AudienceUpdated $audienceUpdated
287
     */
288
    public function applyAudienceUpdated(AudienceUpdated $audienceUpdated)
289
    {
290
        $this->audience= $audienceUpdated->getAudience();
291
    }
292
293
    /**
294
     * @inheritDoc
295
     * @return ImagesImportedFromUDB2
296
     */
297
    protected function createImagesImportedFromUDB2(ImageCollection $images)
298
    {
299
        return new ImagesImportedFromUDB2($this->eventId, $images);
300
    }
301
302
    /**
303
     * @inheritDoc
304
     * @return ImagesUpdatedFromUDB2
305
     */
306
    protected function createImagesUpdatedFromUDB2(ImageCollection $images)
307
    {
308
        return new ImagesUpdatedFromUDB2($this->eventId, $images);
309
    }
310
311
    /**
312
     * @inheritdoc
313
     */
314
    public function updateWithCdbXml($cdbXml, $cdbXmlNamespaceUri)
315
    {
316
        $this->apply(
317
            new EventUpdatedFromUDB2(
318
                $this->eventId,
319
                $cdbXml,
320
                $cdbXmlNamespaceUri
321
            )
322
        );
323
    }
324
325
    /**
326
     * @param Label $label
327
     * @return LabelAdded
328
     */
329
    protected function createLabelAddedEvent(Label $label)
330
    {
331
        return new LabelAdded($this->eventId, $label);
332
    }
333
334
    /**
335
     * @param Label $label
336
     * @return LabelRemoved
337
     */
338
    protected function createLabelRemovedEvent(Label $label)
339
    {
340
        return new LabelRemoved($this->eventId, $label);
341
    }
342
343
    /**
344
     * @param Image $image
345
     * @return ImageAdded
346
     */
347
    protected function createImageAddedEvent(Image $image)
348
    {
349
        return new ImageAdded($this->eventId, $image);
350
    }
351
352
    /**
353
     * @param Image $image
354
     * @return ImageRemoved
355
     */
356
    protected function createImageRemovedEvent(Image $image)
357
    {
358
        return new ImageRemoved($this->eventId, $image);
359
    }
360
361
    /**
362
     * @param AbstractUpdateImage $updateImageCommand
363
     * @return ImageUpdated
364
     */
365
    protected function createImageUpdatedEvent(
366
        AbstractUpdateImage $updateImageCommand
367
    ) {
368
        return new ImageUpdated(
369
            $this->eventId,
370
            $updateImageCommand->getMediaObjectId(),
371
            $updateImageCommand->getDescription(),
372
            $updateImageCommand->getCopyrightHolder()
373
        );
374
    }
375
376
    /**
377
     * @param Image $image
378
     * @return MainImageSelected
379
     */
380
    protected function createMainImageSelectedEvent(Image $image)
381
    {
382
        return new MainImageSelected($this->eventId, $image);
383
    }
384
385
    /**
386
     * @param Language $language
387
     * @param StringLiteral $title
388
     * @return TitleTranslated
389
     */
390
    protected function createTitleTranslatedEvent(Language $language, StringLiteral $title)
391
    {
392
        return new TitleTranslated($this->eventId, $language, $title);
393
    }
394
395
    /**
396
     * @param Language $language
397
     * @param StringLiteral $description
398
     * @return DescriptionTranslated
399
     */
400
    protected function createDescriptionTranslatedEvent(Language $language, StringLiteral $description)
401
    {
402
        return new DescriptionTranslated($this->eventId, $language, $description);
403
    }
404
405
    /**
406
     * @param string $description
407
     * @return DescriptionUpdated
408
     */
409
    protected function createDescriptionUpdatedEvent($description)
410
    {
411
        return new DescriptionUpdated($this->eventId, $description);
412
    }
413
414
    /**
415
     * @inheritdoc
416
     */
417
    protected function createCalendarUpdatedEvent(Calendar $calendar)
418
    {
419
        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...
420
    }
421
422
    /**
423
     * @param string $typicalAgeRange
424
     * @return TypicalAgeRangeUpdated
425
     */
426
    protected function createTypicalAgeRangeUpdatedEvent($typicalAgeRange)
427
    {
428
        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...
429
    }
430
431
    /**
432
     * @return TypicalAgeRangeDeleted
433
     */
434
    protected function createTypicalAgeRangeDeletedEvent()
435
    {
436
        return new TypicalAgeRangeDeleted($this->eventId);
437
    }
438
439
    /**
440
     * @param string $organizerId
441
     * @return OrganizerUpdated
442
     */
443
    protected function createOrganizerUpdatedEvent($organizerId)
444
    {
445
        return new OrganizerUpdated($this->eventId, $organizerId);
446
    }
447
448
    /**
449
     * @param string $organizerId
450
     * @return OrganizerDeleted
451
     */
452
    protected function createOrganizerDeletedEvent($organizerId)
453
    {
454
        return new OrganizerDeleted($this->eventId, $organizerId);
455
    }
456
457
    /**
458
     * @param ContactPoint $contactPoint
459
     * @return ContactPointUpdated
460
     */
461
    protected function createContactPointUpdatedEvent(ContactPoint $contactPoint)
462
    {
463
        return new ContactPointUpdated($this->eventId, $contactPoint);
464
    }
465
466
    /**
467
     * @param BookingInfo $bookingInfo
468
     * @return BookingInfoUpdated
469
     */
470
    protected function createBookingInfoUpdatedEvent(BookingInfo $bookingInfo)
471
    {
472
        return new BookingInfoUpdated($this->eventId, $bookingInfo);
473
    }
474
475
    /**
476
     * @param PriceInfo $priceInfo
477
     * @return PriceInfoUpdated
478
     */
479
    protected function createPriceInfoUpdatedEvent(PriceInfo $priceInfo)
480
    {
481
        return new PriceInfoUpdated($this->eventId, $priceInfo);
482
    }
483
484
    /**
485
     * @return EventDeleted
486
     */
487
    protected function createOfferDeletedEvent()
488
    {
489
        return new EventDeleted($this->eventId);
490
    }
491
492
    /**
493
     * @inheritdoc
494
     */
495
    protected function createPublishedEvent(\DateTimeInterface $publicationDate)
496
    {
497
        return new Published($this->eventId, $publicationDate);
498
    }
499
500
    /**
501
     * @inheritdoc
502
     */
503
    protected function createApprovedEvent()
504
    {
505
        return new Approved($this->eventId);
506
    }
507
508
    /**
509
     * @inheritdoc
510
     */
511
    protected function createRejectedEvent(StringLiteral $reason)
512
    {
513
        return new Rejected($this->eventId, $reason);
514
    }
515
516
    /**
517
     * @inheritDoc
518
     */
519
    protected function createFlaggedAsDuplicate()
520
    {
521
        return new FlaggedAsDuplicate($this->eventId);
522
    }
523
524
    /**
525
     * @inheritDoc
526
     */
527
    protected function createFlaggedAsInappropriate()
528
    {
529
        return new FlaggedAsInappropriate($this->eventId);
530
    }
531
532
    /**
533
     * Use reflection to get check if the aggregate has uncommitted events.
534
     * @return bool
535
     */
536
    private function hasUncommittedEvents()
537
    {
538
        $reflector = new \ReflectionClass(EventSourcedAggregateRoot::class);
539
        $property = $reflector->getProperty('uncommittedEvents');
540
541
        $property->setAccessible(true);
542
        $uncommittedEvents = $property->getValue($this);
543
544
        return !empty($uncommittedEvents);
545
    }
546
547
    public function conclude()
548
    {
549
        if (!$this->concluded) {
550
            $this->apply(new Concluded($this->eventId));
551
        }
552
    }
553
554
    /**
555
     * @param Concluded $concluded
556
     */
557
    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...
558
    {
559
        $this->concluded = true;
560
    }
561
}
562