Completed
Pull Request — master (#309)
by Luc
08:47
created

PlaceLDProjector::applyPlaceCreated()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 59
Code Lines 36

Duplication

Lines 5
Ratio 8.47 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 5
loc 59
rs 8.7117
cc 5
eloc 36
nc 12
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace CultuurNet\UDB3\Place\ReadModel\JSONLD;
4
5
use Broadway\Domain\DateTime;
6
use Broadway\Domain\DomainMessage;
7
use Broadway\EventHandling\EventListenerInterface;
8
use CultuurNet\UDB3\Actor\ActorImportedFromUDB2;
9
use CultuurNet\UDB3\Address\Address;
10
use CultuurNet\UDB3\Cdb\ActorItemFactory;
11
use CultuurNet\UDB3\CulturefeedSlugger;
12
use CultuurNet\UDB3\EntityServiceInterface;
13
use CultuurNet\UDB3\Event\EventType;
14
use CultuurNet\UDB3\Event\ReadModel\DocumentGoneException;
15
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
16
use CultuurNet\UDB3\Facility;
17
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
18
use CultuurNet\UDB3\Language;
19
use CultuurNet\UDB3\Offer\AvailableTo;
20
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferLDProjector;
21
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\OfferUpdate;
22
use CultuurNet\UDB3\Offer\WorkflowStatus;
23
use CultuurNet\UDB3\Place\Events\AddressTranslated;
24
use CultuurNet\UDB3\Place\Events\AddressUpdated;
25
use CultuurNet\UDB3\Place\Events\BookingInfoUpdated;
26
use CultuurNet\UDB3\Place\Events\ContactPointUpdated;
27
use CultuurNet\UDB3\Place\Events\DescriptionTranslated;
28
use CultuurNet\UDB3\Place\Events\DescriptionUpdated;
29
use CultuurNet\UDB3\Place\Events\FacilitiesUpdated;
30
use CultuurNet\UDB3\Place\Events\GeoCoordinatesUpdated;
31
use CultuurNet\UDB3\Place\Events\Image\ImagesImportedFromUDB2;
32
use CultuurNet\UDB3\Place\Events\Image\ImagesUpdatedFromUDB2;
33
use CultuurNet\UDB3\Place\Events\ImageAdded;
34
use CultuurNet\UDB3\Place\Events\ImageRemoved;
35
use CultuurNet\UDB3\Place\Events\ImageUpdated;
36
use CultuurNet\UDB3\Place\Events\LabelAdded;
37
use CultuurNet\UDB3\Place\Events\LabelRemoved;
38
use CultuurNet\UDB3\Place\Events\MainImageSelected;
39
use CultuurNet\UDB3\Place\Events\MajorInfoUpdated;
40
use CultuurNet\UDB3\Place\Events\Moderation\Approved;
41
use CultuurNet\UDB3\Place\Events\Moderation\FlaggedAsDuplicate;
42
use CultuurNet\UDB3\Place\Events\Moderation\FlaggedAsInappropriate;
43
use CultuurNet\UDB3\Place\Events\Moderation\Published;
44
use CultuurNet\UDB3\Place\Events\Moderation\Rejected;
45
use CultuurNet\UDB3\Place\Events\OrganizerDeleted;
46
use CultuurNet\UDB3\Place\Events\OrganizerUpdated;
47
use CultuurNet\UDB3\Place\Events\PlaceCreated;
48
use CultuurNet\UDB3\Place\Events\PlaceDeleted;
49
use CultuurNet\UDB3\Place\Events\PlaceImportedFromUDB2;
50
use CultuurNet\UDB3\Place\Events\PlaceUpdatedFromUDB2;
51
use CultuurNet\UDB3\Place\Events\PriceInfoUpdated;
52
use CultuurNet\UDB3\Place\Events\TitleTranslated;
53
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeDeleted;
54
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeUpdated;
55
use CultuurNet\UDB3\Place\PlaceEvent;
56
use CultuurNet\UDB3\ReadModel\JsonDocument;
57
use CultuurNet\UDB3\Theme;
58
use Symfony\Component\Serializer\SerializerInterface;
59
60
/**
61
 * Projects state changes on Place entities to a JSON-LD read model in a
62
 * document repository.
63
 */
64
class PlaceLDProjector extends OfferLDProjector implements EventListenerInterface
65
{
66
    /**
67
     * @var CdbXMLImporter
68
     */
69
    protected $cdbXMLImporter;
70
71
    /**
72
     * @param DocumentRepositoryInterface $repository
73
     * @param IriGeneratorInterface $iriGenerator
74
     * @param EntityServiceInterface $organizerService
75
     * @param SerializerInterface $mediaObjectSerializer
76
     * @param CdbXMLImporter $cdbXMLImporter
77
     */
78
    public function __construct(
79
        DocumentRepositoryInterface $repository,
80
        IriGeneratorInterface $iriGenerator,
81
        EntityServiceInterface $organizerService,
82
        SerializerInterface $mediaObjectSerializer,
83
        CdbXMLImporter $cdbXMLImporter
84
    ) {
85
        parent::__construct(
86
            $repository,
87
            $iriGenerator,
88
            $organizerService,
89
            $mediaObjectSerializer
90
        );
91
92
        $this->slugger = new CulturefeedSlugger();
93
        $this->cdbXMLImporter = $cdbXMLImporter;
94
    }
95
96
    protected function getImagesImportedFromUdb2ClassName()
97
    {
98
        return ImagesImportedFromUDB2::class;
99
    }
100
101
    protected function getImagesUpdatedFromUdb2ClassName()
102
    {
103
        return ImagesUpdatedFromUDB2::class;
104
    }
105
106
    /**
107
     * @param PlaceImportedFromUDB2 $placeImportedFromUDB2
108
     */
109
    protected function applyPlaceImportedFromUDB2(
110
        PlaceImportedFromUDB2 $placeImportedFromUDB2
111
    ) {
112
        $this->projectActorImportedFromUDB2($placeImportedFromUDB2);
113
    }
114
115
    /**
116
     * @param PlaceUpdatedFromUDB2 $placeUpdatedFromUDB2
117
     */
118
    protected function applyPlaceUpdatedFromUDB2(
119
        PlaceUpdatedFromUDB2 $placeUpdatedFromUDB2
120
    ) {
121
        $this->projectActorImportedFromUDB2($placeUpdatedFromUDB2);
122
    }
123
124
    /**
125
     * @param ActorImportedFromUDB2 $actorImportedFromUDB2
126
     */
127
    protected function projectActorImportedFromUDB2(
128
        ActorImportedFromUDB2 $actorImportedFromUDB2
129
    ) {
130
        $actorId = $actorImportedFromUDB2->getActorId();
131
132
        $udb2Actor = ActorItemFactory::createActorFromCdbXml(
133
            $actorImportedFromUDB2->getCdbXmlNamespaceUri(),
134
            $actorImportedFromUDB2->getCdbXml()
135
        );
136
137
        try {
138
            $document = $this->loadPlaceDocumentFromRepositoryById($actorId);
139
        } catch (DocumentGoneException $e) {
140
            $document = $this->newDocument($actorId);
141
        }
142
143
        $actorLd = $document->getBody();
144
145
        $actorLd = $this->cdbXMLImporter->documentWithCdbXML(
146
            $actorLd,
147
            $udb2Actor
148
        );
149
150
        $this->setMainLanguage($actorLd, new Language('nl'));
151
152
        // Remove geocoordinates, because the address might have been
153
        // updated and we might get inconsistent data if it takes a while
154
        // before the new geocoordinates are added.
155
        // In case geocoding fails, it's also easier to look for places that
156
        // have no geocoordinates instead of places that have incorrect
157
        // geocoordinates.
158
        unset($actorLd->geo);
159
160
        $this->repository->save($document->withBody($actorLd));
161
    }
162
163
    /**
164
     * @param string $id
165
     * @return JsonDocument
166
     */
167 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...
168
    {
169
        $document = new JsonDocument($id);
170
171
        $placeLd = $document->getBody();
172
        $placeLd->{'@id'} = $this->iriGenerator->iri($id);
173
        $placeLd->{'@context'} = '/contexts/place';
174
175
        return $document->withBody($placeLd);
176
    }
177
178
    /**
179
     * @param PlaceCreated $placeCreated
180
     * @param DomainMessage $domainMessage
181
     */
182
    protected function applyPlaceCreated(PlaceCreated $placeCreated, DomainMessage $domainMessage)
183
    {
184
        $document = $this->newDocument($placeCreated->getPlaceId());
185
186
        $jsonLD = $document->getBody();
187
188
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
189
            $placeCreated->getPlaceId()
190
        );
191
192
        $this->setMainLanguage($jsonLD, new Language('nl'));
193
194
        if (empty($jsonLD->name)) {
195
            $jsonLD->name = new \stdClass();
196
        }
197
198
        $jsonLD->name->nl = $placeCreated->getTitle();
199
200
        $this->setAddress(
201
            $jsonLD,
202
            $placeCreated->getAddress(),
203
            $this->getMainLanguage($jsonLD)
204
        );
205
206
        $calendarJsonLD = $placeCreated->getCalendar()->toJsonLd();
207
        $jsonLD = (object) array_merge((array) $jsonLD, $calendarJsonLD);
208
209
        $availableTo = AvailableTo::createFromCalendar($placeCreated->getCalendar());
210
        $jsonLD->availableTo = (string)$availableTo;
211
212
        $eventType = $placeCreated->getEventType();
213
        $jsonLD->terms = [
214
            $eventType->toJsonLd()
215
        ];
216
217
        $theme = $placeCreated->getTheme();
218
        if (!empty($theme)) {
219
            $jsonLD->terms[] = $theme->toJsonLd();
220
        }
221
222
        $recordedOn = $domainMessage->getRecordedOn()->toString();
223
        $jsonLD->created = \DateTime::createFromFormat(
224
            DateTime::FORMAT_STRING,
225
            $recordedOn
226
        )->format('c');
227
228
        $jsonLD->modified = $jsonLD->created;
229
230
        $metaData = $domainMessage->getMetadata()->serialize();
231 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...
232
            $jsonLD->creator = $metaData['user_email'];
233
        } elseif (isset($metaData['user_nick'])) {
234
            $jsonLD->creator = $metaData['user_nick'];
235
        }
236
237
        $jsonLD->workflowStatus = WorkflowStatus::DRAFT()->getName();
238
239
        $this->repository->save($document->withBody($jsonLD));
240
    }
