Completed
Pull Request — master (#386)
by Kristof
05:37
created

EventLDProjector::getPriceInfoUpdatedClassName()   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 0
1
<?php
2
3
namespace CultuurNet\UDB3\Event\ReadModel\JSONLD;
4
5
use Broadway\Domain\DomainMessage;
6
use Broadway\Domain\Metadata;
7
use Broadway\EventHandling\EventListenerInterface;
8
use CultuurNet\UDB3\Cdb\EventItemFactory;
9
use CultuurNet\UDB3\EntityNotFoundException;
10
use CultuurNet\UDB3\Event\Events\AudienceUpdated;
11
use CultuurNet\UDB3\Event\Events\BookingInfoUpdated;
12
use CultuurNet\UDB3\Event\Events\CalendarUpdated;
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\FacilitiesUpdated;
22
use CultuurNet\UDB3\Event\Events\GeoCoordinatesUpdated;
23
use CultuurNet\UDB3\Event\Events\Image\ImagesImportedFromUDB2;
24
use CultuurNet\UDB3\Event\Events\Image\ImagesUpdatedFromUDB2;
25
use CultuurNet\UDB3\Event\Events\ImageAdded;
26
use CultuurNet\UDB3\Event\Events\ImageRemoved;
27
use CultuurNet\UDB3\Event\Events\ImageUpdated;
28
use CultuurNet\UDB3\Event\Events\LabelAdded;
29
use CultuurNet\UDB3\Event\Events\LabelRemoved;
30
use CultuurNet\UDB3\Event\Events\LocationUpdated;
31
use CultuurNet\UDB3\Event\Events\MainImageSelected;
32
use CultuurNet\UDB3\Event\Events\MajorInfoUpdated;
33
use CultuurNet\UDB3\Event\Events\Moderation\Approved;
34
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsDuplicate;
35
use CultuurNet\UDB3\Event\Events\Moderation\FlaggedAsInappropriate;
36
use CultuurNet\UDB3\Event\Events\Moderation\Published;
37
use CultuurNet\UDB3\Event\Events\Moderation\Rejected;
38
use CultuurNet\UDB3\Event\Events\OrganizerDeleted;
39
use CultuurNet\UDB3\Event\Events\OrganizerUpdated;
40
use CultuurNet\UDB3\Event\Events\PriceInfoUpdated;
41
use CultuurNet\UDB3\Event\Events\ThemeUpdated;
42
use CultuurNet\UDB3\Event\Events\TitleTranslated;
43
use CultuurNet\UDB3\Event\Events\TitleUpdated;
44
use CultuurNet\UDB3\Event\Events\TypeUpdated;
45
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeDeleted;
46
use CultuurNet\UDB3\Event\Events\TypicalAgeRangeUpdated;
47
use CultuurNet\UDB3\Event\EventType;
48
use CultuurNet\UDB3\Event\ReadModel\DocumentGoneException;
49
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
50
use CultuurNet\UDB3\Event\ValueObjects\Audience;
51
use CultuurNet\UDB3\Event\ValueObjects\AudienceType;
52
use CultuurNet\UDB3\EventListener\EventSpecification;
53
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
54
use CultuurNet\UDB3\Language;
55
use CultuurNet\UDB3\Offer\AvailableTo;
56
use CultuurNet\UDB3\Offer\IriOfferIdentifierFactoryInterface;
57
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferLDProjector;
58
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferUpdate;
59
use CultuurNet\UDB3\Offer\WorkflowStatus;
60
use CultuurNet\UDB3\OrganizerService;
61
use CultuurNet\UDB3\PlaceService;
62
use CultuurNet\UDB3\ReadModel\JsonDocument;
63
use CultuurNet\UDB3\ReadModel\JsonDocumentMetaDataEnricherInterface;
64
use CultuurNet\UDB3\RecordedOn;
65
use CultuurNet\UDB3\Theme;
66
use Symfony\Component\Serializer\SerializerInterface;
67
use ValueObjects\StringLiteral\StringLiteral;
68
69
/**
70
 * Projects state changes on Event entities to a JSON-LD read model in a
71
 * document repository.
72
 *
73
 * Implements PlaceServiceInterface and OrganizerServiceInterface to do a double
74
 * dispatch with CdbXMLImporter.
75
 */
76
class EventLDProjector extends OfferLDProjector implements
77
    EventListenerInterface,
78
    PlaceServiceInterface,
79
    OrganizerServiceInterface
80
{
81
    /**
82
     * @var PlaceService
83
     */
84
    protected $placeService;
85
86
    /**
87
     * @var IriOfferIdentifierFactoryInterface
88
     */
89
    protected $iriOfferIdentifierFactory;
90
91
    /**
92
     * @var CdbXMLImporter
93
     */
94
    protected $cdbXMLImporter;
95
96
    /**
97
     * @param DocumentRepositoryInterface $repository
98
     * @param IriGeneratorInterface $iriGenerator
99
     * @param PlaceService $placeService
100
     * @param OrganizerService $organizerService
101
     * @param SerializerInterface $mediaObjectSerializer
102
     * @param IriOfferIdentifierFactoryInterface $iriOfferIdentifierFactory
103
     * @param CdbXMLImporter $cdbXMLImporter
104
     * @param JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
105
     * @param string[] $basePriceTranslations
106
     */
107
    public function __construct(
108
        DocumentRepositoryInterface $repository,
109
        IriGeneratorInterface $iriGenerator,
110
        PlaceService $placeService,
111
        OrganizerService $organizerService,
112
        SerializerInterface $mediaObjectSerializer,
113
        IriOfferIdentifierFactoryInterface $iriOfferIdentifierFactory,
114
        CdbXMLImporter $cdbXMLImporter,
115
        JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher,
116
        array $basePriceTranslations
117
    ) {
118
        parent::__construct(
119
            $repository,
120
            $iriGenerator,
121
            $organizerService,
122
            $mediaObjectSerializer,
123
            $jsonDocumentMetaDataEnricher,
124
            $basePriceTranslations
125
        );
126
127
        $this->placeService = $placeService;
128
        $this->cdbXMLImporter = $cdbXMLImporter;
129
130
        $this->iriOfferIdentifierFactory = $iriOfferIdentifierFactory;
131
    }
132
133
    /**
134
     * @param string $id
135
     * @return JsonDocument
136
     */
137 View Code Duplication
    protected function newDocument($id)
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...
138
    {
139
        $document = new JsonDocument($id);
140
141
        $offerLd = $document->getBody();
142
        $offerLd->{'@id'} = $this->iriGenerator->iri($id);
143
        $offerLd->{'@context'} = '/contexts/event';
144
145
        return $document->withBody($offerLd);
146
    }
147
148
    /**
149
     * @param EventImportedFromUDB2 $eventImportedFromUDB2
150
     * @return JsonDocument
151
     */
152
    protected function applyEventImportedFromUDB2(
153
        EventImportedFromUDB2 $eventImportedFromUDB2
154
    ) {
155
        return $this->applyEventCdbXmlFromUDB2(
156
            $eventImportedFromUDB2->getEventId(),
157
            $eventImportedFromUDB2->getCdbXmlNamespaceUri(),
158
            $eventImportedFromUDB2->getCdbXml()
159
        );
160
    }
161
162
    /**
163
     * @param EventUpdatedFromUDB2 $eventUpdatedFromUDB2
164
     * @return JsonDocument
165
     */
166
    protected function applyEventUpdatedFromUDB2(
167
        EventUpdatedFromUDB2 $eventUpdatedFromUDB2
168
    ) {
169
        return $this->applyEventCdbXmlFromUDB2(
170
            $eventUpdatedFromUDB2->getEventId(),
171
            $eventUpdatedFromUDB2->getCdbXmlNamespaceUri(),
172
            $eventUpdatedFromUDB2->getCdbXml()
173
        );
174
    }
175
176
    /**
177
     * Helper function to save a JSON-LD document from cdbxml coming from UDB2.
178
     *
179
     * @param string $eventId
180
     * @param string $cdbXmlNamespaceUri
181
     * @param string $cdbXml
182
     * @return JsonDocument
183
     */
184
    protected function applyEventCdbXmlFromUDB2(
185
        $eventId,
186
        $cdbXmlNamespaceUri,
187
        $cdbXml
188
    ) {
189
        $document = $this->newDocument($eventId);
190
191
        $eventLd = $this->projectEventCdbXmlToObject(
192
            $document->getBody(),
193
            $eventId,
194
            $cdbXmlNamespaceUri,
195
            $cdbXml
196
        );
197
198
        return $document->withBody($eventLd);
199
    }
200
201
    /**
202
     * @param \stdClass $jsonLd
203
     * @param string $eventId
204
     * @param string $cdbXmlNamespaceUri
205
     * @param string $cdbXml
206
     * @return \stdClass
207
     * @throws \CultureFeed_Cdb_ParseException
208
     */
209
    protected function projectEventCdbXmlToObject(
210
        \stdClass $jsonLd,
211
        $eventId,
212
        $cdbXmlNamespaceUri,
213
        $cdbXml
214
    ) {
215
        $udb2Event = EventItemFactory::createEventFromCdbXml(
216
            $cdbXmlNamespaceUri,
217
            $cdbXml
218
        );
219
220
        $jsonLd = $this->cdbXMLImporter->documentWithCdbXML(
221
            $jsonLd,
222
            $udb2Event,
223
            $this,
224
            $this,
225
            $this->slugger
226
        );
227
228
        // Because we can not properly track media coming from UDB2 we simply
229
        // ignore it and give priority to content added through UDB3.
230
        // It's possible that an event has been deleted in udb3, but never
231
        // in udb2. If an update comes for that event from udb2, it should
232
        // be imported again. This is intended by design.
233
        // @see https://jira.uitdatabank.be/browse/III-1092
234
        try {
235
            $document = $this->loadDocumentFromRepositoryByItemId($eventId);
236
        } catch (DocumentGoneException $documentGoneException) {
237
            $document = $this->newDocument($eventId);
238
        }
239
240
        $media = $this->UDB3Media($document);
241
        if (!empty($media)) {
242
            $jsonLd->mediaObject = $media;
243
        }
244
245
        // When importing from UDB2 the main language is always nl.
246
        // When updating from UDB2 never change the main language.
247
        if (!isset($jsonLd->mainLanguage)) {
248
            $this->setMainLanguage($jsonLd, new Language('nl'));
249
        }
250
251
        // Because UDB2 cannot keep track of UDB3 places as a location
252
        // ignore it and give priority to content added through UDB3.
253
        $location = $this->UDB3Location($document);
254
        if (!empty($location)) {
255
            $jsonLd->location = $location;
256
        }
257
258
        return $jsonLd;
259
    }
260
261
    /**
262
     * Return the media of an event if it already exists.
263
     *
264
     * @param JsonDocument $document The JsonDocument.
265
     *
266
     * @return array
267
     *  A list of media objects.
268
     */
269
    private function UDB3Media($document)
270
    {
271
        $media = [];
272
273
        if ($document) {
274
            $item = $document->getBody();
275
            // At the moment we do not include any media coming from UDB2.
276
            // If the mediaObject property contains data it's coming from UDB3.
277
            $item->mediaObject = isset($item->mediaObject) ? $item->mediaObject : [];
278
        }
279
280
        return $media;
281
    }
282
283
    /**
284
     * Return the location of an event if it already exists.
285
     *
286
     * @param JsonDocument $document The JsonDocument.
287
     *
288
     * @return array|null
289
     *  The location
290
     */
291
    private function UDB3Location($document)
292
    {
293
        $location = null;
294
295
        if ($document) {
296
            $item = $document->getBody();
297
            $location = isset($item->location) ? $item->location : null;
298
        }
299
300
        return $location;
301
    }
302
303
    /**
304
     * @param EventCreated $eventCreated
305
     * @param DomainMessage $domainMessage
306
     * @return JsonDocument
307
     */
308
    protected function applyEventCreated(
309
        EventCreated $eventCreated,
310
        DomainMessage $domainMessage
311
    ) {
312
        $document = $this->newDocument($eventCreated->getEventId());
313
        $jsonLD = $document->getBody();
314
315
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
316
            $eventCreated->getEventId()
317
        );
318
319
        $this->setMainLanguage($jsonLD, $eventCreated->getMainLanguage());
320
321
        $jsonLD->name[$eventCreated->getMainLanguage()->getCode()] = $eventCreated->getTitle();
322
        $jsonLD->location = array(
323
                '@type' => 'Place',
324
            ) + (array)$this->placeJSONLD(
325
                $eventCreated->getLocation()->getCdbid()
326
            );
327
328
        $calendarJsonLD = $eventCreated->getCalendar()->toJsonLd();
329
        $jsonLD = (object)array_merge((array)$jsonLD, $calendarJsonLD);
330
331
        $availableTo = AvailableTo::createFromCalendar($eventCreated->getCalendar());
332
        $jsonLD->availableTo = (string)$availableTo;
333
334
        // Same as.
335
        $jsonLD->sameAs = $this->generateSameAs(
336
            $eventCreated->getEventId(),
337
            reset($jsonLD->name)
338
        );
339
340
        $eventType = $eventCreated->getEventType();
341
        $jsonLD->terms = [
342
            $eventType->toJsonLd(),
343
        ];
344
345
        $theme = $eventCreated->getTheme();
346
        if (!empty($theme)) {
347
            $jsonLD->terms[] = $theme->toJsonLd();
348
        }
349
350
        $created = RecordedOn::fromDomainMessage($domainMessage);
351
        $jsonLD->created = $created->toString();
352
        $jsonLD->modified = $created->toString();
353
354
        $metaData = $domainMessage->getMetadata()->serialize();
355 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...
356
            $jsonLD->creator = $metaData['user_email'];
357
        } elseif (isset($metaData['user_nick'])) {
358
            $jsonLD->creator = $metaData['user_nick'];
359
        }
360
361
        $jsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
362
363
        $defaultAudience = new Audience(AudienceType::EVERYONE());
364
        $jsonLD->audience = $defaultAudience->serialize();
365
366
        return $document->withBody($jsonLD);
367
    }
