Completed
Push — master ( dc3001...f72a69 )
by Luc
44:07 queued 08:30
created

OrganizerLDProjector::applyContactPointUpdated()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3\Organizer;
4
5
use Broadway\Domain\DateTime;
6
use Broadway\Domain\DomainMessage;
7
use Broadway\EventHandling\EventBusInterface;
8
use Broadway\EventHandling\EventListenerInterface;
9
use CultuurNet\UDB3\Actor\ActorEvent;
10
use CultuurNet\UDB3\Cdb\ActorItemFactory;
11
use CultuurNet\UDB3\Event\ReadModel\DocumentGoneException;
12
use CultuurNet\UDB3\Event\ReadModel\DocumentRepositoryInterface;
13
use CultuurNet\UDB3\EventHandling\DelegateEventHandlingToSpecificMethodTrait;
14
use CultuurNet\UDB3\Iri\IriGeneratorInterface;
15
use CultuurNet\UDB3\Label;
16
use CultuurNet\UDB3\Language;
17
use CultuurNet\UDB3\Offer\WorkflowStatus;
18
use CultuurNet\UDB3\Organizer\Events\AddressTranslated;
19
use CultuurNet\UDB3\Organizer\Events\AddressUpdated;
20
use CultuurNet\UDB3\Organizer\Events\ContactPointUpdated;
21
use CultuurNet\UDB3\Organizer\Events\LabelAdded;
22
use CultuurNet\UDB3\Organizer\Events\LabelRemoved;
23
use CultuurNet\UDB3\Organizer\Events\OrganizerCreated;
24
use CultuurNet\UDB3\Organizer\Events\OrganizerCreatedWithUniqueWebsite;
25
use CultuurNet\UDB3\Organizer\Events\OrganizerDeleted;
26
use CultuurNet\UDB3\Organizer\Events\OrganizerEvent;
27
use CultuurNet\UDB3\Organizer\Events\OrganizerImportedFromUDB2;
28
use CultuurNet\UDB3\Organizer\Events\OrganizerUpdatedFromUDB2;
29
use CultuurNet\UDB3\Organizer\Events\TitleTranslated;
30
use CultuurNet\UDB3\Organizer\Events\TitleUpdated;
31
use CultuurNet\UDB3\Organizer\Events\WebsiteUpdated;
32
use CultuurNet\UDB3\Organizer\ReadModel\JSONLD\CdbXMLImporter;
33
use CultuurNet\UDB3\ReadModel\JsonDocument;
34
use CultuurNet\UDB3\ReadModel\JsonDocumentMetaDataEnricherInterface;
35
use CultuurNet\UDB3\ReadModel\MultilingualJsonLDProjectorTrait;
36
use CultuurNet\UDB3\RecordedOn;
37
use CultuurNet\UDB3\Title;
38
39
class OrganizerLDProjector implements EventListenerInterface
40
{
41
    use MultilingualJsonLDProjectorTrait;
42
    /**
43
     * @uses applyOrganizerImportedFromUDB2
44
     * @uses applyOrganizerCreated
45
     * @uses applyOrganizerCreatedWithUniqueWebsite
46
     * @uses applyWebsiteUpdated
47
     * @uses applyTitleUpdated
48
     * @uses applyTitleTranslated
49
     * @uses applyAddressUpdated
50
     * @uses applyAddressTranslated
51
     * @uses applyContactPointUpdated
52
     * @uses applyOrganizerUpdatedFRomUDB2
53
     * @uses applyLabelAdded
54
     * @uses applyLabelRemoved
55
     * @uses applyOrganizerDeleted
56
     */
57
    use DelegateEventHandlingToSpecificMethodTrait {
58
        DelegateEventHandlingToSpecificMethodTrait::handle as handleMethodSpecificEvents;
59
    }
60
61
    /**
62
     * @var DocumentRepositoryInterface
63
     */
64
    private $repository;
65
66
    /**
67
     * @var IriGeneratorInterface
68
     */
69
    private $iriGenerator;
70
71
    /**
72
     * @var EventBusInterface
73
     */
74
    private $eventBus;
75
76
    /**
77
     * @var JsonDocumentMetaDataEnricherInterface
78
     */
79
    private $jsonDocumentMetaDataEnricher;
80
81
    /**
82
     * @var CdbXMLImporter
83
     */
84
    private $cdbXMLImporter;
85
86
    /**
87
     * @param DocumentRepositoryInterface $repository
88
     * @param IriGeneratorInterface $iriGenerator
89
     * @param EventBusInterface $eventBus
90
     * @param JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
91
     */
92
    public function __construct(
93
        DocumentRepositoryInterface $repository,
94
        IriGeneratorInterface $iriGenerator,
95
        EventBusInterface $eventBus,
96
        JsonDocumentMetaDataEnricherInterface $jsonDocumentMetaDataEnricher
97
    ) {
98
        $this->repository = $repository;
99
        $this->iriGenerator = $iriGenerator;
100
        $this->eventBus = $eventBus;
101
        $this->jsonDocumentMetaDataEnricher = $jsonDocumentMetaDataEnricher;
102
        $this->cdbXMLImporter = new CdbXMLImporter();
103
    }
104
105
    /**
106
     * @inheritdoc
107
     */
108
    public function handle(DomainMessage $domainMessage)
109
    {
110
        $event = $domainMessage->getPayload();
111
112
        $handleMethod = $this->getHandleMethodName($event);
113
        if (!$handleMethod) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $handleMethod of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
114
            return;
115
        }
116
117
        $jsonDocument = $this->{$handleMethod}($event, $domainMessage);
118
119
        if ($jsonDocument) {
120
            $jsonDocument = $this->jsonDocumentMetaDataEnricher->enrich($jsonDocument, $domainMessage->getMetadata());
121
122
            $jsonDocument = $this->updateModified($jsonDocument, $domainMessage);
123
124
            $this->repository->save($jsonDocument);
125
        }
126
    }