241
242
    /**
243
     * @param PlaceDeleted $placeDeleted
244
     */
245
    protected function applyPlaceDeleted(PlaceDeleted $placeDeleted)
246
    {
247
        $this->repository->remove($placeDeleted->getItemId());
248
    }
249
250
    /**
251
     * Apply the major info updated command to the projector.
252
     * @param MajorInfoUpdated $majorInfoUpdated
253
     */
254
    protected function applyMajorInfoUpdated(MajorInfoUpdated $majorInfoUpdated)
255
    {
256
        $document = $this
257
            ->loadPlaceDocumentFromRepository($majorInfoUpdated)
258
            ->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...
259
260
        $jsonLD = $document->getBody();
261
262
        $jsonLD->name->nl = $majorInfoUpdated->getTitle();
263
264
        $this->setAddress(
265
            $jsonLD,
266
            $majorInfoUpdated->getAddress(),
267
            $this->getMainLanguage($jsonLD)
268
        );
269
270
        $availableTo = AvailableTo::createFromCalendar($majorInfoUpdated->getCalendar());
271
        $jsonLD->availableTo = (string)$availableTo;
272
273
        // Remove old theme and event type.
274
        $jsonLD->terms = array_filter($jsonLD->terms, function ($term) {
275
            return $term->domain !== EventType::DOMAIN &&  $term->domain !== Theme::DOMAIN;
276
        });
277
278
        $eventType = $majorInfoUpdated->getEventType();
279
        $jsonLD->terms = [
280
            $eventType->toJsonLd()
281
        ];
282
283
        $theme = $majorInfoUpdated->getTheme();
284
        if (!empty($theme)) {
285
            $jsonLD->terms[] = $theme->toJsonLd();
286
        }
287
288
        // Remove geocoordinates, because the address might have been
289
        // updated and we might get inconsistent data if it takes a while
290
        // before the new geocoordinates are added.
291
        // In case geocoding fails, it's also easier to look for places that
292
        // have no geocoordinates instead of places that have incorrect
293
        // geocoordinates.
294
        unset($jsonLD->geo);
295
296
        $this->repository->save($document->withBody($jsonLD));
297
    }