368
369
    /**
370
     * @param EventCopied $eventCopied
371
     * @param DomainMessage $domainMessage
372
     * @return JsonDocument
373
     */
374
    protected function applyEventCopied(
375
        EventCopied $eventCopied,
376
        DomainMessage $domainMessage
377
    ) {
378
        $originalDocument = $this->repository->get($eventCopied->getOriginalEventId());
379
        $eventJsonLD = $originalDocument->getBody();
380
381
        // Set the created and modified date.
382
        $created = RecordedOn::fromDomainMessage($domainMessage);
383
        $eventJsonLD->created = $created->toString();
384
        $eventJsonLD->modified = $created->toString();
385
386
        // Set the creator.
387
        $eventJsonLD->creator = $this->getAuthorFromMetadata($domainMessage->getMetadata())->toNative();
388
389
        // Set the id.
390
        $eventJsonLD->{'@id'} = $this->iriGenerator->iri($eventCopied->getItemId());
391
392
        // Set the new calendar.
393
        $eventJsonLD = (object) array_merge(
394
            (array) $eventJsonLD,
395
            $eventCopied->getCalendar()->toJsonLd()
396
        );
397
398
        // Set workflow status.
399
        $eventJsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
400
401
        // Remove labels.
402
        unset($eventJsonLD->labels);
403
        unset($eventJsonLD->hiddenLabels);
404
405
        // Set available to and from.
406
        $availableTo = AvailableTo::createFromCalendar($eventCopied->getCalendar());
407
        $eventJsonLD->availableTo = (string) $availableTo;
408
        unset($eventJsonLD->availableFrom);
409
410
        $newDocument = new JsonDocument($eventCopied->getItemId());
411
        $newDocument = $newDocument->withBody($eventJsonLD);
412
        return $newDocument;
413
    }
