Completed
Push — master ( 5ace45...cd9bd4 )
by
unknown
14s queued 10s
created

Organizer::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
namespace CultuurNet\UDB3\Organizer;
4
5
use Broadway\EventSourcing\EventSourcedAggregateRoot;
6
use CultuurNet\UDB3\Address\Address;
7
use CultuurNet\UDB3\Cdb\ActorItemFactory;
8
use CultuurNet\UDB3\Cdb\UpdateableWithCdbXmlInterface;
9
use CultuurNet\UDB3\ContactPoint;
10
use CultuurNet\UDB3\Label;
11
use CultuurNet\UDB3\LabelAwareAggregateRoot;
12
use CultuurNet\UDB3\LabelCollection;
13
use CultuurNet\UDB3\Language;
14
use CultuurNet\UDB3\Model\ValueObject\Taxonomy\Label\LabelName;
15
use CultuurNet\UDB3\Model\ValueObject\Taxonomy\Label\Labels;
16
use CultuurNet\UDB3\Organizer\Commands\ImportLabels;
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\LabelsImported;
22
use CultuurNet\UDB3\Organizer\Events\OrganizerCreated;
23
use CultuurNet\UDB3\Organizer\Events\OrganizerCreatedWithUniqueWebsite;
24
use CultuurNet\UDB3\Organizer\Events\OrganizerDeleted;
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\Title;
31
use ValueObjects\Web\Url;
32
33
class Organizer extends EventSourcedAggregateRoot implements UpdateableWithCdbXmlInterface, LabelAwareAggregateRoot
34
{
35
    /**
36
     * The actor id.
37
     *
38
     * @var string
39
     */
40
    protected $actorId;
41
42
    /**
43
     * @var Language
44
     */
45
    private $mainLanguage;
46
47
    /**
48
     * @var Url
49
     */
50
    private $website;
51
52
    /**
53
     * @var Title[]
54
     */
55
    private $titles;
56
57
    /**
58
     * @var Address|null
59
     */
60
    private $address;
61
62
    /**
63
     * @var ContactPoint
64
     */
65
    private $contactPoint;
66
67
    /**
68
     * @var LabelCollection|Label[]
69
     */
70
    private $labels;
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    public function getAggregateRootId()
76
    {
77
        return $this->actorId;
78
    }
79
80
    public function __construct()
81
    {
82
        // Contact points can be empty, but we only want to start recording
83
        // ContactPointUpdated events as soon as the organizer is updated
84
        // with a non-empty contact point. To enforce this we initialize the
85
        // aggregate state with an empty contact point.
86
        $this->contactPoint = new ContactPoint();
87
        $this->labels = new LabelCollection();
88
    }
89
90
    /**
91
     * Import from UDB2.
92
     *
93
     * @param string $actorId
94
     *   The actor id.
95
     * @param string $cdbXml
96
     *   The cdb xml.
97
     * @param string $cdbXmlNamespaceUri
98
     *   The cdb xml namespace uri.
99
     *
100
     * @return Organizer
101
     *   The actor.
102
     */
103
    public static function importFromUDB2(
104
        $actorId,
105
        $cdbXml,
106
        $cdbXmlNamespaceUri
107
    ) {
108
        $organizer = new static();
109
        $organizer->apply(
110
            new OrganizerImportedFromUDB2(
111
                $actorId,
112
                $cdbXml,
113
                $cdbXmlNamespaceUri
114
            )
115
        );
116
117
        return $organizer;
118
    }
119
120
    /**
121
     * Factory method to create a new Organizer.
122
     *
123
     * @param string $id
124
     * @param Language $mainLanguage
125
     * @param Url $website
126
     * @param Title $title
127
     * @return Organizer
128
     */
129
    public static function create(
130
        $id,
131
        Language $mainLanguage,
132
        Url $website,
133
        Title $title
134
    ) {
135
        $organizer = new self();
136
137
        $organizer->apply(
138
            new OrganizerCreatedWithUniqueWebsite($id, $mainLanguage, $website, $title)
139
        );
140
141
        return $organizer;
142
    }
143
144
    /**
145
     * @inheritdoc
146
     */
147
    public function updateWithCdbXml($cdbXml, $cdbXmlNamespaceUri)
148
    {
149
        $this->apply(
150
            new OrganizerUpdatedFromUDB2(
151
                $this->actorId,
152
                $cdbXml,
153
                $cdbXmlNamespaceUri
154
            )
155
        );
156
    }
157
158
    /**
159
     * @param Url $website
160
     */
161
    public function updateWebsite(Url $website)
162
    {
163
        if (is_null($this->website) || !$this->website->sameValueAs($website)) {
164
            $this->apply(
165
                new WebsiteUpdated(
166
                    $this->actorId,
167
                    $website
168
                )
169
            );
170
        }
171
    }
172
173
    /**
174
     * @param Title $title
175
     * @param Language $language
176
     */
177
    public function updateTitle(
178
        Title $title,
179
        Language $language
180
    ) {
181
        if ($this->isTitleChanged($title, $language)) {
182
            if ($language->getCode() !== $this->mainLanguage->getCode()) {
183
                $event = new TitleTranslated(
184
                    $this->actorId,
185
                    $title,
186
                    $language
187
                );
188
            } else {
189
                $event = new TitleUpdated(
190
                    $this->actorId,
191
                    $title
192
                );
193
            }
194
195
            $this->apply($event);
196
        }
197
    }
198
199
    /**
200
     * @param Address $address
201
     */
202
    public function updateAddress(Address $address)
203
    {
204
        if (is_null($this->address) || !$this->address->sameAs($address)) {
205
            $this->apply(
206
                new AddressUpdated($this->actorId, $address)
207
            );
208
        }
209
    }
210
211
    /**
212
     * @param ContactPoint $contactPoint
213
     */
214
    public function updateContactPoint(ContactPoint $contactPoint)
215
    {
216
        if (!$this->contactPoint->sameAs($contactPoint)) {
217
            $this->apply(
218
                new ContactPointUpdated($this->actorId, $contactPoint)
219
            );
220
        }
221
    }
222
223
    /**
224
     * @inheritdoc
225
     */
226
    public function addLabel(Label $label)
227
    {
228
        if (!$this->labels->contains($label)) {
229
            $this->apply(new LabelAdded($this->actorId, $label));
230
        }
231
    }
232
233
    /**
234
     * @inheritdoc
235
     */
236
    public function removeLabel(Label $label)
237
    {
238
        if ($this->labels->contains($label)) {
239
            $this->apply(new LabelRemoved($this->actorId, $label));
240
        }
241
    }
242
243
    /**
244
     * @param Labels $labels
245
     */
246
    public function importLabels(Labels $labels)
247
    {
248
        // Convert the imported labels to label collection.
249
        $importLabelsCollection = new LabelCollection(
250
            array_map(
251
                function (\CultuurNet\UDB3\Model\ValueObject\Taxonomy\Label\Label $label) {
252
                    return new Label(
253
                        $label->getName()->toString(),
254
                        $label->isVisible()
255
                    );
256
                },
257
                $labels->toArray()
258
            )
259
        );
260
261
        // What are the added labels?
262
        // Labels which are not inside the internal state but inside the imported labels
263
        $addedLabels = new LabelCollection();
264
        foreach ($importLabelsCollection->asArray() as $label) {
265
            if (!$this->labels->contains($label)) {
266
                $addedLabels = $addedLabels->with($label);
267
            }
268
        }
269
270
        // Fire a LabelsImported for all new labels.
271
        $importLabels = new Labels();
272 View Code Duplication
        foreach ($addedLabels->asArray() as $addedLabel) {
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...
273
            $importLabels = $importLabels->with(
274
                new \CultuurNet\UDB3\Model\ValueObject\Taxonomy\Label\Label(
275
                    new LabelName((string) $addedLabel),
276
                    $addedLabel->isVisible()
277
                )
278
            );
279
        }
280
        if ($importLabels->count() > 0) {
281
            $this->apply(new LabelsImported(
282
                $this->actorId,
283
                $importLabels
284
            ));
285
        }
286
287
        // For each added label fire a LabelAdded event.
288
        foreach ($addedLabels->asArray() as $label) {
289
            $this->apply(new LabelAdded($this->actorId, $label));
290
        }
291
292
        // What are the deleted labels?
293
        // Labels which are inside the internal state but not inside imported labels.
294
        // For each deleted label fire a LabelDeleted event.
295
        foreach ($this->labels->asArray() as $label) {
296
            if (!$importLabelsCollection->contains($label)) {
297
                $this->apply(new LabelRemoved($this->actorId, $label));
298
            }
299
        }
300
    }
301
302
    public function delete()
303
    {
304
        $this->apply(
305
            new OrganizerDeleted($this->getAggregateRootId())
306
        );
307
    }
308
309
    /**
310
     * Apply the organizer created event.
311
     * @param OrganizerCreated $organizerCreated
312
     */
313
    protected function applyOrganizerCreated(OrganizerCreated $organizerCreated)
314
    {
315
        $this->actorId = $organizerCreated->getOrganizerId();
316
317
        $this->mainLanguage = new Language('nl');
318
319
        $this->setTitle($organizerCreated->getTitle(), $this->mainLanguage);
320
    }
321
322
    /**
323
     * Apply the organizer created event.
324
     * @param OrganizerCreatedWithUniqueWebsite $organizerCreated
325
     */
326
    protected function applyOrganizerCreatedWithUniqueWebsite(OrganizerCreatedWithUniqueWebsite $organizerCreated)
327
    {
328
        $this->actorId = $organizerCreated->getOrganizerId();
329
330
        $this->mainLanguage = $organizerCreated->getMainLanguage();
331
332
        $this->website = $organizerCreated->getWebsite();
333
334
        $this->setTitle($organizerCreated->getTitle(), $this->mainLanguage);
335
    }
336
337
    /**
338
     * @param OrganizerImportedFromUDB2 $organizerImported
339
     */
340
    protected function applyOrganizerImportedFromUDB2(
341
        OrganizerImportedFromUDB2 $organizerImported
342
    ) {
343
        $this->actorId = (string) $organizerImported->getActorId();
344
345
        // On import from UDB2 the default main language is 'nl'.
346
        $this->mainLanguage = new Language('nl');
347
348
        $actor = ActorItemFactory::createActorFromCdbXml(
349
            $organizerImported->getCdbXmlNamespaceUri(),
350
            $organizerImported->getCdbXml()
351
        );
352
353
        $this->setTitle($this->getTitle($actor), $this->mainLanguage);
0 ignored issues
show
Bug introduced by
It seems like $this->getTitle($actor) can be null; however, setTitle() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
354
355
        $this->labels = LabelCollection::fromKeywords($actor->getKeywords(true));
356
    }
357
358
    /**
359
     * @param OrganizerUpdatedFromUDB2 $organizerUpdatedFromUDB2
360
     */
361
    protected function applyOrganizerUpdatedFromUDB2(
362
        OrganizerUpdatedFromUDB2 $organizerUpdatedFromUDB2
363
    ) {
364
        // Note: never change the main language on update from UDB2.
365
366
        $actor = ActorItemFactory::createActorFromCdbXml(
367
            $organizerUpdatedFromUDB2->getCdbXmlNamespaceUri(),
368
            $organizerUpdatedFromUDB2->getCdbXml()
369
        );
370
371
        $this->setTitle($this->getTitle($actor), $this->mainLanguage);
0 ignored issues
show
Bug introduced by
It seems like $this->getTitle($actor) can be null; however, setTitle() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
372
373
        $this->labels = LabelCollection::fromKeywords($actor->getKeywords(true));
374
    }
375
376
    /**
377
     * @param WebsiteUpdated $websiteUpdated
378
     */
379
    protected function applyWebsiteUpdated(WebsiteUpdated $websiteUpdated)
380
    {
381
        $this->website = $websiteUpdated->getWebsite();
382
    }
383
384
    /**
385
     * @param TitleUpdated $titleUpdated
386
     */
387
    protected function applyTitleUpdated(TitleUpdated $titleUpdated)
388
    {
389
        $this->setTitle($titleUpdated->getTitle(), $this->mainLanguage);
390
    }
391
392
    /**
393
     * @param TitleTranslated $titleTranslated
394
     */
395
    protected function applyTitleTranslated(TitleTranslated $titleTranslated)
396
    {
397
        $this->setTitle($titleTranslated->getTitle(), $titleTranslated->getLanguage());
398
    }
399
400
    /**
401
     * @param AddressUpdated $addressUpdated
402
     */
403
    protected function applyAddressUpdated(AddressUpdated $addressUpdated)
404
    {
405
        $this->address = $addressUpdated->getAddress();
406
    }
407
408
    /**
409
     * @param ContactPointUpdated $contactPointUpdated
410
     */
411
    protected function applyContactPointUpdated(ContactPointUpdated $contactPointUpdated)
412
    {
413
        $this->contactPoint = $contactPointUpdated->getContactPoint();
414
    }
415
416
    /**
417
     * @param LabelAdded $labelAdded
418
     */
419
    protected function applyLabelAdded(LabelAdded $labelAdded)
420
    {
421
        $this->labels = $this->labels->with($labelAdded->getLabel());
422
    }
423
424
    /**
425
     * @param LabelRemoved $labelRemoved
426
     */
427
    protected function applyLabelRemoved(LabelRemoved $labelRemoved)
428
    {
429
        $this->labels = $this->labels->without($labelRemoved->getLabel());
430
    }
431
432
    /**
433
     * @param \CultureFeed_Cdb_Item_Actor $actor
434
     * @return null|Title
435
     */
436
    private function getTitle(\CultureFeed_Cdb_Item_Actor $actor)
437
    {
438
        $details = $actor->getDetails();
439
        $details->rewind();
440
441
        // The first language detail found will be used to retrieve
442
        // properties from which in UDB3 are not any longer considered
443
        // to be language specific.
444
        if ($details->valid()) {
445
            return new Title($details->current()->getTitle());
446
        } else {
447
            return null;
448
        }
449
    }
450
451
    /**
452
     * @param Title $title
453
     * @param Language $language
454
     */
455
    private function setTitle(Title $title, Language $language)
456
    {
457
        $this->titles[$language->getCode()] = $title;
458
    }
459
460
    /**
461
     * @param Title $title
462
     * @param Language $language
463
     * @return bool
464
     */
465
    private function isTitleChanged(Title $title, Language $language)
466
    {
467
        return !isset($this->titles[$language->getCode()]) ||
468
            !$title->sameValueAs($this->titles[$language->getCode()]);
469
    }
470
}
471