298
299
    /**
300
     * @param AddressUpdated $addressUpdated
301
     */
302 View Code Duplication
    protected function applyAddressUpdated(AddressUpdated $addressUpdated)
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...
303
    {
304
        $document = $this->loadPlaceDocumentFromRepository($addressUpdated);
305
        $jsonLD = $document->getBody();
306
        $this->setAddress($jsonLD, $addressUpdated->getAddress(), $this->getMainLanguage($jsonLD));
307
        $this->repository->save($document->withBody($jsonLD));
308
    }
309
310
    /**
311
     * @param AddressTranslated $addressTranslated
312
     */
313 View Code Duplication
    protected function applyAddressTranslated(AddressTranslated $addressTranslated)
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...
314
    {
315
        $document = $this->loadPlaceDocumentFromRepository($addressTranslated);
316
        $jsonLD = $document->getBody();
317
        $this->setAddress($jsonLD, $addressTranslated->getAddress(), $addressTranslated->getLanguage());
318
        $this->repository->save($document->withBody($jsonLD));
319
    }
320
321
    /**
322
     * @param \stdClass $jsonLd
323
     * @param Address $address
324
     * @param Language $language
325
     */
326
    protected function setAddress(\stdClass $jsonLd, Address $address, Language $language)
327
    {
328
        if (!isset($jsonLd->address)) {
329
            $jsonLd->address = new \stdClass();
330
        }
331
332
        if (isset($jsonLd->address->streetAddress)) {
333
            // Old projections have their address in a single language.
334
            // Set the old address as the address for the main language before
335
            // updating it or adding another address.
336
            // @replay_i18n
337
            // @see https://jira.uitdatabank.be/browse/III-2201
338
            $mainLanguageCode = $this->getMainLanguage($jsonLd)->getCode();
339
            $jsonLd->address = (object) [
340
                $mainLanguageCode => $jsonLd->address,
341
            ];
342
        }
343
344
        $jsonLd->address->{$language->getCode()} = $address->toJsonLd();
345
    }