127
128
    /**
129
     * @param OrganizerImportedFromUDB2 $organizerImportedFromUDB2
130
     * @return JsonDocument
131
     * @throws \CultureFeed_Cdb_ParseException
132
     */
133 View Code Duplication
    private function applyOrganizerImportedFromUDB2(
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...
134
        OrganizerImportedFromUDB2 $organizerImportedFromUDB2
135
    ) {
136
        $udb2Actor = ActorItemFactory::createActorFromCdbXml(
137
            $organizerImportedFromUDB2->getCdbXmlNamespaceUri(),
138
            $organizerImportedFromUDB2->getCdbXml()
139
        );
140
141
        $document = $this->newDocument($organizerImportedFromUDB2->getActorId());
142
        $actorLd = $document->getBody();
143
144
        $actorLd = $this->cdbXMLImporter->documentWithCdbXML(
145
            $actorLd,
146
            $udb2Actor
147
        );
148
149
        return $document->withBody($actorLd);
150
    }
151
152
    /**
153
     * @param OrganizerCreated $organizerCreated
154
     * @param DomainMessage $domainMessage
155
     * @return JsonDocument
156
     */
157
    private function applyOrganizerCreated(OrganizerCreated $organizerCreated, DomainMessage $domainMessage)
158
    {
159
        $document = $this->newDocument($organizerCreated->getOrganizerId());
160
161
        $jsonLD = $document->getBody();
162
163
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
164
            $organizerCreated->getOrganizerId()
165
        );
166
167
        $jsonLD->name = [
168
            $this->getMainLanguage($jsonLD)->getCode() => $organizerCreated->getTitle(),
169
        ];
170
171
        // Only take the first address into account.
172
        $addresses = $organizerCreated->getAddresses();
173
        if (!empty($addresses)) {
174
            $address = $addresses[0];
175
            $jsonLD->address = [
176
                $this->getMainLanguage($jsonLD)->getCode() => $address->toJsonLd(),
177
            ];
178
        }
179
180
        $jsonLD->phone = $organizerCreated->getPhones();
181
        $jsonLD->email = $organizerCreated->getEmails();
182
        $jsonLD->url = $organizerCreated->getUrls();
183
184
        $recordedOn = $domainMessage->getRecordedOn()->toString();
185
        $jsonLD->created = \DateTime::createFromFormat(
186
            DateTime::FORMAT_STRING,
187
            $recordedOn
188
        )->format('c');
