Completed
Push — master ( dc82d8...d048aa )
by Kristof
14:05
created

PlaceLDProjector::applyImageUpdated()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 38
Code Lines 21

Duplication

Lines 15
Ratio 39.47 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
dl 15
loc 38
c 3
b 1
f 0
rs 8.439
cc 6
eloc 21
nc 8
nop 1
1
<?php
2
3
/**
4
 * @file
5
 * Contains \Cultuurnet\UDB3\Place\PlaceLDProjector.
6
 */
7
8
namespace CultuurNet\UDB3\Place\ReadModel\JSONLD;
9
10
use Broadway\Domain\DateTime;
11
use Broadway\Domain\DomainMessage;
12
use Broadway\EventHandling\EventListenerInterface;
13
use CultuurNet\UDB3\Cdb\ActorItemFactory;
14
use CultuurNet\UDB3\Cdb\EventItemFactory;
15
use CultuurNet\UDB3\CulturefeedSlugger;
16
use CultuurNet\UDB3\EntityNotFoundException;
17
use CultuurNet\UDB3\EntityServiceInterface;
18
use CultuurNet\UDB3\Event\EventType;
19
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
20
use CultuurNet\UDB3\EventHandling\DelegateEventHandlingToSpecificMethodTrait;
21
use CultuurNet\UDB3\Facility;
22
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
23
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\CdbXMLItemBaseImporter;
24
use CultuurNet\UDB3\Place\Events\BookingInfoUpdated;
25
use CultuurNet\UDB3\Place\Events\ContactPointUpdated;
26
use CultuurNet\UDB3\Place\Events\DescriptionUpdated;
27
use CultuurNet\UDB3\Place\Events\FacilitiesUpdated;
28
use CultuurNet\UDB3\Place\Events\ImageAdded;
29
use CultuurNet\UDB3\Place\Events\ImageDeleted;
30
use CultuurNet\UDB3\Place\Events\ImageUpdated;
31
use CultuurNet\UDB3\Place\Events\MajorInfoUpdated;
32
use CultuurNet\UDB3\Place\Events\OrganizerDeleted;
33
use CultuurNet\UDB3\Place\Events\OrganizerUpdated;
34
use CultuurNet\UDB3\Place\Events\PlaceCreated;
35
use CultuurNet\UDB3\Place\Events\PlaceDeleted;
36
use CultuurNet\UDB3\Place\Events\PlaceImportedFromUDB2;
37
use CultuurNet\UDB3\Place\Events\PlaceImportedFromUDB2Event;
38
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeDeleted;
39
use CultuurNet\UDB3\Place\Events\TypicalAgeRangeUpdated;
40
use CultuurNet\UDB3\Place\PlaceEvent;
41
use CultuurNet\UDB3\Place\ReadModel\JSONLD\CdbXMLImporter;
42
use CultuurNet\UDB3\ReadModel\JsonDocument;
43
use CultuurNet\UDB3\SluggerInterface;
44
use CultuurNet\UDB3\Theme;
45
use Symfony\Component\Serializer\SerializerInterface;
46
47
/**
48
 * Projects state changes on Place entities to a JSON-LD read model in a
49
 * document repository.
50
 */