414
415
    /**
416
     * @param EventDeleted $eventDeleted
417
     * @return null
418
     */
419 View Code Duplication
    protected function applyEventDeleted(EventDeleted $eventDeleted)
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...
420
    {
421
        $document = $this->loadDocumentFromRepository($eventDeleted);
422
423
        $jsonLD = $document->getBody();
424
425
        $jsonLD->workflowStatus = WorkflowStatus::DELETED()->getName();
426
427
        return $document->withBody($jsonLD);
428
    }
429
430
    /**
431
     * Apply the major info updated command to the projector.
432
     * @param MajorInfoUpdated $majorInfoUpdated
433
     * @return JsonDocument
434
     */
435
    protected function applyMajorInfoUpdated(MajorInfoUpdated $majorInfoUpdated)
436
    {
437
        $document = $this
438
            ->loadDocumentFromRepository($majorInfoUpdated)
439
            ->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...
440
441
        $jsonLD = $document->getBody();
442
443
        $jsonLD->name->{$this->getMainLanguage($jsonLD)->getCode()} = $majorInfoUpdated->getTitle();
444
445
        $jsonLD->location = array(
446
          '@type' => 'Place',
447
        ) + (array)$this->placeJSONLD($majorInfoUpdated->getLocation()->getCdbid());
448
449
        $availableTo = AvailableTo::createFromCalendar($majorInfoUpdated->getCalendar());
450
        $jsonLD->availableTo = (string)$availableTo;
451
452
        // Remove old theme and event type.
453
        $jsonLD->terms = array_filter($jsonLD->terms, function ($term) {
454
            return $term->domain !== EventType::DOMAIN &&  $term->domain !== Theme::DOMAIN;
455
        });
456
        $jsonLD->terms = array_values($jsonLD->terms);
457
458
        $eventType = $majorInfoUpdated->getEventType();
459
        $jsonLD->terms[] = $eventType->toJsonLd();
460
461
        $theme = $majorInfoUpdated->getTheme();
462
        if (!empty($theme)) {
463
            $jsonLD->terms[] = $theme->toJsonLd();
464
        }
465
466
        return $document->withBody($jsonLD);
467
    }
