Completed
Pull Request — master (#270)
by Luc
06:03
created

EventLDProjector::applyEventCopied()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 16
nc 1
nop 2
1
<?php
2
3
namespace CultuurNet\UDB3\Event\ReadModel\JSONLD;
4
5
use Broadway\Domain\DateTime;
6
use Broadway\Domain\DomainMessage;
7
use Broadway\Domain\Metadata;
8
use Broadway\EventHandling\EventListenerInterface;
9
use CultuurNet\UDB3\Cdb\EventItemFactory;
10
use CultuurNet\UDB3\EntityNotFoundException;
11
use CultuurNet\UDB3\Event\Events\AudienceUpdated;
12
use CultuurNet\UDB3\Event\Events\BookingInfoUpdated;
13
use CultuurNet\UDB3\Event\Events\ContactPointUpdated;
14
use CultuurNet\UDB3\Event\Events\DescriptionTranslated;
15
use CultuurNet\UDB3\Event\Events\DescriptionUpdated;
16
use CultuurNet\UDB3\Event\Events\EventCopied;
17
use CultuurNet\UDB3\Event\Events\EventCreated;
18
use CultuurNet\UDB3\Event\Events\EventDeleted;
19
use CultuurNet\UDB3\Event\Events\EventImportedFromUDB2;
20
use CultuurNet\UDB3\Event\Events\EventUpdatedFromUDB2;
21
use CultuurNet\UDB3\Event\Events\ImageAdded;
22
use CultuurNet\UDB3\Event\Events\ImageRemoved;
23
use CultuurNet\UDB3\Event\Events\Image\ImagesImportedFromUDB2;
24
use CultuurNet\UDB3\Event\Events\Image\ImagesUpdatedFromUDB2;
25
use CultuurNet\UDB3\Event\Events\ImageUpdated;
26
use CultuurNet\UDB3\Event\Events\LabelAdded;
27
use CultuurNet\UDB3\Event\Events\LabelRemoved;
28
use CultuurNet\UDB3\Event\Events\MainImageSelected;
29
use CultuurNet\UDB3\Event\Events\MajorInfoUpdated;
30
use CultuurNet\UDB3\Event\Events\Moderation\Approved;
31
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsDuplicate;
32
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsInappropriate;
33
use CultuurNet\UDB3\Event\Events\Moderation\Published;
34
use CultuurNet\UDB3\Event\Events\Moderation\Rejected;
35
use CultuurNet\UDB3\Event\Events\OrganizerDeleted;
36
use CultuurNet\UDB3\Event\Events\OrganizerUpdated;
37
use CultuurNet\UDB3\Event\Events\PriceInfoUpdated;
38
use CultuurNet\UDB3\Event\Events\TitleTranslated;
39
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted;
40
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated;
41
use CultuurNet\UDB3\Event\EventType;
42
use CultuurNet\UDB3\Event\ReadModel\DocumentGoneException;
43
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
44
use CultuurNet\UDB3\Event\EventServiceInterface;
45
use CultuurNet\UDB3\Event\ValueObjects\Audience;
46
use CultuurNet\UDB3\Event\ValueObjects\AudienceType;
47
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
48
use CultuurNet\UDB3\Offer\AvailableTo;
49
use CultuurNet\UDB3\Offer\IriOfferIdentifierFactoryInterface;
50
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferLDProjector;
51
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferUpdate;
52
use CultuurNet\UDB3\Offer\WorkflowStatus;
53
use CultuurNet\UDB3\Organizer\OrganizerProjectedToJSONLD;
54
use CultuurNet\UDB3\OrganizerService;
55
use CultuurNet\UDB3\Place\Events\PlaceProjectedToJSONLD;
56
use CultuurNet\UDB3\PlaceService;
57
use CultuurNet\UDB3\ReadModel\JsonDocument;
58
use CultuurNet\UDB3\Theme;
59
use Symfony\Component\Serializer\SerializerInterface;
60
use ValueObjects\StringLiteral\StringLiteral;
61
use ValueObjects\Web\Url;
62
63
/**
64
 * Projects state changes on Event entities to a JSON-LD read model in a
65
 * document repository.
66
 *
67
 * Implements PlaceServiceInterface and OrganizerServiceInterface to do a double
68
 * dispatch with CdbXMLImporter.
69
 */
70
class EventLDProjector extends OfferLDProjector implements
71
    EventListenerInterface,
72
    PlaceServiceInterface,
73
    OrganizerServiceInterface
74
{
75
    /**
76
     * @var PlaceService
77
     */
78
    protected $placeService;
79
80
    /**
81
     * @var EventServiceInterface
82
     */
83
    protected $eventService;
84
85
    /**
86
     * @var IriOfferIdentifierFactoryInterface
87
     */
88
    protected $iriOfferIdentifierFactory;
89
90
    /**
91
     * @var CdbXMLImporter
92
     */
93
    protected $cdbXmlImporter;
94
95
    /**
96
     * @param DocumentRepositoryInterface $repository
97
     * @param IriGeneratorInterface $iriGenerator
98
     * @param EventServiceInterface $eventService
99
     * @param PlaceService $placeService
100
     * @param OrganizerService $organizerService
101
     * @param SerializerInterface $mediaObjectSerializer
102
     * @param IriOfferIdentifierFactoryInterface $iriOfferIdentifierFactory
103
     * @param CdbXMLImporter $cdbXMLImporter
104
     */
105
    public function __construct(
106
        DocumentRepositoryInterface $repository,
107
        IriGeneratorInterface $iriGenerator,
108
        EventServiceInterface $eventService,
109
        PlaceService $placeService,
110
        OrganizerService $organizerService,
111
        SerializerInterface $mediaObjectSerializer,
112
        IriOfferIdentifierFactoryInterface $iriOfferIdentifierFactory,
113
        CdbXMLImporter $cdbXMLImporter
114
    ) {
115
        parent::__construct(
116
            $repository,
117
            $iriGenerator,
118
            $organizerService,
119
            $mediaObjectSerializer
120
        );
121
122
        $this->placeService = $placeService;
123
        $this->eventService = $eventService;
124
        $this->cdbXMLImporter = $cdbXMLImporter;
0 ignored issues
show
Bug introduced by
The property cdbXMLImporter does not seem to exist. Did you mean cdbXmlImporter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
125
126
        $this->iriOfferIdentifierFactory = $iriOfferIdentifierFactory;
127
    }
128
129
    protected function applyOrganizerProjectedToJSONLD(OrganizerProjectedToJSONLD $organizerProjectedToJSONLD)
130
    {
131
        $eventIds = $this->eventsOrganizedByOrganizer(
132
            $organizerProjectedToJSONLD->getId()
133
        );
134
135
        $organizer = $this->organizerService->getEntity(
136
            $organizerProjectedToJSONLD->getId()
137
        );
138
139
        foreach ($eventIds as $eventId) {
140
            $document = $this->loadDocumentFromRepositoryByItemId(
141
                $eventId
142
            );
143
            $eventLD = $document->getBody();
144
145
            $newEventLD = clone $eventLD;
146
            $newEventLD->organizer = json_decode($organizer);
147
148
            if ($newEventLD != $eventLD) {
149
                $this->repository->save($document->withBody($newEventLD));
150
            }
151
        }
152
    }
153
154
    protected function applyPlaceProjectedToJSONLD(
155
        PlaceProjectedToJSONLD $placeProjectedToJSONLD
156
    ) {
157
        $identifier = $this->iriOfferIdentifierFactory->fromIri(
158
            Url::fromNative($placeProjectedToJSONLD->getIri())
159
        );
160
161
        $eventsLocatedAtPlace = $this->eventsLocatedAtPlace(
162
            $identifier->getId()
163
        );
164
165
        $placeJSONLD = $this->placeService->getEntity(
166
            $identifier->getId()
167
        );
168
169
        foreach ($eventsLocatedAtPlace as $eventId) {
170
            $document = $this->loadDocumentFromRepositoryByItemId(
171
                $eventId
172
            );
173
            $eventLD = $document->getBody();
174
175
            $newEventLD = clone $eventLD;
176
            $newEventLD->location = json_decode($placeJSONLD);
177
178
            if ($newEventLD != $eventLD) {
179
                $this->repository->save($document->withBody($newEventLD));
180
            }
181
        }
182
    }
183
184
    /**
185
     * @param string $organizerId
186
     * @return string[]
187
     */
188
    protected function eventsOrganizedByOrganizer($organizerId)
189
    {
190
        return $this->eventService->eventsOrganizedByOrganizer(
191
            $organizerId
192
        );
193
    }
194
195
    /**
196
     * @param string $placeId
197
     * @return string[]
198
     */
199
    protected function eventsLocatedAtPlace($placeId)
200
    {
201
        return $this->eventService->eventsLocatedAtPlace(
202
            $placeId
203
        );
204
    }
205
206
    /**
207
     * @param EventImportedFromUDB2 $eventImportedFromUDB2
208
     */
209
    protected function applyEventImportedFromUDB2(
210
        EventImportedFromUDB2 $eventImportedFromUDB2
211
    ) {
212
        $this->applyEventCdbXmlFromUDB2(
213
            $eventImportedFromUDB2->getEventId(),
214
            $eventImportedFromUDB2->getCdbXmlNamespaceUri(),
215
            $eventImportedFromUDB2->getCdbXml()
216
        );
217
    }
218
219
    /**
220
     * @param EventUpdatedFromUDB2 $eventUpdatedFromUDB2
221
     */
222
    protected function applyEventUpdatedFromUDB2(
223
        EventUpdatedFromUDB2 $eventUpdatedFromUDB2
224
    ) {
225
        $this->applyEventCdbXmlFromUDB2(
226
            $eventUpdatedFromUDB2->getEventId(),
227
            $eventUpdatedFromUDB2->getCdbXmlNamespaceUri(),
228
            $eventUpdatedFromUDB2->getCdbXml()
229
        );
230
    }
231
232
    /**
233
     * Helper function to save JSONLD document from entryapi cdbxml.
234
     *
235
     * @param string $eventId
236
     * @param string $cdbXmlNamespaceUri
237
     * @param string $cdbXml
238
     * @param DomainMessage $domainMessage
239
     */
240
    protected function applyEventFromCdbXml(
241
        $eventId,
242
        $cdbXmlNamespaceUri,
243
        $cdbXml,
244
        $domainMessage
245
    ) {
246
        $this->saveNewDocument(
247
            $eventId,
248
            function (\stdClass $eventLd) use ($eventId, $cdbXmlNamespaceUri, $cdbXml, $domainMessage) {
249
                $eventLd = $this->projectEventCdbXmlToObject(
250
                    $eventLd,
251
                    $eventId,
252
                    $cdbXmlNamespaceUri,
253
                    $cdbXml
254
                );
255
256
                // Add creation date and update date from metadata.
257
                $eventCreationDate = $domainMessage->getRecordedOn();
258
259
                $eventCreationString = $eventCreationDate->toString();
260
                $eventCreationDateTime = \DateTime::createFromFormat(
261
                    DateTime::FORMAT_STRING,
262
                    $eventCreationString
263
                );
264
                $eventLd->created = $eventCreationDateTime->format('c');
265
                $eventLd->modified = $eventCreationDateTime->format('c');
266
267
                // Add creator.
268
                $eventLd->creator = $this->getAuthorFromMetadata($domainMessage->getMetadata())->toNative();
269
270
                // Add publisher, which is the consumer name.
271
                $eventLd->publisher = $this->getConsumerFromMetadata($domainMessage->getMetadata())->toNative();
272
273
                return $eventLd;
274
            }
275
        );
276
    }
277
278
    /**
279
     * @param string $eventId
280
     * @param callable $fn
281
     */
282
    protected function saveNewDocument($eventId, callable $fn)
283
    {
284
        $document = $this
285
            ->newDocument($eventId)
286
            ->apply($fn);
287
288
        $this->repository->save($document);
289
    }
290
291
    /**
292
     * Helper function to save a JSON-LD document from cdbxml coming from UDB2.
293
     *
294
     * @param string $eventId
295
     * @param string $cdbXmlNamespaceUri
296
     * @param string $cdbXml
297
     */
298
    protected function applyEventCdbXmlFromUDB2(
299
        $eventId,
300
        $cdbXmlNamespaceUri,
301
        $cdbXml
302
    ) {
303
        $this->saveNewDocument(
304
            $eventId,
305
            function (\stdClass $eventLd) use ($cdbXmlNamespaceUri, $eventId, $cdbXml) {
306
                return $this->projectEventCdbXmlToObject(
307
                    $eventLd,
308
                    $eventId,
309
                    $cdbXmlNamespaceUri,
310
                    $cdbXml
311
                ) ;
312
            }
313
        );
314
    }
315
316
    /**
317
     * @param \stdClass $jsonLd
318
     * @param string $eventId
319
     * @param string $cdbXmlNamespaceUri
320
     * @param string $cdbXml
321
     *
322
     * @return \stdClass
323
     */
324
    protected function projectEventCdbXmlToObject(
325
        \stdClass $jsonLd,
326
        $eventId,
327
        $cdbXmlNamespaceUri,
328
        $cdbXml
329
    ) {
330
        $udb2Event = EventItemFactory::createEventFromCdbXml(
331
            $cdbXmlNamespaceUri,
332
            $cdbXml
333
        );
334
335
        $jsonLd = $this->cdbXMLImporter->documentWithCdbXML(
0 ignored issues
show
Bug introduced by
The property cdbXMLImporter does not seem to exist. Did you mean cdbXmlImporter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
336
            $jsonLd,
337
            $udb2Event,
338
            $this,
339
            $this,
340
            $this->slugger
341
        );
342
343
        // Because we can not properly track media coming from UDB2 we simply
344
        // ignore it and give priority to content added through UDB3.
345
        // It's possible that an event has been deleted in udb3, but never
346
        // in udb2. If an update comes for that event from udb2, it should
347
        // be imported again. This is intended by design.
348
        // @see https://jira.uitdatabank.be/browse/III-1092
349
        try {
350
            $document = $this->loadDocumentFromRepositoryByItemId($eventId);
351
        } catch (DocumentGoneException $documentGoneException) {
352
            $document = $this->newDocument($eventId);
353
        }
354
355
        $media = $this->UDB3Media($document);
356
        if (!empty($media)) {
357
            $jsonLd->mediaObject = $media;
358
        }
359
360
        // Because UDB2 cannot keep track of UDB3 places as a location
361
        // ignore it and give priority to content added through UDB3.
362
        $location = $this->UDB3Location($document);
363
        if (!empty($location)) {
364
            $jsonLd->location = $location;
365
        }
366
367
        return $jsonLd;
368
    }
369
370
    /**
371
     * Return the media of an event if it already exists.
372
     *
373
     * @param JsonDocument $document The JsonDocument.
374
     *
375
     * @return array
376
     *  A list of media objects.
377
     */
378
    private function UDB3Media($document)
379
    {
380
        $media = [];
381
382
        if ($document) {
383
            $item = $document->getBody();
384
            // At the moment we do not include any media coming from UDB2.
385
            // If the mediaObject property contains data it's coming from UDB3.
386
            $item->mediaObject = isset($item->mediaObject) ? $item->mediaObject : [];
387
        }
388
389
        return $media;
390
    }
391
392
    /**
393
     * Return the location of an event if it already exists.
394
     *
395
     * @param JsonDocument $document The JsonDocument.
396
     *
397
     * @return array|null
398
     *  The location
399
     */
400
    private function UDB3Location($document)
401
    {
402
        $location = null;
403
404
        if ($document) {
405
            $item = $document->getBody();
406
            $location = isset($item->location) ? $item->location : null;
407
        }
408
409
        return $location;
410
    }
411
412
    /**
413
     * @param EventCreated $eventCreated
414
     * @param DomainMessage $domainMessage
415
     */
416
    protected function applyEventCreated(
417
        EventCreated $eventCreated,
418
        DomainMessage $domainMessage
419
    ) {
420
        $this->saveNewDocument(
421
            $eventCreated->getEventId(),
422
            function (\stdClass $jsonLD) use ($eventCreated, $domainMessage) {
423
                $jsonLD->{'@id'} = $this->iriGenerator->iri(
424
                    $eventCreated->getEventId()
425
                );
426
                $jsonLD->name['nl'] = $eventCreated->getTitle();
427
                $jsonLD->location = array(
428
                        '@type' => 'Place',
429
                    ) + (array)$this->placeJSONLD(
430
                        $eventCreated->getLocation()->getCdbid()
431
                    );
432
433
                $calendarJsonLD = $eventCreated->getCalendar()->toJsonLd();
434
                $jsonLD = (object)array_merge((array)$jsonLD, $calendarJsonLD);
435
436
                $availableTo = AvailableTo::createFromCalendar($eventCreated->getCalendar());
437
                $jsonLD->availableTo = (string)$availableTo;
438
439
                // Same as.
440
                $jsonLD->sameAs = $this->generateSameAs(
441
                    $eventCreated->getEventId(),
442
                    reset($jsonLD->name)
443
                );
444
445
                $eventType = $eventCreated->getEventType();
446
                $jsonLD->terms = [
447
                    $eventType->toJsonLd()
448
                ];
449
450
                $theme = $eventCreated->getTheme();
451
                if (!empty($theme)) {
452
                    $jsonLD->terms[] = $theme->toJsonLd();
453
                }
454
455
                $recordedOn = $domainMessage->getRecordedOn()->toString();
456
                $jsonLD->created = \DateTime::createFromFormat(
457
                    DateTime::FORMAT_STRING,
458
                    $recordedOn
459
                )->format('c');
460
                $jsonLD->modified = $jsonLD->created;
461
462
                $metaData = $domainMessage->getMetadata()->serialize();
463 View Code Duplication
                if (isset($metaData['user_email'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
464
                    $jsonLD->creator = $metaData['user_email'];
465
                } elseif (isset($metaData['user_nick'])) {
466
                    $jsonLD->creator = $metaData['user_nick'];
467
                }
468
469
                $jsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
470
471
                $defaultAudience = new Audience(AudienceType::EVERYONE());
472
                $jsonLD->audience = $defaultAudience->serialize();
473
474
                return $jsonLD;
475
            }
476
        );
477
    }
478
479
    /**
480
     * @param EventCopied $eventCopied
481
     * @param DomainMessage $domainMessage
482
     */
483
    protected function applyEventCopied(
484
        EventCopied $eventCopied,
485
        DomainMessage $domainMessage
0 ignored issues
show
Unused Code introduced by
The parameter $domainMessage 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...
486
    ) {
487
        $originalDocument = $this->repository->get($eventCopied->getOriginalEventId());
488
489
        // Set new calendar.
490
        $originalDocument->apply(OfferUpdate::calendar($eventCopied->getCalendar()));
0 ignored issues
show
Compatibility introduced by
$eventCopied->getCalendar() of type object<CultuurNet\UDB3\CalendarInterface> is not a sub-type of object<CultuurNet\UDB3\Calendar>. It seems like you assume a concrete implementation of the interface CultuurNet\UDB3\CalendarInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
491
492
        $eventJsonLD = $originalDocument->getBody();
493
494
        // Set the id.
495
        $eventJsonLD->{'@id'} = $this->iriGenerator->iri($eventCopied->getItemId());
496
497
        // Set workflow status.
498
        $eventJsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
499
500
        // Remove labels.
501
        unset($eventJsonLD->labels);
502
        unset($eventJsonLD->hiddenLabels);
503
504
        // Set available to and from.
505
        $availableTo = AvailableTo::createFromCalendar($eventCopied->getCalendar());
506
        $eventJsonLD->availableTo = (string) $availableTo;
507
        unset($eventJsonLD->availableFrom);
508
509
        $newDocument = new JsonDocument($eventCopied->getItemId());
510
        $newDocument = $newDocument->withBody($eventJsonLD);
511
        $this->repository->save($newDocument);
512
    }
513
514
    /**
515
     * @param EventDeleted $eventDeleted
516
     */
517
    protected function applyEventDeleted(EventDeleted $eventDeleted)
518
    {
519
        $this->repository->remove($eventDeleted->getItemId());
520
    }
521
522
    /**
523
     * Apply the major info updated command to the projector.
524
     */
525
    protected function applyMajorInfoUpdated(MajorInfoUpdated $majorInfoUpdated)
526
    {
527
        $document = $this
528
            ->loadDocumentFromRepository($majorInfoUpdated)
529
            ->apply(OfferUpdate::calendar($majorInfoUpdated->getCalendar()));
0 ignored issues
show
Compatibility introduced by
$majorInfoUpdated->getCalendar() of type object<CultuurNet\UDB3\CalendarInterface> is not a sub-type of object<CultuurNet\UDB3\Calendar>. It seems like you assume a concrete implementation of the interface CultuurNet\UDB3\CalendarInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
530
531
        $jsonLD = $document->getBody();
532
533
        $jsonLD->name->nl = $majorInfoUpdated->getTitle();
534
        $jsonLD->location = array(
535
          '@type' => 'Place',
536
        ) + (array)$this->placeJSONLD($majorInfoUpdated->getLocation()->getCdbid());
537
538
        $availableTo = AvailableTo::createFromCalendar($majorInfoUpdated->getCalendar());
539
        $jsonLD->availableTo = (string)$availableTo;
540
541
        // Remove old theme and event type.
542
        $jsonLD->terms = array_filter($jsonLD->terms, function ($term) {
543
            return $term->domain !== EventType::DOMAIN &&  $term->domain !== Theme::DOMAIN;
544
        });
545
        $jsonLD->terms = array_values($jsonLD->terms);
546
547
        $eventType = $majorInfoUpdated->getEventType();
548
        $jsonLD->terms[] = $eventType->toJsonLd();
549
550
        $theme = $majorInfoUpdated->getTheme();
551
        if (!empty($theme)) {
552
            $jsonLD->terms[] = $theme->toJsonLd();
553
        }
554
555
        $this->repository->save($document->withBody($jsonLD));
556
    }
557
558
    /**
559
     * @param AudienceUpdated $audienceUpdated
560
     */
561
    protected function applyAudienceUpdated(AudienceUpdated $audienceUpdated)
562
    {
563
        $document = $this->loadDocumentFromRepository($audienceUpdated);
564
        $jsonLD = $document->getBody();
565
566
        $jsonLD->audience = $audienceUpdated->getAudience()->serialize();
567
568
        $this->repository->save($document->withBody($jsonLD));
569
    }
570
571
    /**
572
     * @inheritdoc
573
     */
574
    public function placeJSONLD($placeId)
575
    {
576
        if (empty($placeId)) {
577
            return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type declared by the interface CultuurNet\UDB3\Event\Re...eInterface::placeJSONLD of type stdClass.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
578
        }
579
580
        try {
581
            $placeJSONLD = $this->placeService->getEntity(
582
                $placeId
583
            );
584
585
            return json_decode($placeJSONLD);
586
        } catch (EntityNotFoundException $e) {
587
            // In case the place can not be found at the moment, just add its ID
588
            return array(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('@id' => $t...ervice->iri($placeId)); (array<string,string>) is incompatible with the return type declared by the interface CultuurNet\UDB3\Event\Re...eInterface::placeJSONLD of type stdClass.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
589
                '@id' => $this->placeService->iri($placeId)
590
            );
591
        } catch (DocumentGoneException $e) {
592
            // In case the place can not be found at the moment, just add its ID
593
            return array(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('@id' => $t...ervice->iri($placeId)); (array<string,string>) is incompatible with the return type declared by the interface CultuurNet\UDB3\Event\Re...eInterface::placeJSONLD of type stdClass.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
594
                '@id' => $this->placeService->iri($placeId)
595
            );
596
        }
597
    }
598
599
    private function generateSameAs($eventId, $name)
600
    {
601
        $eventSlug = $this->slugger->slug($name);
602
        return array(
603
            'http://www.uitinvlaanderen.be/agenda/e/' . $eventSlug . '/' . $eventId,
604
        );
605
    }
606
607 View Code Duplication
    private function getAuthorFromMetadata(Metadata $metadata)
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...
608
    {
609
        $properties = $metadata->serialize();
610
611
        if (isset($properties['user_nick'])) {
612
            return new StringLiteral($properties['user_nick']);
613
        }
614
    }
615
616 View Code Duplication
    private function getConsumerFromMetadata(Metadata $metadata)
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...
617
    {
618
        $properties = $metadata->serialize();
619
620
        if (isset($properties['consumer']['name'])) {
621
            return new StringLiteral($properties['consumer']['name']);
622
        }
623
    }
624
625
    /**
626
     * @return string
627
     */
628
    protected function getLabelAddedClassName()
629
    {
630
        return LabelAdded::class;
631
    }
632
633
    /**
634
     * @return string
635
     */
636
    protected function getLabelRemovedClassName()
637
    {
638
        return LabelRemoved::class;
639
    }
640
641
    /**
642
     * @return string
643
     */
644
    protected function getImageAddedClassName()
645
    {
646
        return ImageAdded::class;
647
    }
648
649
    /**
650
     * @return string
651
     */
652
    protected function getImageRemovedClassName()
653
    {
654
        return ImageRemoved::class;
655
    }
656
657
    /**
658
     * @return string
659
     */
660
    protected function getImageUpdatedClassName()
661
    {
662
        return ImageUpdated::class;
663
    }
664
665
    protected function getMainImageSelectedClassName()
666
    {
667
        return MainImageSelected::class;
668
    }
669
670
    /**
671
     * @return string
672
     */
673
    protected function getTitleTranslatedClassName()
674
    {
675
        return TitleTranslated::class;
676
    }
677
678
    /**
679
     * @return string
680
     */
681
    protected function getDescriptionTranslatedClassName()
682
    {
683
        return DescriptionTranslated::class;
684
    }
685
686
    /**
687
     * @return string
688
     */
689
    protected function getOrganizerUpdatedClassName()
690
    {
691
        return OrganizerUpdated::class;
692
    }
693
694
    /**
695
     * @return string
696
     */
697
    protected function getOrganizerDeletedClassName()
698
    {
699
        return OrganizerDeleted::class;
700
    }
701
702
    protected function getBookingInfoUpdatedClassName()
703
    {
704
        return BookingInfoUpdated::class;
705
    }
706
707
    /**
708
     * @return string
709
     */
710
    protected function getPriceInfoUpdatedClassName()
711
    {
712
        return PriceInfoUpdated::class;
713
    }
714
715
    protected function getContactPointUpdatedClassName()
716
    {
717
        return ContactPointUpdated::class;
718
    }
719
720
    protected function getDescriptionUpdatedClassName()
721
    {
722
        return DescriptionUpdated::class;
723
    }
724
725
    protected function getTypicalAgeRangeUpdatedClassName()
726
    {
727
        return TypicalAgeRangeUpdated::class;
728
    }
729
730
    protected function getTypicalAgeRangeDeletedClassName()
731
    {
732
        return TypicalAgeRangeDeleted::class;
733
    }
734
735
    protected function getPublishedClassName()
736
    {
737
        return Published::class;
738
    }
739
740
    protected function getApprovedClassName()
741
    {
742
        return Approved::class;
743
    }
744
745
    protected function getRejectedClassName()
746
    {
747
        return Rejected::class;
748
    }
749
750
    protected function getFlaggedAsDuplicateClassName()
751
    {
752
        return FlaggedAsDuplicate::class;
753
    }
754
755
    protected function getFlaggedAsInappropriateClassName()
756
    {
757
        return FlaggedAsInappropriate::class;
758
    }
759
760
    protected function getImagesImportedFromUdb2ClassName()
761
    {
762
        return ImagesImportedFromUDB2::class;
763
    }
764
765
    protected function getImagesUpdatedFromUdb2ClassName()
766
    {
767
        return ImagesUpdatedFromUDB2::class;
768
    }
769
}
770