51
class PlaceLDProjector implements EventListenerInterface
52
{
53
    use DelegateEventHandlingToSpecificMethodTrait;
54
55
    /**
56
     * @var DocumentRepositoryInterface
57
     */
58
    protected $repository;
59
60
    /**
61
     * @var IriGeneratorInterface
62
     */
63
    protected $iriGenerator;
64
65
    /**
66
     * @var EntityServiceInterface
67
     */
68
    protected $organizerService;
69
70
    /**
71
     * @var SluggerInterface
72
     */
73
    protected $slugger;
74
75
    /**
76
     * @var CdbXMLImporter
77
     */
78
    protected $cdbXMLImporter;
79
80
    /**
81
     * @var SerializerInterface
82
     */
83
    protected $mediaObjectSerializer;
84
85
    /**
86
     * @param DocumentRepositoryInterface $repository
87
     * @param IriGeneratorInterface $iriGenerator
88
     * @param EntityServiceInterface $organizerService
89
     * @param SerializerInterface $mediaObjectSerializer
90
     */
91
    public function __construct(
92
        DocumentRepositoryInterface $repository,
93
        IriGeneratorInterface $iriGenerator,
94
        EntityServiceInterface $organizerService,
95
        SerializerInterface $mediaObjectSerializer
96
    ) {
97
        $this->repository = $repository;
98
        $this->iriGenerator = $iriGenerator;
99
        $this->organizerService = $organizerService;
100
        $this->mediaObjectSerializer = $mediaObjectSerializer;
101
        $this->slugger = new CulturefeedSlugger();
102
        $this->cdbXMLImporter = new CdbXMLImporter(
103
            new CdbXMLItemBaseImporter()
104
        );
105
    }
106
107
    /**
108
     * @param PlaceImportedFromUDB2 $actorImportedFromUDB2
109
     */
110
    protected function applyPlaceImportedFromUDB2(
111
        PlaceImportedFromUDB2 $actorImportedFromUDB2
112
    ) {
113
        $udb2Actor = ActorItemFactory::createActorFromCdbXml(
114
            $actorImportedFromUDB2->getCdbXmlNamespaceUri(),
115
            $actorImportedFromUDB2->getCdbXml()
116
        );
117
118
        $document = $this->newDocument($actorImportedFromUDB2->getActorId());
119
        $actorLd = $document->getBody();
120
121
        $actorLd = $this->cdbXMLImporter->documentWithCdbXML(
122
            $actorLd,
123
            $udb2Actor
124
        );
125
126
        $this->repository->save($document->withBody($actorLd));
127
    }
128
129
130
    /**
131
     * @param PlaceImportedFromUDB2Event $eventImportedFromUDB2
132
     */
133
    protected function applyPlaceImportedFromUDB2Event(
134
        PlaceImportedFromUDB2Event $eventImportedFromUDB2
135
    ) {
136
        $udb2Event = EventItemFactory::createEventFromCdbXml(
137
            $eventImportedFromUDB2->getCdbXmlNamespaceUri(),
138
            $eventImportedFromUDB2->getCdbXml()
139
        );
140
141
        $document = $this->newDocument($eventImportedFromUDB2->getActorId());
142
        $placeLd = $document->getBody();
143
144
        $placeLd = $this->cdbXMLImporter->eventDocumentWithCdbXML(
145
            $placeLd,
146
            $udb2Event
147
        );
148
149
        $this->repository->save($document->withBody($placeLd));
150
    }
151
152
    /**
153
     * @param string $id
154
     * @return JsonDocument
155
     */
156 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...
157
    {
158
        $document = new JsonDocument($id);
159
160
        $placeLd = $document->getBody();
161
        $placeLd->{'@id'} = $this->iriGenerator->iri($id);
162
163
        // @todo provide Event-LD context here relative to the base URI
164
        $placeLd->{'@context'} = '/api/1.0/place.jsonld';
165
166
        return $document->withBody($placeLd);
167
    }
168
169
    /**
170
     * @param PlaceCreated $placeCreated
171
     * @param DomainMessage $domainMessage
172
     */
173
    protected function applyPlaceCreated(PlaceCreated $placeCreated, DomainMessage $domainMessage)
174
    {
175
        $document = $this->newDocument($placeCreated->getPlaceId());
176
177
        $jsonLD = $document->getBody();
178
179
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
180
            $placeCreated->getPlaceId()
181
        );
182
        $jsonLD->name = $placeCreated->getTitle();
183
184
        $jsonLD->address = $placeCreated->getAddress()->toJsonLd();
185
186
        $calendarJsonLD = $placeCreated->getCalendar()->toJsonLd();
187
        $jsonLD = (object) array_merge((array) $jsonLD, $calendarJsonLD);
188
189
        $eventType = $placeCreated->getEventType();
190
        $jsonLD->terms = [
191
            $eventType->toJsonLd()
192
        ];
193
194
        $theme = $placeCreated->getTheme();
195
        if (!empty($theme)) {
196
            $jsonLD->terms[] = $theme->toJsonLd();
197
        }
198
199
        $recordedOn = $domainMessage->getRecordedOn()->toString();
200
        $jsonLD->created = \DateTime::createFromFormat(
201
            DateTime::FORMAT_STRING,
202
            $recordedOn
203
        )->format('c');
204
205
        $jsonLD->modified = $jsonLD->created;
206
207
        $metaData = $domainMessage->getMetadata()->serialize();
208 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...
209
            $jsonLD->creator = $metaData['user_email'];
210
        } elseif (isset($metaData['user_nick'])) {
211
            $jsonLD->creator = $metaData['user_nick'];
212
        }
