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\Organizer\Events\AddressUpdated; |
18
|
|
|
use CultuurNet\UDB3\Organizer\Events\ContactPointUpdated; |
19
|
|
|
use CultuurNet\UDB3\Organizer\Events\LabelAdded; |
20
|
|
|
use CultuurNet\UDB3\Organizer\Events\LabelRemoved; |
21
|
|
|
use CultuurNet\UDB3\Organizer\Events\OrganizerCreated; |
22
|
|
|
use CultuurNet\UDB3\Organizer\Events\OrganizerCreatedWithUniqueWebsite; |
23
|
|
|
use CultuurNet\UDB3\Organizer\Events\OrganizerDeleted; |
24
|
|
|
use CultuurNet\UDB3\Organizer\Events\OrganizerEvent; |
25
|
|
|
use CultuurNet\UDB3\Organizer\Events\OrganizerImportedFromUDB2; |
26
|
|
|
use CultuurNet\UDB3\Organizer\Events\OrganizerUpdatedFromUDB2; |
27
|
|
|
use CultuurNet\UDB3\Organizer\Events\TitleTranslated; |
28
|
|
|
use CultuurNet\UDB3\Organizer\Events\TitleUpdated; |
29
|
|
|
use CultuurNet\UDB3\Organizer\Events\WebsiteUpdated; |
30
|
|
|
use CultuurNet\UDB3\Organizer\ReadModel\JSONLD\CdbXMLImporter; |
31
|
|
|
use CultuurNet\UDB3\ReadModel\JsonDocument; |
32
|
|
|
use CultuurNet\UDB3\ReadModel\MultilingualJsonLDProjectorTrait; |
33
|
|
|
use CultuurNet\UDB3\Title; |
34
|
|
|
|
35
|
|
|
class OrganizerLDProjector implements EventListenerInterface |
36
|
|
|
{ |
37
|
|
|
use MultilingualJsonLDProjectorTrait; |
38
|
|
|
/** |
39
|
|
|
* @uses applyOrganizerImportedFromUDB2 |
40
|
|
|
* @uses applyOrganizerCreated |
41
|
|
|
* @uses applyOrganizerCreatedWithUniqueWebsite |
42
|
|
|
* @uses applyWebsiteUpdated |
43
|
|
|
* @uses applyTitleUpdated |
44
|
|
|
* @uses applyTitleTranslated |
45
|
|
|
* @uses applyAddressUpdated |
46
|
|
|
* @uses applyContactPointUpdated |
47
|
|
|
* @uses applyOrganizerUpdatedFRomUDB2 |
48
|
|
|
* @uses applyLabelAdded |
49
|
|
|
* @uses applyLabelRemoved |
50
|
|
|
* @uses applyOrganizerDeleted |
51
|
|
|
*/ |
52
|
|
|
use DelegateEventHandlingToSpecificMethodTrait; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @var DocumentRepositoryInterface |
56
|
|
|
*/ |
57
|
|
|
protected $repository; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @var IriGeneratorInterface |
61
|
|
|
*/ |
62
|
|
|
protected $iriGenerator; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @var EventBusInterface |
66
|
|
|
*/ |
67
|
|
|
protected $eventBus; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @var CdbXMLImporter |
71
|
|
|
*/ |
72
|
|
|
private $cdbXMLImporter; |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* @param DocumentRepositoryInterface $repository |
76
|
|
|
* @param IriGeneratorInterface $iriGenerator |
77
|
|
|
* @param EventBusInterface $eventBus |
78
|
|
|
*/ |
79
|
|
|
public function __construct( |
80
|
|
|
DocumentRepositoryInterface $repository, |
81
|
|
|
IriGeneratorInterface $iriGenerator, |
82
|
|
|
EventBusInterface $eventBus |
83
|
|
|
) { |
84
|
|
|
$this->repository = $repository; |
85
|
|
|
$this->iriGenerator = $iriGenerator; |
86
|
|
|
$this->eventBus = $eventBus; |
87
|
|
|
$this->cdbXMLImporter = new CdbXMLImporter(); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @param OrganizerImportedFromUDB2 $organizerImportedFromUDB2 |
92
|
|
|
*/ |
93
|
|
View Code Duplication |
private function applyOrganizerImportedFromUDB2( |
|
|
|
|
94
|
|
|
OrganizerImportedFromUDB2 $organizerImportedFromUDB2 |
95
|
|
|
) { |
96
|
|
|
$udb2Actor = ActorItemFactory::createActorFromCdbXml( |
97
|
|
|
$organizerImportedFromUDB2->getCdbXmlNamespaceUri(), |
98
|
|
|
$organizerImportedFromUDB2->getCdbXml() |
99
|
|
|
); |
100
|
|
|
|
101
|
|
|
$document = $this->newDocument($organizerImportedFromUDB2->getActorId()); |
102
|
|
|
$actorLd = $document->getBody(); |
103
|
|
|
|
104
|
|
|
$this->setMainLanguage($actorLd, new Language('nl')); |
105
|
|
|
|
106
|
|
|
$actorLd = $this->cdbXMLImporter->documentWithCdbXML( |
107
|
|
|
$actorLd, |
108
|
|
|
$udb2Actor |
109
|
|
|
); |
110
|
|
|
|
111
|
|
|
$this->repository->save($document->withBody($actorLd)); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @param OrganizerCreated $organizerCreated |
116
|
|
|
* @param DomainMessage $domainMessage |
117
|
|
|
*/ |
118
|
|
|
private function applyOrganizerCreated(OrganizerCreated $organizerCreated, DomainMessage $domainMessage) |
119
|
|
|
{ |
120
|
|
|
$document = $this->newDocument($organizerCreated->getOrganizerId()); |
121
|
|
|
|
122
|
|
|
$jsonLD = $document->getBody(); |
123
|
|
|
|
124
|
|
|
$jsonLD->{'@id'} = $this->iriGenerator->iri( |
125
|
|
|
$organizerCreated->getOrganizerId() |
126
|
|
|
); |
127
|
|
|
|
128
|
|
|
$this->setMainLanguage($jsonLD, new Language('nl')); |
129
|
|
|
|
130
|
|
|
$jsonLD->name = [ |
131
|
|
|
$this->getMainLanguage($jsonLD)->getCode() => $organizerCreated->getTitle() |
132
|
|
|
]; |
133
|
|
|
|
134
|
|
|
$addresses = $organizerCreated->getAddresses(); |
135
|
|
|
$jsonLD->addresses = array(); |
136
|
|
|
foreach ($addresses as $address) { |
137
|
|
|
$jsonLD->addresses[] = array( |
138
|
|
|
'addressCountry' => $address->getCountry(), |
139
|
|
|
'addressLocality' => $address->getLocality(), |
140
|
|
|
'postalCode' => $address->getPostalCode(), |
141
|
|
|
'streetAddress' => $address->getStreetAddress(), |
142
|
|
|
); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
$jsonLD->phone = $organizerCreated->getPhones(); |
146
|
|
|
$jsonLD->email = $organizerCreated->getEmails(); |
147
|
|
|
$jsonLD->url = $organizerCreated->getUrls(); |
148
|
|
|
|
149
|
|
|
$recordedOn = $domainMessage->getRecordedOn()->toString(); |
150
|
|
|
$jsonLD->created = \DateTime::createFromFormat( |
151
|
|
|
DateTime::FORMAT_STRING, |
152
|
|
|
$recordedOn |
153
|
|
|
)->format('c'); |
154
|
|
|
|
155
|
|
|
$metaData = $domainMessage->getMetadata()->serialize(); |
156
|
|
View Code Duplication |
if (isset($metaData['user_id']) && isset($metaData['user_nick'])) { |
|
|
|
|
157
|
|
|
$jsonLD->creator = "{$metaData['user_id']} ({$metaData['user_nick']})"; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @param OrganizerCreatedWithUniqueWebsite $organizerCreated |
165
|
|
|
* @param DomainMessage $domainMessage |
166
|
|
|
*/ |
167
|
|
|
private function applyOrganizerCreatedWithUniqueWebsite( |
168
|
|
|
OrganizerCreatedWithUniqueWebsite $organizerCreated, |
169
|
|
|
DomainMessage $domainMessage |
170
|
|
|
) { |
171
|
|
|
$document = $this->newDocument($organizerCreated->getOrganizerId()); |
172
|
|
|
|
173
|
|
|
$jsonLD = $document->getBody(); |
174
|
|
|
|
175
|
|
|
$jsonLD->{'@id'} = $this->iriGenerator->iri( |
176
|
|
|
$organizerCreated->getOrganizerId() |
177
|
|
|
); |
178
|
|
|
|
179
|
|
|
$this->setMainLanguage($jsonLD, new Language('nl')); |
180
|
|
|
|
181
|
|
|
$jsonLD->url = (string) $organizerCreated->getWebsite(); |
182
|
|
|
|
183
|
|
|
$jsonLD->name = [ |
184
|
|
|
$this->getMainLanguage($jsonLD)->getCode() => $organizerCreated->getTitle() |
185
|
|
|
]; |
186
|
|
|
|
187
|
|
|
$recordedOn = $domainMessage->getRecordedOn()->toString(); |
188
|
|
|
$jsonLD->created = \DateTime::createFromFormat( |
189
|
|
|
DateTime::FORMAT_STRING, |
190
|
|
|
$recordedOn |
191
|
|
|
)->format('c'); |
192
|
|
|
|
193
|
|
|
$metaData = $domainMessage->getMetadata()->serialize(); |
194
|
|
View Code Duplication |
if (isset($metaData['user_id']) && isset($metaData['user_nick'])) { |
|
|
|
|
195
|
|
|
$jsonLD->creator = "{$metaData['user_id']} ({$metaData['user_nick']})"; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* @param WebsiteUpdated $websiteUpdated |
203
|
|
|
*/ |
204
|
|
|
private function applyWebsiteUpdated(WebsiteUpdated $websiteUpdated) |
205
|
|
|
{ |
206
|
|
|
$organizerId = $websiteUpdated->getOrganizerId(); |
207
|
|
|
|
208
|
|
|
$document = $this->repository->get($organizerId); |
209
|
|
|
|
210
|
|
|
$jsonLD = $document->getBody(); |
211
|
|
|
$jsonLD->url = (string) $websiteUpdated->getWebsite(); |
212
|
|
|
|
213
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* @param TitleUpdated $titleUpdated |
218
|
|
|
*/ |
219
|
|
|
private function applyTitleUpdated(TitleUpdated $titleUpdated) |
220
|
|
|
{ |
221
|
|
|
$this->applyTitle($titleUpdated, $titleUpdated->getTitle()); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* @param TitleTranslated $titleTranslated |
226
|
|
|
*/ |
227
|
|
|
private function applyTitleTranslated(TitleTranslated $titleTranslated) |
228
|
|
|
{ |
229
|
|
|
$this->applyTitle( |
230
|
|
|
$titleTranslated, |
231
|
|
|
$titleTranslated->getTitle(), |
232
|
|
|
$titleTranslated->getLanguage() |
233
|
|
|
); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @param AddressUpdated $addressUpdated |
238
|
|
|
*/ |
239
|
|
View Code Duplication |
private function applyAddressUpdated(AddressUpdated $addressUpdated) |
|
|
|
|
240
|
|
|
{ |
241
|
|
|
$organizerId = $addressUpdated->getOrganizerId(); |
242
|
|
|
$address = $addressUpdated->getAddress(); |
243
|
|
|
|
244
|
|
|
$document = $this->repository->get($organizerId); |
245
|
|
|
|
246
|
|
|
$jsonLD = $document->getBody(); |
247
|
|
|
$jsonLD->address = $address->toJsonLd(); |
248
|
|
|
|
249
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* @param ContactPointUpdated $contactPointUpdated |
254
|
|
|
*/ |
255
|
|
View Code Duplication |
private function applyContactPointUpdated(ContactPointUpdated $contactPointUpdated) |
|
|
|
|
256
|
|
|
{ |
257
|
|
|
$organizerId = $contactPointUpdated->getOrganizerId(); |
258
|
|
|
$contactPoint = $contactPointUpdated->getContactPoint(); |
259
|
|
|
|
260
|
|
|
$document = $this->repository->get($organizerId); |
261
|
|
|
|
262
|
|
|
$jsonLD = $document->getBody(); |
263
|
|
|
$jsonLD->contactPoint = $contactPoint->toJsonLd(); |
264
|
|
|
|
265
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* @param OrganizerUpdatedFromUDB2 $organizerUpdatedFromUDB2 |
270
|
|
|
*/ |
271
|
|
View Code Duplication |
private function applyOrganizerUpdatedFromUDB2( |
|
|
|
|
272
|
|
|
OrganizerUpdatedFromUDB2 $organizerUpdatedFromUDB2 |
273
|
|
|
) { |
274
|
|
|
// It's possible that an organizer has been deleted in udb3, but never |
275
|
|
|
// in udb2. If an update comes for that organizer from udb2, it should |
276
|
|
|
// be imported again. This is intended by design. |
277
|
|
|
// @see https://jira.uitdatabank.be/browse/III-1092 |
278
|
|
|
try { |
279
|
|
|
$document = $this->loadDocumentFromRepository( |
280
|
|
|
$organizerUpdatedFromUDB2 |
281
|
|
|
); |
282
|
|
|
} catch (DocumentGoneException $e) { |
283
|
|
|
$document = $this->newDocument($organizerUpdatedFromUDB2->getActorId()); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
$udb2Actor = ActorItemFactory::createActorFromCdbXml( |
287
|
|
|
$organizerUpdatedFromUDB2->getCdbXmlNamespaceUri(), |
288
|
|
|
$organizerUpdatedFromUDB2->getCdbXml() |
289
|
|
|
); |
290
|
|
|
|
291
|
|
|
$actorLd = $this->cdbXMLImporter->documentWithCdbXML( |
292
|
|
|
$document->getBody(), |
293
|
|
|
$udb2Actor |
294
|
|
|
); |
295
|
|
|
|
296
|
|
|
$this->setMainLanguage($actorLd, new Language('nl')); |
297
|
|
|
|
298
|
|
|
$this->repository->save($document->withBody($actorLd)); |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* @param LabelAdded $labelAdded |
303
|
|
|
*/ |
304
|
|
View Code Duplication |
private function applyLabelAdded(LabelAdded $labelAdded) |
|
|
|
|
305
|
|
|
{ |
306
|
|
|
$document = $this->repository->get($labelAdded->getOrganizerId()); |
307
|
|
|
|
308
|
|
|
$jsonLD = $document->getBody(); |
309
|
|
|
|
310
|
|
|
// Check the visibility of the label to update the right property. |
311
|
|
|
$labelsProperty = $labelAdded->getLabel()->isVisible() ? 'labels' : 'hiddenLabels'; |
312
|
|
|
|
313
|
|
|
$labels = isset($jsonLD->{$labelsProperty}) ? $jsonLD->{$labelsProperty} : []; |
314
|
|
|
$label = (string) $labelAdded->getLabel(); |
315
|
|
|
|
316
|
|
|
$labels[] = $label; |
317
|
|
|
$jsonLD->{$labelsProperty} = array_unique($labels); |
318
|
|
|
|
319
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* @param LabelRemoved $labelRemoved |
324
|
|
|
*/ |
325
|
|
View Code Duplication |
private function applyLabelRemoved(LabelRemoved $labelRemoved) |
|
|
|
|
326
|
|
|
{ |
327
|
|
|
$document = $this->repository->get($labelRemoved->getOrganizerId()); |
328
|
|
|
$jsonLD = $document->getBody(); |
329
|
|
|
|
330
|
|
|
// Don't presume that the label visibility is correct when removing. |
331
|
|
|
// So iterate over both the visible and invisible labels. |
332
|
|
|
$labelsProperties = ['labels', 'hiddenLabels']; |
333
|
|
|
|
334
|
|
|
foreach ($labelsProperties as $labelsProperty) { |
335
|
|
|
if (isset($jsonLD->{$labelsProperty}) && is_array($jsonLD->{$labelsProperty})) { |
336
|
|
|
$jsonLD->{$labelsProperty} = array_filter( |
337
|
|
|
$jsonLD->{$labelsProperty}, |
338
|
|
|
function ($label) use ($labelRemoved) { |
339
|
|
|
return !$labelRemoved->getLabel()->equals( |
340
|
|
|
new Label($label) |
341
|
|
|
); |
342
|
|
|
} |
343
|
|
|
); |
344
|
|
|
|
345
|
|
|
// Ensure array keys start with 0 so json_encode() does encode it |
346
|
|
|
// as an array and not as an object. |
347
|
|
|
if (count($jsonLD->{$labelsProperty}) > 0) { |
348
|
|
|
$jsonLD->{$labelsProperty} = array_values($jsonLD->{$labelsProperty}); |
349
|
|
|
} else { |
350
|
|
|
unset($jsonLD->{$labelsProperty}); |
351
|
|
|
} |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
/** |
359
|
|
|
* @param OrganizerDeleted $organizerDeleted |
360
|
|
|
*/ |
361
|
|
|
private function applyOrganizerDeleted( |
362
|
|
|
OrganizerDeleted $organizerDeleted |
363
|
|
|
) { |
364
|
|
|
$this->repository->remove($organizerDeleted->getOrganizerId()); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* @param string $id |
369
|
|
|
* @return JsonDocument |
370
|
|
|
*/ |
371
|
|
View Code Duplication |
private function newDocument($id) |
|
|
|
|
372
|
|
|
{ |
373
|
|
|
$document = new JsonDocument($id); |
374
|
|
|
|
375
|
|
|
$organizerLd = $document->getBody(); |
376
|
|
|
$organizerLd->{'@id'} = $this->iriGenerator->iri($id); |
377
|
|
|
$organizerLd->{'@context'} = '/contexts/organizer'; |
378
|
|
|
|
379
|
|
|
return $document->withBody($organizerLd); |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
/** |
383
|
|
|
* @param OrganizerEvent $organizerEvent |
384
|
|
|
* @param Title $title |
385
|
|
|
* @param Language|null $language |
386
|
|
|
*/ |
387
|
|
|
private function applyTitle( |
388
|
|
|
OrganizerEvent $organizerEvent, |
389
|
|
|
Title $title, |
390
|
|
|
Language $language = null |
391
|
|
|
) { |
392
|
|
|
$organizerId = $organizerEvent->getOrganizerId(); |
393
|
|
|
|
394
|
|
|
$document = $this->repository->get($organizerId); |
395
|
|
|
|
396
|
|
|
$jsonLD = $document->getBody(); |
397
|
|
|
|
398
|
|
|
$mainLanguage = $this->getMainLanguage($jsonLD); |
399
|
|
|
if ($language === null) { |
400
|
|
|
$language = $mainLanguage; |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
// @replay_i18n For old projections the name is untranslated and just a string. |
404
|
|
|
// This needs to be upgraded to an object with languages and translation. |
405
|
|
|
// When a full replay is done this code becomes obsolete. |
406
|
|
|
// @see https://jira.uitdatabank.be/browse/III-2201 |
407
|
|
|
if (isset($jsonLD->name) && is_string($jsonLD->name)) { |
408
|
|
|
$previousTitle = $jsonLD->name; |
409
|
|
|
$jsonLD->name = new \StdClass(); |
410
|
|
|
$jsonLD->name->{$mainLanguage->getCode()} = $previousTitle; |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
$jsonLD->name->{$language->getCode()} = $title->toNative(); |
414
|
|
|
|
415
|
|
|
$this->repository->save($document->withBody($jsonLD)); |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
/** |
419
|
|
|
* @param ActorEvent $actor |
420
|
|
|
* @return JsonDocument |
421
|
|
|
*/ |
422
|
|
|
private function loadDocumentFromRepository(ActorEvent $actor) |
423
|
|
|
{ |
424
|
|
|
$document = $this->repository->get($actor->getActorId()); |
425
|
|
|
|
426
|
|
|
if (!$document) { |
427
|
|
|
return $this->newDocument($actor->getActorId()); |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
return $document; |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
|
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.