468
469
    /**
470
     * @param LocationUpdated $locationUpdated
471
     *
472
     * @return JsonDocument
473
     */
474
    public function applyLocationUpdated(LocationUpdated $locationUpdated)
475
    {
476
        $document = $this->loadDocumentFromRepository($locationUpdated);
477
478
        $jsonLD = $document->getBody();
479
480
        $jsonLD->location = [
481
            '@type' => 'Place',
482
         ] + (array) $this->placeJSONLD($locationUpdated->getLocationId()->toNative());
483
484
        return $document->withBody($jsonLD);
485
    }
486
487
    /**
488
     * @param GeoCoordinatesUpdated $geoCoordinatesUpdated
489
     * @return JsonDocument
490
     */
491 View Code Duplication
    protected function applyGeoCoordinatesUpdated(GeoCoordinatesUpdated $geoCoordinatesUpdated)
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...
492
    {
493
        $document = $this->loadDocumentFromRepositoryByItemId($geoCoordinatesUpdated->getItemId());
494
495
        $eventLd = $document->getBody();
496
497
        $eventLd->location->geo = (object) [
498
            'latitude' => $geoCoordinatesUpdated->getCoordinates()->getLatitude()->toDouble(),
499
            'longitude' => $geoCoordinatesUpdated->getCoordinates()->getLongitude()->toDouble(),
500
        ];
501
502
        return $document->withBody($eventLd);
503
    }
