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