213
214
        $this->repository->save($document->withBody($jsonLD));
215
    }
216
217
    /**
218
     * @param PlaceDeleted $placeDeleted
219
     */
220
    protected function applyPlaceDeleted(PlaceDeleted $placeDeleted)
221
    {
222
        $this->repository->remove($placeDeleted->getPlaceId());
223
    }
224
225
    /**
226
     * Apply the major info updated command to the projector.
227
     * @param MajorInfoUpdated $majorInfoUpdated
228
     */
229
    protected function applyMajorInfoUpdated(MajorInfoUpdated $majorInfoUpdated)
230
    {
231
232
        $document = $this->loadPlaceDocumentFromRepository($majorInfoUpdated);
233
        $jsonLD = $document->getBody();
234
235
        $jsonLD->name = $majorInfoUpdated->getTitle();
236
        $jsonLD->address = $majorInfoUpdated->getAddress()->toJsonLd();
237
238
        $calendarJsonLD = $majorInfoUpdated->getCalendar()->toJsonLd();
239
        $jsonLD = (object) array_merge((array) $jsonLD, $calendarJsonLD);
240
241
        // Remove old theme and event type.
242
        $jsonLD->terms = array_filter($jsonLD->terms, function ($term) {
243
            return $term->domain !== EventType::DOMAIN &&  $term->domain !== Theme::DOMAIN;
244
        });
245
246
        $eventType = $majorInfoUpdated->getEventType();
247
        $jsonLD->terms = [
248
            $eventType->toJsonLd()
249
        ];
250
251
        $theme = $majorInfoUpdated->getTheme();
252
        if (!empty($theme)) {
253
            $jsonLD->terms[] = $theme->toJsonLd();
254
        }
255
256
        $this->repository->save($document->withBody($jsonLD));
257
258
    }
259
260
    /**
261
     * Apply the description updated event to the place repository.
262
     * @param DescriptionUpdated $descriptionUpdated
263
     */
264 View Code Duplication
    protected function applyDescriptionUpdated(
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...
265
        DescriptionUpdated $descriptionUpdated
266
    ) {
267
268
        $document = $this->loadPlaceDocumentFromRepository($descriptionUpdated);
269
270
        $placeLD = $document->getBody();
271
        if (empty($placeLD->description)) {
272
            $placeLD->description = new \stdClass();
273
        }
274
        $placeLD->description->{'nl'} = $descriptionUpdated->getDescription();
275
276
        $this->repository->save($document->withBody($placeLD));
277
    }
278
279
    /**
280
     * Apply the booking info updated event to the place repository.
281
     * @param BookingInfoUpdated $bookingInfoUpdated
282
     */
283 View Code Duplication
    protected function applyBookingInfoUpdated(BookingInfoUpdated $bookingInfoUpdated)
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...
284
    {
285
286
        $document = $this->loadPlaceDocumentFromRepository($bookingInfoUpdated);
287
288
        $placeLD = $document->getBody();
289
        $placeLD->bookingInfo = $bookingInfoUpdated->getBookingInfo()->toJsonLd();
290
291
        $this->repository->save($document->withBody($placeLD));
292
293
    }
294
295
    /**
296
     * Apply the typical age range updated event to the place repository.
297
     * @param TypicalAgeRangeUpdated $typicalAgeRangeUpdated
298
     */