504
505
    /**
506
     * @param AudienceUpdated $audienceUpdated
507
     * @return JsonDocument
508
     */
509
    protected function applyAudienceUpdated(AudienceUpdated $audienceUpdated)
510
    {
511
        $document = $this->loadDocumentFromRepository($audienceUpdated);
512
        $jsonLD = $document->getBody();
513
514
        $jsonLD->audience = $audienceUpdated->getAudience()->serialize();
515
516
        return $document->withBody($jsonLD);
517
    }
518
519
    /**
520
     * @inheritdoc
521
     */
522
    public function placeJSONLD($placeId)
523
    {
524
        if (empty($placeId)) {
525
            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...
526
        }
527
528
        try {
529
            $placeJSONLD = $this->placeService->getEntity(
530
                $placeId
531
            );
532
533
            return json_decode($placeJSONLD);
534
        } catch (EntityNotFoundException $e) {
535
            // In case the place can not be found at the moment, just add its ID
536
            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...
537
                '@id' => $this->placeService->iri($placeId),
538
            );
539
        } catch (DocumentGoneException $e) {
540
            // In case the place can not be found at the moment, just add its ID
541
            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...
542
                '@id' => $this->placeService->iri($placeId),
543
            );
544
        }
545
    }
546
547
    private function generateSameAs($eventId, $name)
548
    {
549
        $eventSlug = $this->slugger->slug($name);
550
        return array(
551
            'http://www.uitinvlaanderen.be/agenda/e/' . $eventSlug . '/' . $eventId,
552
        );
553
    }
554
555 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...
556
    {
557
        $properties = $metadata->serialize();
558
559
        if (isset($properties['user_nick'])) {
560
            return new StringLiteral($properties['user_nick']);
561
        }
562
    }