346
347
    /**
348
     * Apply the facilitiesupdated event to the place repository.
349
     * @param FacilitiesUpdated $facilitiesUpdated
350
     */
351
    protected function applyFacilitiesUpdated(FacilitiesUpdated $facilitiesUpdated)
352
    {
353
        $document = $this->loadPlaceDocumentFromRepository($facilitiesUpdated);
354
355
        $placeLd = $document->getBody();
356
357
        $terms = isset($placeLd->terms) ? $placeLd->terms : array();
358
359
        // Remove all old facilities + get numeric keys.
360
        $terms = array_values(array_filter(
361
            $terms,
362
            function ($term) {
363
                return $term->domain !== Facility::DOMAIN;
364
            }
365
        ));
366
367
        // Add the new facilities.
368
        foreach ($facilitiesUpdated->getFacilities() as $facility) {
369
            $terms[] = $facility->toJsonLd();
370
        }
371
372
        $placeLd->terms = $terms;
373
374
        $this->repository->save($document->withBody($placeLd));
375
    }
376
377
    /**
378
     * @param GeoCoordinatesUpdated $geoCoordinatesUpdated
379
     */
380
    protected function applyGeoCoordinatesUpdated(GeoCoordinatesUpdated $geoCoordinatesUpdated)
381
    {
382
        $document = $this->loadPlaceDocumentFromRepository($geoCoordinatesUpdated);
383
384
        $placeLd = $document->getBody();
385
386
        $placeLd->geo = (object) [
387
            'latitude' => $geoCoordinatesUpdated->getCoordinates()->getLatitude()->toDouble(),
388
            'longitude' => $geoCoordinatesUpdated->getCoordinates()->getLongitude()->toDouble(),
389
        ];
390
391
        $this->repository->save($document->withBody($placeLd));
392
    }
