Completed
Pull Request — master (#309)
by Luc
08:47
created

CdbXMLImporter::longDescriptionStartsWithShortDescription()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 2
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->importUitInVlaanderenReference($event, $slugger, $jsonLD);
154
155
        $this->cdbXMLItemBaseImporter->importExternalId($event, $jsonLD);
156
157
        $this->importSeeAlso($event, $jsonLD);
158
159
        $this->cdbXMLItemBaseImporter->importWorkflowStatus($event, $jsonLD);
160
161
        $this->importAudience($event, $jsonLD);
162
163
        return $jsonLD;
164
    }
165
166
    /**
167
     * @param \CultureFeed_Cdb_Data_EventDetail $languageDetail
168
     * @param \stdClass $jsonLD
169
     * @param string $language
170
     */
171
    private function importDescription($languageDetail, $jsonLD, $language)
172
    {
173
        try {
174
            $description = MergedDescription::fromCdbDetail($languageDetail);
175
            $jsonLD->description[$language] = $description->toNative();
176
        } catch (\InvalidArgumentException $e) {
177
            return;
178
        }
179
    }
180
181
    /**
182
     * @param \CultureFeed_Cdb_Item_Event $event
183
     * @param PlaceServiceInterface $placeManager
184
     * @param \stdClass $jsonLD
185
     */
186
    private function importLocation(\CultureFeed_Cdb_Item_Event $event, PlaceServiceInterface $placeManager, $jsonLD)
187
    {
188
        $location = array();
189
        $location['@type'] = 'Place';
190
191
        $location_id = $this->cdbIdExtractor->getRelatedPlaceCdbId($event);
192
193
        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...
194
            $location += (array)$placeManager->placeJSONLD($location_id);
195
        } else {
196
            $location_cdb = $event->getLocation();
197
            $location['name']['nl'] = $location_cdb->getLabel();
198
            $address = $location_cdb->getAddress()->getPhysicalAddress();
199
            if ($address) {
200
                $location['address'] = array(
201
                    'addressCountry' => $address->getCountry(),
202
                    'addressLocality' => $address->getCity(),
203
                    'postalCode' => $address->getZip(),
204
                    'streetAddress' =>
205
                        $address->getStreet() . ' ' . $address->getHouseNumber(
206
                        ),
207
                );
208
            }
209
        }
210
        $jsonLD->location = $location;
211
    }
212
213
    /**
214
     * @param \CultureFeed_Cdb_Item_Event $event
215
     * @param OrganizerServiceInterface $organizerManager
216
     * @param \stdClass $jsonLD
217
     */
218
    private function importOrganizer(
219
        \CultureFeed_Cdb_Item_Event $event,
220
        OrganizerServiceInterface $organizerManager,
221
        $jsonLD
222
    ) {
223
        $organizer = null;
224
        $organizer_id = $this->cdbIdExtractor->getRelatedOrganizerCdbId($event);
225
        $organizer_cdb = $event->getOrganiser();
226
        $contact_info_cdb = $event->getContactInfo();
227
228
        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...
229
            $organizer = (array)$organizerManager->organizerJSONLD($organizer_id);
230
        } elseif ($organizer_cdb && $contact_info_cdb) {
231
            $organizer = array();
232
            $organizer['name'] = $organizer_cdb->getLabel();
233
234
            $emails_cdb = $contact_info_cdb->getMails();
235
            if (count($emails_cdb) > 0) {
236
                $organizer['email'] = array();
237
                foreach ($emails_cdb as $email) {
238
                    $organizer['email'][] = $email->getMailAddress();
239
                }
240
            }
241
242
            /** @var \CultureFeed_Cdb_Data_Phone[] $phones_cdb */
243
            $phones_cdb = $contact_info_cdb->getPhones();
244
            if (count($phones_cdb) > 0) {
245
                $organizer['phone'] = array();
246
                foreach ($phones_cdb as $phone) {
247
                    $organizer['phone'][] = $phone->getNumber();
248
                }
249
            }
250
        }
251
252
        if (!is_null($organizer)) {
253
            $organizer['@type'] = 'Organizer';
254
            $jsonLD->organizer = $organizer;
255
        }
256
    }
257
258
    /**
259
     * @param \CultureFeed_Cdb_Data_EventDetail $detail
260
     * @param \stdClass $jsonLD
261
     */
262
    private function importPriceInfo(
263
        \CultureFeed_Cdb_Data_EventDetail $detail,
264
        $jsonLD
265
    ) {
266
        $prices = array();
267
268
        $price = $detail->getPrice();
269
270
        if ($price) {
271
            $description = $price->getDescription();
272
273
            if ($description) {
274
                $prices = $this->priceDescriptionParser->parse($description);
275
            }
276
277
            $priceValue = $price->getValue();
278
279
            if ($priceValue !== null) {
280
                $priceValue = floatval($priceValue);
281
            }
282
283
            // Ignore prices parsed from description when its base price
284
            // does not equal the cdbxml price value.
285
            if (!empty($prices) && $prices['Basistarief'] !== $priceValue) {
286
                $prices = [];
287
            }
288
289
            // If price description was not interpretable, fall back to
290
            // price title and value.
291
            if (empty($prices) && $priceValue !== null) {
292
                $prices['Basistarief'] = floatval($price->getValue());
293
            }
294
        }
295
296
        if (!empty($prices)) {
297
            $priceInfo = array();
298
299
            /** @var \CultureFeed_Cdb_Data_Price $price */
300
            foreach ($prices as $title => $value) {
301
                $priceInfoItem = array(
302
                    'name' => $title,
303
                    'priceCurrency' => 'EUR',
304
                    'price' => $value,
305
                );
306
307
                $priceInfoItem['category'] = 'tariff';
308
309
                if ($priceInfoItem['name'] === 'Basistarief') {
310
                    $priceInfoItem['category'] = 'base';
311
                }
312
313
                $priceInfo[] = $priceInfoItem;
314
            }
315
316
            if (!empty($priceInfo)) {
317
                $jsonLD->priceInfo = $priceInfo;
318
            }
319
        }
320
    }
