Completed
Pull Request — master (#287)
by Luc
04:52
created

Projector::applyPlaceImportedFromUDB2()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 14

Duplication

Lines 23
Ratio 100 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 23
loc 23
rs 9.0856
cc 1
eloc 14
nc 1
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3\ReadModel\Index;
4
5
use Broadway\Domain\DomainMessage;
6
use Broadway\EventHandling\EventListenerInterface;
7
use CultuurNet\UDB3\Cdb\ActorItemFactory;
8
use CultuurNet\UDB3\Cdb\CreatedByToUserIdResolverInterface;
9
use CultuurNet\UDB3\Cdb\EventItemFactory;
10
use CultuurNet\UDB3\Event\Events\EventCopied;
11
use CultuurNet\UDB3\Event\Events\EventImportedFromUDB2;
12
use CultuurNet\UDB3\Event\Events\EventCreated;
13
use CultuurNet\UDB3\Event\Events\EventDeleted;
14
use CultuurNet\UDB3\Event\Events\EventProjectedToJSONLD;
15
use CultuurNet\UDB3\EventHandling\DelegateEventHandlingToSpecificMethodTrait;
16
use CultuurNet\UDB3\Offer\Events\AbstractEventWithIri;
17
use CultuurNet\UDB3\Offer\IriOfferIdentifierFactoryInterface;
18
use CultuurNet\UDB3\Place\Events\PlaceCreated;
19
use CultuurNet\UDB3\Place\Events\PlaceDeleted;
20
use CultuurNet\UDB3\Place\Events\PlaceImportedFromUDB2;
21
use CultuurNet\UDB3\Place\Events\PlaceProjectedToJSONLD;
22
use DateTime;
23
use DateTimeInterface;
24
use DateTimeZone;
25
use ValueObjects\StringLiteral\StringLiteral;
26
use ValueObjects\Web\Domain;
27
use ValueObjects\Web\Url;
28
29
/**
30
 * Logs new events / updates to an index for querying.
31
 */
32
class Projector implements EventListenerInterface
33
{
34
    use DelegateEventHandlingToSpecificMethodTrait {
35
        DelegateEventHandlingToSpecificMethodTrait::handle as handleMethodSpecificEvents;
36
    }
37
38
    /**
39
     * @var RepositoryInterface
40
     */
41
    protected $repository;
42
43
    /**
44
     * @var CreatedByToUserIdResolverInterface
45
     */
46
    protected $userIdResolver;
47
48
    /**
49
     * A list of events that should trigger an index item update.
50
     *  The key is the namespaced class name.
51
     *  The value is the method the method to call to get the id of the index item.
52
     *
53
     * @var string[]
54
     */
55
    protected static $indexUpdateEvents = [
56
        EventProjectedToJSONLD::class,
57
        PlaceProjectedToJSONLD::class,
58
    ];
59
60
    /**
61
     * @var Domain
62
     */
63
    protected $localDomain;
64
65
    /**
66
     * @var Domain
67
     */
68
    protected $UDB2Domain;
69
70
    /**
71
     * @var IriOfferIdentifierFactoryInterface
72
     */
73
    protected $identifierFactory;
74
75
    /**
76
     * @param RepositoryInterface $repository
77
     * @param CreatedByToUserIdResolverInterface $createdByToUserIdResolver
78
     * @param Domain $localDomain
79
     * @param Domain $UDB2Domain
80
     * @param IriOfferIdentifierFactoryInterface $identifierFactory
81
     */
82
    public function __construct(
83
        RepositoryInterface $repository,
84
        CreatedByToUserIdResolverInterface $createdByToUserIdResolver,
85
        Domain $localDomain,
86
        Domain $UDB2Domain,
87
        IriOfferIdentifierFactoryInterface $identifierFactory
88
    ) {
89
        $this->repository = $repository;
90
        $this->userIdResolver = $createdByToUserIdResolver;
91
        $this->localDomain = $localDomain;
92
        $this->UDB2Domain = $UDB2Domain;
93
        $this->identifierFactory = $identifierFactory;
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    public function handle(DomainMessage $domainMessage)
100
    {
101
        $this->handleIndexUpdateEvents($domainMessage);
102
        $this->handleMethodSpecificEvents($domainMessage);
103
    }
104
105
    protected function handleIndexUpdateEvents(DomainMessage $domainMessage)
106
    {
107
        /** @var AbstractEventWithIri $event */
108
        $event = $domainMessage->getPayload();
109
        $eventName = get_class($event);
110
111
        if (in_array($eventName, self::$indexUpdateEvents)) {
112
            $identifier = $this->identifierFactory->fromIri(
113
                Url::fromNative($event->getIri())
114
            );
115
            $dateUpdated = $this->getRecordedDate($domainMessage);
116
117
            $this->setItemUpdateDate($identifier->getId(), $dateUpdated);
118
        }
119
    }
120
121
    /**
122
     * @param string $itemId
123
     * @param DateTimeInterface $dateUpdated
124
     */
125
    protected function setItemUpdateDate($itemId, DateTimeInterface $dateUpdated)
126
    {
127
        $this->repository->setUpdateDate($itemId, $dateUpdated);
128
    }
129
130
    /**
131
     * @param \CultureFeed_Cdb_Item_Base $udb2Item
132
     *
133
     * @return null|string
134
     */
135
    protected function resolveUserId(\CultureFeed_Cdb_Item_Base $udb2Item)
136
    {
137
        $createdByIdentifier = $udb2Item->getCreatedBy();
138
        if ($createdByIdentifier) {
139
            $userId = $this->userIdResolver->resolveCreatedByToUserId(
140
                new StringLiteral($createdByIdentifier)
141
            );
142
        }
143
144
        return isset($userId) ? (string) $userId : '';
145
    }
146
147
    /**
148
     *
149
     * @param EventImportedFromUDB2 $eventImportedFromUDB2
150
     */
151 View Code Duplication
    protected function applyEventImportedFromUDB2(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
152
        EventImportedFromUDB2 $eventImportedFromUDB2
153
    ) {
154
        $eventId = $eventImportedFromUDB2->getEventId();
155
156
        $udb2Event = EventItemFactory::createEventFromCdbXml(
157
            $eventImportedFromUDB2->getCdbXmlNamespaceUri(),
158
            $eventImportedFromUDB2->getCdbXml()
159
        );
160
        $userId = $this->resolveUserId($udb2Event);
161
162
        $creationDate = $this->dateTimeFromUDB2DateString(
163
            $udb2Event->getCreationDate()
164
        );
165
166
        $this->updateIndex(
167
            $eventId,
168
            EntityType::EVENT(),
169
            (string) $userId,
170
            $this->UDB2Domain,
171
            $creationDate
0 ignored issues
show
Security Bug introduced by
It seems like $creationDate defined by $this->dateTimeFromUDB2D...ent->getCreationDate()) on line 162 can also be of type false; however, CultuurNet\UDB3\ReadMode...rojector::updateIndex() does only seem to accept null|object<DateTimeInterface>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
172
        );
173
    }
174
175
    /**
176
     *
177
     * @param PlaceImportedFromUDB2 $placeImportedFromUDB2
178
     */
179 View Code Duplication
    protected function applyPlaceImportedFromUDB2(PlaceImportedFromUDB2 $placeImportedFromUDB2)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
180
    {
181
        $placeId = $placeImportedFromUDB2->getActorId();
182
183
        $udb2Actor = ActorItemFactory::createActorFromCdbXml(
184
            $placeImportedFromUDB2->getCdbXmlNamespaceUri(),
185
            $placeImportedFromUDB2->getCdbXml()
186
        );
187
188
        $userId = $this->resolveUserId($udb2Actor);
189
190
        $creationDate = $this->dateTimeFromUDB2DateString(
191
            $udb2Actor->getCreationDate()
192
        );
193
194
        $this->updateIndex(
195
            $placeId,
196
            EntityType::PLACE(),
197
            $userId,
198
            $this->UDB2Domain,
199
            $creationDate
0 ignored issues
show
Security Bug introduced by
It seems like $creationDate defined by $this->dateTimeFromUDB2D...tor->getCreationDate()) on line 190 can also be of type false; however, CultuurNet\UDB3\ReadMode...rojector::updateIndex() does only seem to accept null|object<DateTimeInterface>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
200
        );
201
    }
202
203
    /**
204
     * Listener for event created commands.
205
     * @param EventCreated $eventCreated
206
     * @param DomainMessage $domainMessage
207
     */
208 View Code Duplication
    protected function applyEventCreated(EventCreated $eventCreated, DomainMessage $domainMessage)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
209
    {
210
        $eventId = $eventCreated->getEventId();
211
212
        $userId = $this->getUserId($domainMessage);
213
214
        $this->updateIndex(
215
            $eventId,
216
            EntityType::EVENT(),
217
            $userId,
218
            $this->localDomain,
219
            $this->getRecordedDate($domainMessage)
220
        );
221
    }
222
223
    /**
224
     * @param EventCopied $eventCopied
225
     * @param DomainMessage $domainMessage
226
     */
227 View Code Duplication
    public function applyEventCopied(EventCopied $eventCopied, DomainMessage $domainMessage)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
228
    {
229
        $eventId = $eventCopied->getItemId();
230
231
        $userId = $this->getUserId($domainMessage);
232
233
        $this->updateIndex(
234
            $eventId,
235
            EntityType::EVENT(),
236
            $userId,
237
            $this->localDomain,
238
            $this->getRecordedDate($domainMessage)
239
        );
240
    }
241
242
    /**
243
     * Listener for place created commands.
244
     * @param PlaceCreated $placeCreated
245
     * @param DomainMessage $domainMessage
246
     */
247 View Code Duplication
    protected function applyPlaceCreated(PlaceCreated $placeCreated, DomainMessage $domainMessage)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
248
    {
249
        $placeId = $placeCreated->getPlaceId();
250
251
        $userId = $this->getUserId($domainMessage);
252
253
        $this->updateIndex(
254
            $placeId,
255
            EntityType::PLACE(),
256
            $userId,
257
            $this->localDomain,
258
            $this->getRecordedDate($domainMessage)
259
        );
260
    }
261
262
    /**
263
     * @param $dateString
264
     *  A UDB2 formatted date string
265
     *
266
     * @return DateTimeInterface
267
     */
268
    protected function dateTimeFromUDB2DateString($dateString)
269
    {
270
        return DateTime::createFromFormat(
271
            'Y-m-d?H:i:s',
272
            $dateString,
273
            new DateTimeZone('Europe/Brussels')
274
        );
275
    }
276
277
    /**
278
     * Update the index
279
     * @param $id
280
     * @param EntityType $type
281
     * @param $userId
282
     * @param Domain $owningDomain
283
     * @param DateTimeInterface $creationDate
284
     */
285
    protected function updateIndex(
286
        $id,
287
        EntityType $type,
288
        $userId,
289
        Domain $owningDomain,
290
        DateTimeInterface $creationDate = null
291
    ) {
292
        $this->repository->updateIndex(
293
            $id,
294
            $type,
295
            $userId,
296
            $owningDomain,
297
            $creationDate
298
        );
299
    }
300
301
    /**
302
     * Remove the index for events
303
     * @param EventDeleted $eventDeleted
304
     */
305
    public function applyEventDeleted(EventDeleted $eventDeleted)
306
    {
307
        $this->repository->deleteIndex($eventDeleted->getItemId(), EntityType::EVENT());
308
    }
309
310
    /**
311
     * Remove the index for places
312
     * @param PlaceDeleted $placeDeleted
313
     */
314
    public function applyPlaceDeleted(PlaceDeleted $placeDeleted)
315
    {
316
        $this->repository->deleteIndex($placeDeleted->getItemId(), EntityType::PLACE());
317
    }
318
319
    /**
320
     * @param DomainMessage $domainMessage
321
     * @return string
322
     */
323
    private function getUserId(DomainMessage $domainMessage)
324
    {
325
        $metaData = $domainMessage->getMetadata()->serialize();
326
        return isset($metaData['user_id']) ? $metaData['user_id'] : '';
327
    }
328
329
    /**
330
     * @param DomainMessage $domainMessage
331
     * @return DateTime
332
     */
333
    private function getRecordedDate(DomainMessage $domainMessage)
334
    {
335
        return new DateTime($domainMessage->getRecordedOn()->toString());
336
    }
337
}
338