563
564 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...
565
    {
566
        $properties = $metadata->serialize();
567
568
        if (isset($properties['consumer']['name'])) {
569
            return new StringLiteral($properties['consumer']['name']);
570
        }
571
    }
572
573
    /**
574
     * @return string
575
     */
576
    protected function getLabelAddedClassName()
577
    {
578
        return LabelAdded::class;
579
    }
580
581
    /**
582
     * @return string
583
     */
584
    protected function getLabelRemovedClassName()
585
    {
586
        return LabelRemoved::class;
587
    }
588
589
    /**
590
     * @return string
591
     */
592
    protected function getImageAddedClassName()
593
    {
594
        return ImageAdded::class;
595
    }
596
597
    /**
598
     * @return string
599
     */
600
    protected function getImageRemovedClassName()
601
    {
602
        return ImageRemoved::class;
603
    }
604
605
    /**
606
     * @return string
607
     */
608
    protected function getImageUpdatedClassName()
609
    {
610
        return ImageUpdated::class;
611
    }
612
613
    protected function getMainImageSelectedClassName()
614
    {
615
        return MainImageSelected::class;
616
    }
617
618
    /**
619
     * @return string
620
     */
621
    protected function getTitleTranslatedClassName()
622
    {
623
        return TitleTranslated::class;
624
    }
625
626
    /**
627
     * @return string
628
     */
629
    protected function getDescriptionTranslatedClassName()
630
    {
631
        return DescriptionTranslated::class;
632
    }
633
634
    /**
635
     * @return string
636
     */
637
    protected function getOrganizerUpdatedClassName()
638
    {
639
        return OrganizerUpdated::class;
640
    }
641
642
    /**
643
     * @return string
644
     */
645
    protected function getOrganizerDeletedClassName()
646
    {
647
        return OrganizerDeleted::class;
648
    }
649
650
    protected function getBookingInfoUpdatedClassName()
651
    {
652
        return BookingInfoUpdated::class;
653
    }
654
655
    /**
656
     * @return string
657
     */
658
    protected function getPriceInfoUpdatedClassName()
659
    {
660
        return PriceInfoUpdated::class;
661
    }
662
663
    protected function getContactPointUpdatedClassName()
664
    {
665
        return ContactPointUpdated::class;
666
    }
667
668
    protected function getDescriptionUpdatedClassName()
669
    {
670
        return DescriptionUpdated::class;
671
    }
672
673
    protected function getCalendarUpdatedClassName()
674
    {
675
        return CalendarUpdated::class;
676
    }
677
678
    protected function getTypicalAgeRangeUpdatedClassName()
679
    {
680
        return TypicalAgeRangeUpdated::class;
681
    }
682
683
    protected function getTypicalAgeRangeDeletedClassName()
684
    {
685
        return TypicalAgeRangeDeleted::class;
686
    }
687
688
    protected function getPublishedClassName()
689
    {
690
        return Published::class;
691
    }
692
693
    protected function getApprovedClassName()
694
    {
695
        return Approved::class;
696
    }
697
698
    protected function getRejectedClassName()
699
    {
700
        return Rejected::class;
701
    }
702
703
    protected function getFlaggedAsDuplicateClassName()
704
    {
705
        return FlaggedAsDuplicate::class;
706
    }
707
708
    protected function getFlaggedAsInappropriateClassName()
709
    {
710
        return FlaggedAsInappropriate::class;
711
    }
712
713
    protected function getImagesImportedFromUdb2ClassName()
714
    {
715
        return ImagesImportedFromUDB2::class;
716
    }
717
718
    protected function getImagesUpdatedFromUdb2ClassName()
719
    {
720
        return ImagesUpdatedFromUDB2::class;
721
    }
722
723
    protected function getTitleUpdatedClassName()
724
    {
725
        return TitleUpdated::class;
726
    }
727
728
    protected function getTypeUpdatedClassName()
729
    {
730
        return TypeUpdated::class;
731
    }
732
733
    protected function getThemeUpdatedClassName()
734
    {
735
        return ThemeUpdated::class;
736
    }
737
738
    protected function getFacilitiesUpdatedClassName()
739
    {
740
        return FacilitiesUpdated::class;
741
    }
742
}
743