321
322
    /**
323
     * @param \CultureFeed_Cdb_Item_Event $event
324
     * @param \stdClass $jsonLD
325
     */
326
    private function importTerms(\CultureFeed_Cdb_Item_Event $event, $jsonLD)
327
    {
328
        $themeBlacklist = [
329
            'Thema onbepaald',
330
            'Meerder kunstvormen',
331
            'Meerdere filmgenres'
332
        ];
333
        $categories = array();
334 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...
335
            /* @var \Culturefeed_Cdb_Data_Category $category */
336
            if ($category && !in_array($category->getName(), $themeBlacklist)) {
337
                $categories[] = array(
338
                    'label' => $category->getName(),
339
                    'domain' => $category->getType(),
340
                    'id' => $category->getId(),
341
                );
342
            }
343
        }
344
        $jsonLD->terms = $categories;
345
    }
346
347
    /**
348
     * @param \CultureFeed_Cdb_Item_Event $event
349
     * @param \stdClass $jsonLD
350
     */
351
    private function importTypicalAgeRange(\CultureFeed_Cdb_Item_Event $event, $jsonLD)
352
    {
353
        $ageFrom = $event->getAgeFrom();
354
        $ageTo = $event->getAgeTo();
355
356
        if (!is_int($ageFrom) && !is_int($ageTo)) {
357
            return;
358
        }
359
360
        $jsonLD->typicalAgeRange = "{$ageFrom}-{$ageTo}";
361
    }
362
363
    /**
364
     * @param \CultureFeed_Cdb_Data_EventDetail $detail
365
     * @param \stdClass $jsonLD
366
     */
367
    private function importPerformers(\CultureFeed_Cdb_Data_EventDetail $detail, $jsonLD)
368
    {
369
        /** @var \CultureFeed_Cdb_Data_Performer $performer */
370
        $performers = $detail->getPerformers();
371
        if ($performers) {
372
            foreach ($performers as $performer) {
373
                if ($performer->getLabel()) {
374
                    $performerData = new \stdClass();
375
                    $performerData->name = $performer->getLabel();
376
                    $jsonLD->performer[] = $performerData;
377
                }
378
            }
379
        }
380
    }
381
382
    /**
383
     * @param \CultureFeed_Cdb_Item_Event $event
384
     * @param \stdClass $jsonLD
385
     */
386
    private function importSeeAlso(
387
        \CultureFeed_Cdb_Item_Event $event,
388
        \stdClass $jsonLD
389
    ) {
390
        if (!property_exists($jsonLD, 'seeAlso')) {
391
            $jsonLD->seeAlso = [];
392
        }
393
394
        // Add contact info url, if it's not for reservations.
395
        if ($contactInfo = $event->getContactInfo()) {
396
            /** @var \CultureFeed_Cdb_Data_Url[] $contactUrls */
397
            $contactUrls = $contactInfo->getUrls();
398
            if (is_array($contactUrls) && count($contactUrls) > 0) {
399
                foreach ($contactUrls as $contactUrl) {
400
                    if (!$contactUrl->isForReservations()) {
401
                        $jsonLD->seeAlso[] = $contactUrl->getUrl();
402
                    }
403
                }
404
            }
405
        }
406
    }
407
408
    /**
409
     * @param \CultureFeed_Cdb_Item_Event $event
410
     * @param SluggerInterface $slugger
411
     * @param \stdClass $jsonLD
412
     */
413
    private function importUitInVlaanderenReference(
414
        \CultureFeed_Cdb_Item_Event $event,
415
        SluggerInterface $slugger,
416
        $jsonLD
417
    ) {
418
419
        // Some events seem to not have a Dutch name, even though this is
420
        // required. If there's no Dutch name, we just leave the slug empty as
421
        // that seems to be the behaviour on http://m.uitinvlaanderen.be
422
        if (isset($jsonLD->name['nl'])) {
423
            $name = $jsonLD->name['nl'];
424
            $slug = $slugger->slug($name);
425
        } else {
426
            $slug = '';
427
        }
428
429
        $reference = 'http://www.uitinvlaanderen.be/agenda/e/' . $slug . '/' . $event->getCdbId();
430
431
432
        if (!property_exists($jsonLD, 'sameAs')) {
433
            $jsonLD->sameAs = [];
434
        }
435
436
        if (!in_array($reference, $jsonLD->sameAs)) {
437
            array_push($jsonLD->sameAs, $reference);
438
        }
439
    }
440
441
    /**
442
     * @param \CultureFeed_Cdb_Item_Event $event
443
     * @param \stdClass $jsonLD
444
     */
445
    private function importAudience(\CultureFeed_Cdb_Item_Event $event, \stdClass $jsonLD)
446
    {
447
        $eventIsPrivate = (bool) $event->isPrivate();
448
        $eventTargetsEducation = $eventIsPrivate && $event->getCategories()->hasCategory('2.1.3.0.0');
449
450
        $audienceType = $eventTargetsEducation ? 'education' : ($eventIsPrivate ? 'members' : 'everyone');
451
        $audience = new Audience(AudienceType::fromNative($audienceType));
452
453
        $jsonLD->audience = $audience->serialize();
454
    }
455
}
456