189
190
        $jsonLD = $this->appendCreator($jsonLD, $domainMessage);
191
192
        return $document->withBody($jsonLD);
193
    }
194
195
    /**
196
     * @param $jsonLD
197
     * @param DomainMessage $domainMessage
198
     * @return mixed
199
     */
200
    private function appendCreator($jsonLD, $domainMessage)
201
    {
202
        $newJsonLD = clone $jsonLD;
203
204
        $metaData = $domainMessage->getMetadata()->serialize();
205
        if (isset($metaData['user_id'])) {
206
            $newJsonLD->creator = $metaData['user_id'];
207
        }
208
209
        return $newJsonLD;
210
    }
211
212
    /**
213
     * @param OrganizerCreatedWithUniqueWebsite $organizerCreated
214
     * @param DomainMessage $domainMessage
215
     * @return JsonDocument
216
     */
217
    private function applyOrganizerCreatedWithUniqueWebsite(
218
        OrganizerCreatedWithUniqueWebsite $organizerCreated,
219
        DomainMessage $domainMessage
220
    ) {
221
        $document = $this->newDocument($organizerCreated->getOrganizerId());
222
223
        $jsonLD = $document->getBody();
224
225
        $jsonLD->{'@id'} = $this->iriGenerator->iri(
226
            $organizerCreated->getOrganizerId()
227
        );
228
229
        $this->setMainLanguage($jsonLD, $organizerCreated->getMainLanguage());
230
231
        $jsonLD->url = (string) $organizerCreated->getWebsite();
232
233
        $jsonLD->name = [
234
            $this->getMainLanguage($jsonLD)->getCode() => $organizerCreated->getTitle(),
235
        ];
236
237
        $recordedOn = $domainMessage->getRecordedOn()->toString();
238
        $jsonLD->created = \DateTime::createFromFormat(
239
            DateTime::FORMAT_STRING,
240
            $recordedOn
241
        )->format('c');
242
243
        $jsonLD = $this->appendCreator($jsonLD, $domainMessage);
244
245
        return $document->withBody($jsonLD);
246
    }
247
248
    /**
249
     * @param WebsiteUpdated $websiteUpdated
250
     * @return JsonDocument
251
     */
252
    private function applyWebsiteUpdated(WebsiteUpdated $websiteUpdated)
253
    {
254
        $organizerId = $websiteUpdated->getOrganizerId();
255
256
        $document = $this->repository->get($organizerId);
257
258
        $jsonLD = $document->getBody();
259
        $jsonLD->url = (string) $websiteUpdated->getWebsite();
260
261
        return $document->withBody($jsonLD);
262
    }
263
264
    /**
265
     * @param TitleUpdated $titleUpdated
266
     * @return JsonDocument
267
     */
268
    private function applyTitleUpdated(TitleUpdated $titleUpdated)
269
    {
270
        return $this->applyTitle($titleUpdated, $titleUpdated->getTitle());
271
    }
272
273
    /**
274
     * @param TitleTranslated $titleTranslated
275
     * @return JsonDocument
276
     */
277
    private function applyTitleTranslated(TitleTranslated $titleTranslated)
278
    {
279
        return $this->applyTitle(
280
            $titleTranslated,
281
            $titleTranslated->getTitle(),
282
            $titleTranslated->getLanguage()
283
        );
284
    }
285
286
    /**
287
     * @param AddressUpdated $addressUpdated
288
     * @return JsonDocument
289
     */
290
    private function applyAddressUpdated(AddressUpdated $addressUpdated)
291
    {
292
        return $this->applyAddress($addressUpdated);
293
    }
294
295
    /**
296
     * @param AddressTranslated $addressTranslated
297
     * @return JsonDocument
298
     */
299
    private function applyAddressTranslated(AddressTranslated $addressTranslated)
300
    {
301
        return $this->applyAddress($addressTranslated, $addressTranslated->getLanguage());
302
    }
303
304
    /**
305
     * @param ContactPointUpdated $contactPointUpdated
306
     * @return JsonDocument
307
     */
308
    private function applyContactPointUpdated(ContactPointUpdated $contactPointUpdated)