299 View Code Duplication
    protected function applyTypicalAgeRangeUpdated(
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...
300
        TypicalAgeRangeUpdated $typicalAgeRangeUpdated
301
    ) {
302
        $document = $this->loadPlaceDocumentFromRepository($typicalAgeRangeUpdated);
303
304
        $placeLd = $document->getBody();
305
        $placeLd->typicalAgeRange = $typicalAgeRangeUpdated->getTypicalAgeRange();
306
307
        $this->repository->save($document->withBody($placeLd));
308
    }
309
310
    /**
311
     * Apply the typical age range deleted event to the place repository.
312
     * @param TypicalAgeRangeDeleted $typicalAgeRangeDeleted
313
     */
314
    protected function applyTypicalAgeRangeDeleted(
315
        TypicalAgeRangeDeleted $typicalAgeRangeDeleted
316
    ) {
317
        $document = $this->loadPlaceDocumentFromRepository($typicalAgeRangeDeleted);
318
319
        $placeLd = $document->getBody();
320
321
        unset($placeLd->typicalAgeRange);
322
323
        $this->repository->save($document->withBody($placeLd));
324
    }
325
326
    /**
327
     * Apply the organizer updated event to the place repository.
328
     * @param OrganizerUpdated $organizerUpdated
329
     */
330 View Code Duplication
    protected function applyOrganizerUpdated(OrganizerUpdated $organizerUpdated)
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...
331
    {
332
        $document = $this->loadPlaceDocumentFromRepository($organizerUpdated);
333
334
        $placeLd = $document->getBody();
335
336
        $placeLd->organizer = array(
337
          '@type' => 'Organizer',
338
        ) + (array)$this->organizerJSONLD($organizerUpdated->getOrganizerId());
339
340
        $this->repository->save($document->withBody($placeLd));
341
    }
342
343
    /**
344
     * Apply the organizer delete event to the place repository.
345
     * @param OrganizerDeleted $organizerDeleted
346
     */
347
    protected function applyOrganizerDeleted(OrganizerDeleted $organizerDeleted)
348
    {
349
        $document = $this->loadPlaceDocumentFromRepository($organizerDeleted);
350
351
        $placeLd = $document->getBody();
352
353
        unset($placeLd->organizer);
354
355
        $this->repository->save($document->withBody($placeLd));
356
    }
357
358
    /**
359
     * Apply the contact point updated event to the place repository.
360
     * @param ContactPointUpdated $contactPointUpdated
361
     */
362 View Code Duplication
    protected function applyContactPointUpdated(ContactPointUpdated $contactPointUpdated)
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...
363
    {
364
365
        $document = $this->loadPlaceDocumentFromRepository($contactPointUpdated);
366
367
        $placeLd = $document->getBody();
368
        $placeLd->contactPoint = $contactPointUpdated->getContactPoint()->toJsonLd();
369
370
        $this->repository->save($document->withBody($placeLd));
371
    }
372
373
    /**
374
     * Apply the facilitiesupdated event to the place repository.
375
     * @param FacilitiesUpdated $facilitiesUpdated
376
     */
377
    protected function applyFacilitiesUpdated(FacilitiesUpdated $facilitiesUpdated)
378
    {
379
380
        $document = $this->loadPlaceDocumentFromRepository($facilitiesUpdated);
381
382
        $placeLd = $document->getBody();
383
384
        $terms = isset($placeLd->terms) ? $placeLd->terms : array();
385
386
        // Remove all old facilities + get numeric keys.
387
        $terms = array_values(array_filter(
388
            $terms,
389
            function ($term) {
390
                return $term->domain !== Facility::DOMAIN;
391
            }
392
        ));
393
394
        // Add the new facilities.
395
        foreach ($facilitiesUpdated->getFacilities() as $facility) {
396
            $terms[] = $facility->toJsonLd();
397
        }
398
399
        $placeLd->terms = $terms;
400
401
        $this->repository->save($document->withBody($placeLd));
402
403
    }
