Completed
Push — master ( 694b48...b76062 )
by Luc
434:27 queued 424:47
created

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