393
394
    /**
395
     * @param PlaceEvent $place
396
     * @return JsonDocument
397
     */
398
    protected function loadPlaceDocumentFromRepository(PlaceEvent $place)
399
    {
400
        $document = $this->repository->get($place->getPlaceId());
401
402
        if (!$document) {
403
            return $this->newDocument($place->getPlaceId());
404
        }
405
406
        return $document;
407
    }
408
409
    /**
410
     * @param string $itemId
411
     * @return JsonDocument
412
     */
413
    protected function loadPlaceDocumentFromRepositoryById($itemId)
414
    {
415
        $document = $this->repository->get($itemId);
416
417
        if (!$document) {
418
            return $this->newDocument($itemId);
419
        }
420
421
        return $document;
422
    }
423
424
    /**
425
     * @return string
426
     */
427
    protected function getLabelAddedClassName()
428
    {
429
        return LabelAdded::class;
430
    }
431
432
    /**
433
     * @return string
434
     */
435
    protected function getLabelRemovedClassName()
436
    {
437
        return LabelRemoved::class;
438
    }
439
440
    /**
441
     * @return string
442
     */
443
    protected function getImageAddedClassName()
444
    {
445
        return ImageAdded::class;
446
    }
447
448
    /**
449
     * @return string
450
     */
451
    protected function getImageRemovedClassName()
452
    {
453
        return ImageRemoved::class;
454
    }
455
456
    /**
457
     * @return string
458
     */
459
    protected function getImageUpdatedClassName()
460
    {
461
        return ImageUpdated::class;
462
    }
463
464
    protected function getMainImageSelectedClassName()
465
    {
466
        return MainImageSelected::class;
467
    }
468
469
    /**
470
     * @return string
471
     */
472
    protected function getTitleTranslatedClassName()
473
    {
474
        return TitleTranslated::class;
475
    }
476
477
    /**
478
     * @return string
479
     */
480
    protected function getDescriptionTranslatedClassName()
481
    {
482
        return DescriptionTranslated::class;
483
    }
484
485
    /**
486
     * @return string
487
     */
488
    protected function getOrganizerUpdatedClassName()
489
    {
490
        return OrganizerUpdated::class;
491
    }
492
493
    /**
494
     * @return string
495
     */
496
    protected function getOrganizerDeletedClassName()
497
    {
498
        return OrganizerDeleted::class;
499
    }
500
501
    protected function getBookingInfoUpdatedClassName()
502
    {
503
        return BookingInfoUpdated::class;
504
    }
505
506
    /**
507
     * @return string
508
     */
509
    protected function getPriceInfoUpdatedClassName()
510
    {
511
        return PriceInfoUpdated::class;
512
    }
513
514
    protected function getContactPointUpdatedClassName()
515
    {
516
        return ContactPointUpdated::class;
517
    }
518
519
    protected function getDescriptionUpdatedClassName()
520
    {
521
        return DescriptionUpdated::class;
522
    }
523
524
    protected function getTypicalAgeRangeUpdatedClassName()
525
    {
526
        return TypicalAgeRangeUpdated::class;
527
    }
528
529
    protected function getTypicalAgeRangeDeletedClassName()
530
    {
531
        return TypicalAgeRangeDeleted::class;
532
    }
533
534
    protected function getPublishedClassName()
535
    {
536
        return Published::class;
537
    }
538
539
    protected function getApprovedClassName()
540
    {
541
        return Approved::class;
542
    }
543
544
    protected function getRejectedClassName()
545
    {
546
        return Rejected::class;
547
    }
548
549
    protected function getFlaggedAsDuplicateClassName()
550
    {
551
        return FlaggedAsDuplicate::class;
552
    }
553
554
    protected function getFlaggedAsInappropriateClassName()
555
    {
556
        return FlaggedAsInappropriate::class;
557
    }
558
}
559