309
    {
310
        $organizerId = $contactPointUpdated->getOrganizerId();
311
        $contactPoint = $contactPointUpdated->getContactPoint();
312
313
        $document = $this->repository->get($organizerId);
314
315
        $jsonLD = $document->getBody();
316
        $jsonLD->contactPoint = $contactPoint->toJsonLd();
317
318
        return $document->withBody($jsonLD);
319
    }
320
321
    /**
322
     * @param OrganizerUpdatedFromUDB2 $organizerUpdatedFromUDB2
323
     * @return JsonDocument
324
     * @throws \CultureFeed_Cdb_ParseException
325
     */
326 View Code Duplication
    private function applyOrganizerUpdatedFromUDB2(
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...
327
        OrganizerUpdatedFromUDB2 $organizerUpdatedFromUDB2
328
    ) {
329
        // It's possible that an organizer has been deleted in udb3, but never
330
        // in udb2. If an update comes for that organizer from udb2, it should
331
        // be imported again. This is intended by design.
332
        // @see https://jira.uitdatabank.be/browse/III-1092
333
        try {
334
            $document = $this->loadDocumentFromRepository(
335
                $organizerUpdatedFromUDB2
336
            );
337
        } catch (DocumentGoneException $e) {
338
            $document = $this->newDocument($organizerUpdatedFromUDB2->getActorId());
339
        }
340
341
        $udb2Actor = ActorItemFactory::createActorFromCdbXml(
342
            $organizerUpdatedFromUDB2->getCdbXmlNamespaceUri(),
343
            $organizerUpdatedFromUDB2->getCdbXml()
344
        );
345
346
        $actorLd = $this->cdbXMLImporter->documentWithCdbXML(
347
            $document->getBody(),
348
            $udb2Actor
349
        );
350
351
        return $document->withBody($actorLd);
352
    }
353
354
    /**
355
     * @param LabelAdded $labelAdded
356
     * @return JsonDocument
357
     */
358 View Code Duplication
    private function applyLabelAdded(LabelAdded $labelAdded)
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...
359
    {
360
        $document = $this->repository->get($labelAdded->getOrganizerId());
361
362
        $jsonLD = $document->getBody();
363
364
        // Check the visibility of the label to update the right property.
365
        $labelsProperty = $labelAdded->getLabel()->isVisible() ? 'labels' : 'hiddenLabels';
366
367
        $labels = isset($jsonLD->{$labelsProperty}) ? $jsonLD->{$labelsProperty} : [];
368
        $label = (string) $labelAdded->getLabel();
369
370
        $labels[] = $label;
371
        $jsonLD->{$labelsProperty} = array_unique($labels);
372
373
        return $document->withBody($jsonLD);
374
    }
375
376
    /**
377
     * @param LabelRemoved $labelRemoved
378
     * @return JsonDocument
379
     */
380 View Code Duplication
    private function applyLabelRemoved(LabelRemoved $labelRemoved)
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...
381
    {
382
        $document = $this->repository->get($labelRemoved->getOrganizerId());
383
        $jsonLD = $document->getBody();
384
385
        // Don't presume that the label visibility is correct when removing.
386
        // So iterate over both the visible and invisible labels.
387
        $labelsProperties = ['labels', 'hiddenLabels'];
388
389
        foreach ($labelsProperties as $labelsProperty) {
390
            if (isset($jsonLD->{$labelsProperty}) && is_array($jsonLD->{$labelsProperty})) {
391
                $jsonLD->{$labelsProperty} = array_filter(
392
                    $jsonLD->{$labelsProperty},
393
                    function ($label) use ($labelRemoved) {
394
                        return !$labelRemoved->getLabel()->equals(
395
                            new Label($label)
396
                        );
397
                    }
398
                );
399
400
                // Ensure array keys start with 0 so json_encode() does encode it
401
                // as an array and not as an object.
402
                if (count($jsonLD->{$labelsProperty}) > 0) {
403
                    $jsonLD->{$labelsProperty} = array_values($jsonLD->{$labelsProperty});
404
                } else {
405
                    unset($jsonLD->{$labelsProperty});
406
                }
407
            }
408
        }
409
410
        return $document->withBody($jsonLD);
411
    }
412
413
    /**
414
     * @param OrganizerDeleted $organizerDeleted
415
     * @return null
416
     */