404
405
    /**
406
     * Apply the imageAdded event to the place repository.
407
     *
408
     * @param ImageAdded $imageAdded
409
     */
410 View Code Duplication
    protected function applyImageAdded(ImageAdded $imageAdded)
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...
411
    {
412
413
        $document = $this->loadPlaceDocumentFromRepository($imageAdded);
414
415
        $placeLd = $document->getBody();
416
        $placeLd->mediaObject = isset($placeLd->mediaObject) ? $placeLd->mediaObject : [];
417
418
        $imageData = $this->mediaObjectSerializer->serialize(
419
            $imageAdded->getImage(),
420
            'json-ld'
421
        );
422
        $placeLd->mediaObject[] = $imageData;
423
424
        $this->repository->save($document->withBody($placeLd));
425
426
    }
427
428
    /**
429
     * Apply the ImageUpdated event to the place repository.
430
     *
431
     * @param ImageUpdated $imageUpdated
432
     */
433
    protected function applyImageUpdated(ImageUpdated $imageUpdated)
434
    {
435
        $document = $this->repository->get($imageUpdated->getItemId());
436
437
        if (!$document) {
438
            return $this->newDocument($imageUpdated->getItemId());
439
        }
440
441
        $placeLd = $document->getBody();
442
443
        if (!isset($placeLd->mediaObject)) {
444
            throw new \Exception('The image to update could not be found.');
445
        }
446
447
        $updatedMediaObjects = [];
448
449 View Code Duplication
        foreach ($placeLd->mediaObject as $mediaObject) {
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...
450
            $mediaObjectMatches = (
451
                strpos(
452
                    $mediaObject->{'@id'},
453
                    (string)$imageUpdated->getMediaObjectId()
454
                ) > 0
455
            );
456
457
            if ($mediaObjectMatches) {
458
                $mediaObject->description = (string)$imageUpdated->getDescription();
459
                $mediaObject->copyrightHolder = (string)$imageUpdated->getCopyrightHolder();
460
461
                $updatedMediaObjects[] = $mediaObject;
462
            }
463
        };
464
465
        if (empty($updatedMediaObjects)) {
466
            throw new \Exception('The image to update could not be found.');
467
        }
468
469
        $this->repository->save($document->withBody($placeLd));
470
    }
471
472
    /**
473
     * Apply the imageDeleted event to the place repository.
474
     *
475
     * @param ImageDeleted $imageDeleted
476
     */
477 View Code Duplication
    protected function applyImageDeleted(ImageDeleted $imageDeleted)
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...
478
    {
479
480
        $document = $this->loadPlaceDocumentFromRepository($imageDeleted);
481
482
        $placeLd = $document->getBody();
483
        unset($placeLd->mediaObject[$imageDeleted->getIndexToDelete()]);
484
485
        // Generate new numeric keys.
486
        $placeLd->mediaObject = array_values($placeLd->mediaObject);
487
488
        $this->repository->save($document->withBody($placeLd));
489
490
    }
491
492
    /**
493
     * @param PlaceEvent $place
494
     * @return JsonDocument
495
     */
496
    protected function loadPlaceDocumentFromRepository(PlaceEvent $place)
497
    {
498
        $document = $this->repository->get($place->getPlaceId());
499
500
        if (!$document) {
501
            return $this->newDocument($place->getPlaceId());
502
        }
503
504
        return $document;
505
    }
506
507
    /**
508
     * Get the organizer jsonLD.
509
     * @param string $organizerId
510
     * @return array
511
     */
512 View Code Duplication
    protected function organizerJSONLD($organizerId)
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...
513
    {
514
        try {
515
            $organizerJSONLD = $this->organizerService->getEntity(
516
                $organizerId
517
            );
518
519
            return json_decode($organizerJSONLD);
520
        } catch (EntityNotFoundException $e) {
521
            // In case the place can not be found at the moment, just add its ID
522
            return array(
523
                '@id' => $this->organizerService->iri($organizerId)
524
            );
525
        }
526
    }
527
}
528