Completed
Pull Request — master (#306)
by Luc
06:57 queued 01:33
created

CdbXMLImporter::importDescription()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 6
nc 3
nop 3
1
<?php
2
3
namespace CultuurNet\UDB3\Event\ReadModel\JSONLD;
4
5
use CultuurNet\UDB3\CalendarFactoryInterface;
6
use CultuurNet\UDB3\Cdb\CdbId\EventCdbIdExtractorInterface;
7
use CultuurNet\UDB3\Cdb\Description\MergedDescription;
8
use CultuurNet\UDB3\Cdb\PriceDescriptionParser;
9
use CultuurNet\UDB3\Event\ValueObjects\Audience;
10
use CultuurNet\UDB3\Event\ValueObjects\AudienceType;
11
use CultuurNet\UDB3\LabelImporter;
12
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\CdbXmlContactInfoImporterInterface;
13
use CultuurNet\UDB3\Offer\ReadModel\JSONLD\CdbXMLItemBaseImporter;
14
use CultuurNet\UDB3\SluggerInterface;
15
16
/**
17
 * Takes care of importing cultural events in the CdbXML format (UDB2)
18
 * into a UDB3 JSON-LD document.
19
 */
20
class CdbXMLImporter
21
{
22
    /**
23
     * @var CdbXMLItemBaseImporter
24
     */
25
    private $cdbXMLItemBaseImporter;
26
27
    /**
28
     * @var EventCdbIdExtractorInterface
29
     */
30
    private $cdbIdExtractor;
31
32
    /**
33
     * @var PriceDescriptionParser
34
     */
35
    private $priceDescriptionParser;
36
37
    /**
38
     * @var CalendarFactoryInterface
39
     */
40
    private $calendarFactory;
41
42
    /**
43
     * @var CdbXmlContactInfoImporterInterface
44
     */
45
    private $cdbXmlContactInfoImporter;
46
47
    /**
48
     * @param CdbXMLItemBaseImporter $cdbXMLItemBaseImporter
49
     * @param EventCdbIdExtractorInterface $cdbIdExtractor
50
     * @param PriceDescriptionParser $priceDescriptionParser
51
     * @param CalendarFactoryInterface $calendarFactory
52
     * @param CdbXmlContactInfoImporterInterface $cdbXmlContactInfoImporter
53
     */
54
    public function __construct(
55
        CdbXMLItemBaseImporter $cdbXMLItemBaseImporter,
56
        EventCdbIdExtractorInterface $cdbIdExtractor,
57
        PriceDescriptionParser $priceDescriptionParser,
58
        CalendarFactoryInterface $calendarFactory,
59
        CdbXmlContactInfoImporterInterface $cdbXmlContactInfoImporter
60
    ) {
61
        $this->cdbXMLItemBaseImporter = $cdbXMLItemBaseImporter;
62
        $this->cdbIdExtractor = $cdbIdExtractor;
63
        $this->priceDescriptionParser = $priceDescriptionParser;
64
        $this->calendarFactory = $calendarFactory;
65
        $this->cdbXmlContactInfoImporter = $cdbXmlContactInfoImporter;
66
    }
67
68
    /**
69
     * Imports a UDB2 event into a UDB3 JSON-LD document.
70
     *
71
     * @param \stdClass $base
72
     *   The JSON-LD document to start from.
73
     * @param \CultureFeed_Cdb_Item_Event $event
74
     *   The cultural event data from UDB2 to import.
75
     * @param PlaceServiceInterface $placeManager
76
     *   The manager from which to retrieve the JSON-LD of a place.
77
     * @param OrganizerServiceInterface $organizerManager
78
     *   The manager from which to retrieve the JSON-LD of an organizer.
79
     * @param SluggerInterface $slugger
80
     *   The slugger that's used to generate a sameAs reference.
81
     *
82
     * @return \stdClass
83
     *   The document with the UDB2 event data merged in.
84
     */
85
    public function documentWithCdbXML(
86
        $base,
87
        \CultureFeed_Cdb_Item_Event $event,
88
        PlaceServiceInterface $placeManager,
89
        OrganizerServiceInterface $organizerManager,
90
        SluggerInterface $slugger
91
    ) {
92
        $jsonLD = clone $base;
93
94
        /** @var \CultureFeed_Cdb_Data_EventDetail $detail */
95
        $detail = null;
96
97
        /** @var \CultureFeed_Cdb_Data_EventDetail[] $details */
98
        $details = $event->getDetails();
99
100
        foreach ($details as $languageDetail) {
101
            $language = $languageDetail->getLanguage();
102
103
            // The first language detail found will be used to retrieve
104
            // properties from which in UDB3 are not any longer considered
105
            // to be language specific.
106
            if (!$detail) {
107
                $detail = $languageDetail;
108
            }
109
110
            $jsonLD->name[$language] = $languageDetail->getTitle();
111
112
            $this->importDescription($languageDetail, $jsonLD, $language);
113
        }
114
115
        $this->cdbXMLItemBaseImporter->importAvailable($event, $jsonLD);
116
117
        $labelImporter = new LabelImporter();
118
        $labelImporter->importLabels($event, $jsonLD);
119
120
        $jsonLD->calendarSummary = $detail->getCalendarSummary();
121
122
        $this->importLocation($event, $placeManager, $jsonLD);
123
124
        $this->importOrganizer($event, $organizerManager, $jsonLD);
125
126 View Code Duplication
        if ($event->getContactInfo()) {
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...
127
            $this->cdbXmlContactInfoImporter->importBookingInfo(
128
                $jsonLD,
129
                $event->getContactInfo(),
130
                $detail->getPrice(),
131
                $event->getBookingPeriod()
132
            );
133
134
            $this->cdbXmlContactInfoImporter->importContactPoint(
135
                $jsonLD,
136
                $event->getContactInfo()
137
            );
138
        }
139
140
        $this->importPriceInfo($detail, $jsonLD);
141
142
        $this->importTerms($event, $jsonLD);
143
144
        $this->cdbXMLItemBaseImporter->importPublicationInfo($event, $jsonLD);
145
146
        $calendar = $this->calendarFactory->createFromCdbCalendar($event->getCalendar());
147
        $jsonLD = (object)array_merge((array)$jsonLD, $calendar->toJsonLd());
148
149
        $this->importTypicalAgeRange($event, $jsonLD);
150
151
        $this->importPerformers($detail, $jsonLD);
152
153
        $this->importLanguages($event, $jsonLD);
154
155
        $this->importUitInVlaanderenReference($event, $slugger, $jsonLD);
156
157
        $this->cdbXMLItemBaseImporter->importExternalId($event, $jsonLD);
158
159
        $this->importSeeAlso($event, $jsonLD);
160
161
        $this->cdbXMLItemBaseImporter->importWorkflowStatus($event, $jsonLD);
162
163
        $this->importAudience($event, $jsonLD);
164
165
        return $jsonLD;
166
    }
167
168
    /**
169
     * @param \CultureFeed_Cdb_Data_EventDetail $languageDetail
170
     * @param \stdClass $jsonLD
171
     * @param string $language
172
     */
173
    private function importDescription($languageDetail, $jsonLD, $language)
174
    {
175
        try {
176
            $description = MergedDescription::fromCdbDetail($languageDetail);
177
            $jsonLD->description[$language] = $description->toNative();
178
        } catch (\InvalidArgumentException $e) {
179
            return;
180
        }
181
    }
182
183
    /**
184
     * @param \CultureFeed_Cdb_Item_Event $event
185
     * @param PlaceServiceInterface $placeManager
186
     * @param \stdClass $jsonLD
187
     */
188
    private function importLocation(\CultureFeed_Cdb_Item_Event $event, PlaceServiceInterface $placeManager, $jsonLD)
189
    {
190
        $location = array();
191
        $location['@type'] = 'Place';
192
193
        $location_id = $this->cdbIdExtractor->getRelatedPlaceCdbId($event);
194
195
        if ($location_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $location_id of type string|null is loosely compared to true; 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...
196
            $location += (array)$placeManager->placeJSONLD($location_id);
197
        } else {
198
            $location_cdb = $event->getLocation();
199
            $location['name']['nl'] = $location_cdb->getLabel();
200
            $address = $location_cdb->getAddress()->getPhysicalAddress();
201
            if ($address) {
202
                $location['address'] = array(
203
                    'addressCountry' => $address->getCountry(),
204
                    'addressLocality' => $address->getCity(),
205
                    'postalCode' => $address->getZip(),
206
                    'streetAddress' =>
207
                        $address->getStreet() . ' ' . $address->getHouseNumber(
208
                        ),
209
                );
210
            }
211
        }
212
        $jsonLD->location = $location;
213
    }
214
215
    /**
216
     * @param \CultureFeed_Cdb_Item_Event $event
217
     * @param OrganizerServiceInterface $organizerManager
218
     * @param \stdClass $jsonLD
219
     */
220
    private function importOrganizer(
221
        \CultureFeed_Cdb_Item_Event $event,
222
        OrganizerServiceInterface $organizerManager,
223
        $jsonLD
224
    ) {
225
        $organizer = null;
226
        $organizer_id = $this->cdbIdExtractor->getRelatedOrganizerCdbId($event);
227
        $organizer_cdb = $event->getOrganiser();
228
        $contact_info_cdb = $event->getContactInfo();
229
230
        if ($organizer_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $organizer_id of type string|null is loosely compared to true; 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...
231
            $organizer = (array)$organizerManager->organizerJSONLD($organizer_id);
232
        } elseif ($organizer_cdb && $contact_info_cdb) {
233
            $organizer = array();
234
            $organizer['name'] = $organizer_cdb->getLabel();
235
236
            $emails_cdb = $contact_info_cdb->getMails();
237
            if (count($emails_cdb) > 0) {
238
                $organizer['email'] = array();
239
                foreach ($emails_cdb as $email) {
240
                    $organizer['email'][] = $email->getMailAddress();
241
                }
242
            }
243
244
            /** @var \CultureFeed_Cdb_Data_Phone[] $phones_cdb */
245
            $phones_cdb = $contact_info_cdb->getPhones();
246
            if (count($phones_cdb) > 0) {
247
                $organizer['phone'] = array();
248
                foreach ($phones_cdb as $phone) {
249
                    $organizer['phone'][] = $phone->getNumber();
250
                }
251
            }
252
        }
253
254
        if (!is_null($organizer)) {
255
            $organizer['@type'] = 'Organizer';
256
            $jsonLD->organizer = $organizer;
257
        }
258
    }
259
260
    /**
261
     * @param \CultureFeed_Cdb_Data_EventDetail $detail
262
     * @param \stdClass $jsonLD
263
     */
264
    private function importPriceInfo(
265
        \CultureFeed_Cdb_Data_EventDetail $detail,
266
        $jsonLD
267
    ) {
268
        $prices = array();
269
270
        $price = $detail->getPrice();
271
272
        if ($price) {
273
            $description = $price->getDescription();
274
275
            if ($description) {
276
                $prices = $this->priceDescriptionParser->parse($description);
277
            }
278
279
            $priceValue = $price->getValue();
280
281
            if ($priceValue !== null) {
282
                $priceValue = floatval($priceValue);
283
            }
284
285
            // Ignore prices parsed from description when its base price
286
            // does not equal the cdbxml price value.
287
            if (!empty($prices) && $prices['Basistarief'] !== $priceValue) {
288
                $prices = [];
289
            }
290
291
            // If price description was not interpretable, fall back to
292
            // price title and value.
293
            if (empty($prices) && $priceValue !== null) {
294
                $prices['Basistarief'] = floatval($price->getValue());
295
            }
296
        }
297
298
        if (!empty($prices)) {
299
            $priceInfo = array();
300
301
            /** @var \CultureFeed_Cdb_Data_Price $price */
302
            foreach ($prices as $title => $value) {
303
                $priceInfoItem = array(
304
                    'name' => $title,
305
                    'priceCurrency' => 'EUR',
306
                    'price' => $value,
307
                );
308
309
                $priceInfoItem['category'] = 'tariff';
310
311
                if ($priceInfoItem['name'] === 'Basistarief') {
312
                    $priceInfoItem['category'] = 'base';
313
                }
314
315
                $priceInfo[] = $priceInfoItem;
316
            }
317
318
            if (!empty($priceInfo)) {
319
                $jsonLD->priceInfo = $priceInfo;
320
            }
321
        }
322
    }
323
324
    /**
325
     * @param \CultureFeed_Cdb_Item_Event $event
326
     * @param \stdClass $jsonLD
327
     */
328
    private function importTerms(\CultureFeed_Cdb_Item_Event $event, $jsonLD)
329
    {
330
        $themeBlacklist = [
331
            'Thema onbepaald',
332
            'Meerder kunstvormen',
333
            'Meerdere filmgenres'
334
        ];
335
        $categories = array();
336 View Code Duplication
        foreach ($event->getCategories() as $category) {
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...
337
            /* @var \Culturefeed_Cdb_Data_Category $category */
338
            if ($category && !in_array($category->getName(), $themeBlacklist)) {
339
                $categories[] = array(
340
                    'label' => $category->getName(),
341
                    'domain' => $category->getType(),
342
                    'id' => $category->getId(),
343
                );
344
            }
345
        }
346
        $jsonLD->terms = $categories;
347
    }
348
349
    /**
350
     * @param \CultureFeed_Cdb_Item_Event $event
351
     * @param \stdClass $jsonLD
352
     */
353
    private function importTypicalAgeRange(\CultureFeed_Cdb_Item_Event $event, $jsonLD)
354
    {
355
        $ageFrom = $event->getAgeFrom();
356
        $ageTo = $event->getAgeTo();
357
358
        if (!is_int($ageFrom) && !is_int($ageTo)) {
359
            return;
360
        }
361
362
        $jsonLD->typicalAgeRange = "{$ageFrom}-{$ageTo}";
363
    }
364
365
    /**
366
     * @param \CultureFeed_Cdb_Data_EventDetail $detail
367
     * @param \stdClass $jsonLD
368
     */
369
    private function importPerformers(\CultureFeed_Cdb_Data_EventDetail $detail, $jsonLD)
370
    {
371
        /** @var \CultureFeed_Cdb_Data_Performer $performer */
372
        $performers = $detail->getPerformers();
373
        if ($performers) {
374
            foreach ($performers as $performer) {
375
                if ($performer->getLabel()) {
376
                    $performerData = new \stdClass();
377
                    $performerData->name = $performer->getLabel();
378
                    $jsonLD->performer[] = $performerData;
379
                }
380
            }
381
        }
382
    }
383
384
    /**
385
     * @param \CultureFeed_Cdb_Item_Event $event
386
     * @param \stdClass $jsonLD
387
     */
388
    private function importLanguages(\CultureFeed_Cdb_Item_Event $event, $jsonLD)
389
    {
390
        /** @var \CultureFeed_Cdb_Data_Language $udb2Language */
391
        $languages = $event->getLanguages();
392
        if ($languages) {
393
            $jsonLD->language = [];
394
            foreach ($languages as $udb2Language) {
395
                $jsonLD->language[] = $udb2Language->getLanguage();
396
            }
397
            $jsonLD->language = array_unique($jsonLD->language);
398
        }
399
    }
400
401
    /**
402
     * @param \CultureFeed_Cdb_Item_Event $event
403
     * @param \stdClass $jsonLD
404
     */
405
    private function importSeeAlso(
406
        \CultureFeed_Cdb_Item_Event $event,
407
        \stdClass $jsonLD
408
    ) {
409
        if (!property_exists($jsonLD, 'seeAlso')) {
410
            $jsonLD->seeAlso = [];
411
        }
412
413
        // Add contact info url, if it's not for reservations.
414
        if ($contactInfo = $event->getContactInfo()) {
415
            /** @var \CultureFeed_Cdb_Data_Url[] $contactUrls */
416
            $contactUrls = $contactInfo->getUrls();
417
            if (is_array($contactUrls) && count($contactUrls) > 0) {
418
                foreach ($contactUrls as $contactUrl) {
419
                    if (!$contactUrl->isForReservations()) {
420
                        $jsonLD->seeAlso[] = $contactUrl->getUrl();
421
                    }
422
                }
423
            }
424
        }
425
    }
426
427
    /**
428
     * @param \CultureFeed_Cdb_Item_Event $event
429
     * @param SluggerInterface $slugger
430
     * @param \stdClass $jsonLD
431
     */
432
    private function importUitInVlaanderenReference(
433
        \CultureFeed_Cdb_Item_Event $event,
434
        SluggerInterface $slugger,
435
        $jsonLD
436
    ) {
437
438
        // Some events seem to not have a Dutch name, even though this is
439
        // required. If there's no Dutch name, we just leave the slug empty as
440
        // that seems to be the behaviour on http://m.uitinvlaanderen.be
441
        if (isset($jsonLD->name['nl'])) {
442
            $name = $jsonLD->name['nl'];
443
            $slug = $slugger->slug($name);
444
        } else {
445
            $slug = '';
446
        }
447
448
        $reference = 'http://www.uitinvlaanderen.be/agenda/e/' . $slug . '/' . $event->getCdbId();
449
450
451
        if (!property_exists($jsonLD, 'sameAs')) {
452
            $jsonLD->sameAs = [];
453
        }
454
455
        if (!in_array($reference, $jsonLD->sameAs)) {
456
            array_push($jsonLD->sameAs, $reference);
457
        }
458
    }
459
460
    /**
461
     * @param \CultureFeed_Cdb_Item_Event $event
462
     * @param \stdClass $jsonLD
463
     */
464
    private function importAudience(\CultureFeed_Cdb_Item_Event $event, \stdClass $jsonLD)
465
    {
466
        $eventIsPrivate = (bool) $event->isPrivate();
467
        $eventTargetsEducation = $eventIsPrivate && $event->getCategories()->hasCategory('2.1.3.0.0');
468
469
        $audienceType = $eventTargetsEducation ? 'education' : ($eventIsPrivate ? 'members' : 'everyone');
470
        $audience = new Audience(AudienceType::fromNative($audienceType));
471
472
        $jsonLD->audience = $audience->serialize();
473
    }
474
}
475