417
    private function applyOrganizerDeleted(
418
        OrganizerDeleted $organizerDeleted
419
    ) {
420
        $document =  $this->repository->get($organizerDeleted->getOrganizerId());
421
422
        $jsonLD = $document->getBody();
423
424
        $jsonLD->workflowStatus = WorkflowStatus::DELETED()->getName();
425
426
        return $document->withBody($jsonLD);
427
    }
428
429
    /**
430
     * @param string $id
431
     * @return JsonDocument
432
     */
433 View Code Duplication
    private 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...
434
    {
435
        $document = new JsonDocument($id);
436
437
        $organizerLd = $document->getBody();
438
        $organizerLd->{'@id'} = $this->iriGenerator->iri($id);
439
        $organizerLd->{'@context'} = '/contexts/organizer';
440
        // For an new organizer document set a default language of nl.
441
        // This avoids a missing language for imports.
442
        // When created with UDB3 this main language gets overwritten by the real one.
443
        $organizerLd->mainLanguage = 'nl';
444
445
        return $document->withBody($organizerLd);
446
    }
447
448
    /**
449
     * @param OrganizerEvent $organizerEvent
450
     * @param Title $title
451
     * @param Language|null $language
452
     * @return JsonDocument
453
     */
454
    private function applyTitle(
455
        OrganizerEvent $organizerEvent,
456
        Title $title,
457
        Language $language = null
458
    ) {
459
        $organizerId = $organizerEvent->getOrganizerId();
460
461
        $document = $this->repository->get($organizerId);
462
463
        $jsonLD = $document->getBody();
464
465
        $mainLanguage = $this->getMainLanguage($jsonLD);
466
        if ($language === null) {
467
            $language = $mainLanguage;
468
        }
469
470
        // @replay_i18n For old projections the name is untranslated and just a string.
471
        // This needs to be upgraded to an object with languages and translation.
472
        // When a full replay is done this code becomes obsolete.
473
        // @see https://jira.uitdatabank.be/browse/III-2201
474
        if (isset($jsonLD->name) && is_string($jsonLD->name)) {
475
            $previousTitle = $jsonLD->name;
476
            $jsonLD->name = new \StdClass();
477
            $jsonLD->name->{$mainLanguage->getCode()} = $previousTitle;
478
        }
479
480
        $jsonLD->name->{$language->getCode()} = $title->toNative();
481
482
        return $document->withBody($jsonLD);
483
    }
484
485
    /**
486
     * @param AddressUpdated $addressUpdated
487
     * @param Language $language
488
     * @return JsonDocument|null
489
     */
490
    private function applyAddress(
491
        AddressUpdated $addressUpdated,
492
        Language $language = null
493
    ) {
494
        $organizerId = $addressUpdated->getOrganizerId();
495
        $document = $this->repository->get($organizerId);
496
        $jsonLD = $document->getBody();
497
498
        $mainLanguage = $this->getMainLanguage($jsonLD);
499
        if ($language === null) {
500
            $language = $mainLanguage;
501
        }
502
503
        $jsonLD->address->{$language->getCode()} = $addressUpdated->getAddress()->toJsonLd();
504
505
        return $document->withBody($jsonLD);
506
    }
507
508
    /**
509
     * @param ActorEvent $actor
510
     * @return JsonDocument
511
     */
512
    private function loadDocumentFromRepository(ActorEvent $actor)
513
    {
514
        $document = $this->repository->get($actor->getActorId());
515
516
        if (!$document) {
517
            return $this->newDocument($actor->getActorId());
518
        }
519
520
        return $document;
521
    }
522
523
    /**
524
     * @param JsonDocument $jsonDocument
525
     * @param DomainMessage $domainMessage
526
     * @return JsonDocument
527
     */
528 View Code Duplication
    private function updateModified(JsonDocument $jsonDocument, DomainMessage $domainMessage)
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...
529
    {
530
        $body = $jsonDocument->getBody();
531
532
        $recordedDateTime = RecordedOn::fromDomainMessage($domainMessage);
533
        $body->modified = $recordedDateTime->toString();
534
535
        return $jsonDocument->withBody($body);
536
    }
537
}
538