Completed
Push — master ( 8a4be1...fe7d42 )
by Constantin
06:22
created

InMemoryEventStore::getEventsArrayForAggregate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 2
crap 2
1
<?php
2
3
4
namespace Gica\Cqrs\EventStore\InMemory;
5
6
7
use Gica\Cqrs\Event;
8
use Gica\Cqrs\Event\EventWithMetaData;
9
use Gica\Cqrs\Event\MetaData;
10
use Gica\Cqrs\EventStore;
11
use Gica\Cqrs\EventStore\AggregateEventStream;
12
use Gica\Cqrs\EventStore\EventStream;
13
use Gica\Cqrs\EventStore\Exception\ConcurrentModificationException;
14
15
class InMemoryEventStore implements EventStore
16
{
17
    public $events = [];
18
    private $versions = [];
19
    private $latestSequence = 0;
20
21 5
    public function loadEventsForAggregate(string $aggregateClass, $aggregateId): AggregateEventStream
22
    {
23 5
        return new InMemoryAggregateEventStream($this->getEventsArrayForAggregate($aggregateClass, $aggregateId), $aggregateClass, $aggregateId, $this->latestSequence);
24
    }
25
26 5
    public function appendEventsForAggregate($aggregateId, string $aggregateClass, $eventsWithMetaData, int $expectedVersion, int $expectedSequence)
27
    {
28 5
        if ($this->getAggregateVersion($aggregateClass, $aggregateId) != $expectedVersion) {
29 1
            throw new ConcurrentModificationException();
30
        }
31
32 5
        $this->addEventsToArrayForAggregate($aggregateId, $aggregateClass, $eventsWithMetaData);
33
34 5
        $this->versions[$this->constructKey($aggregateClass, $aggregateId)] = $expectedVersion + 1;
35 5
        $this->latestSequence = $expectedSequence + 1;
36 5
    }
37
38 1
    public function appendEventsForAggregateWithoutChecking($aggregateId, $aggregateClass, $newEvents)
39
    {
40 1
        $this->addEventsToArrayForAggregate($aggregateId, $aggregateClass, $this->decorateEventsWithMetadata($aggregateClass, $aggregateId, $newEvents));
41
42 1
        $constructKey = $this->constructKey($aggregateClass, $aggregateId);
43
44 1
        if (!isset($this->versions[$constructKey])) {
45 1
            $this->versions[$constructKey] = 0;
46
        }
47
48 1
        $this->versions[$constructKey]++;
49 1
        $this->latestSequence++;
50 1
    }
51
52 5
    private function getEventsArrayForAggregate(string $aggregateClass, $aggregateId)
53
    {
54 5
        $aggregateKey = $this->constructKey($aggregateClass, $aggregateId);
55 5
        return isset($this->events[$aggregateKey]) ? $this->events[$aggregateKey] : [];
56
    }
57
58 6
    private function addEventsToArrayForAggregate($aggregateId, $aggregateClass, $newEvents)
59
    {
60 6
        foreach ($newEvents as $event) {
61 6
            $this->events[$this->constructKey($aggregateClass, $aggregateId)][] = $event;
62
        }
63 6
    }
64
65 1
    public function loadEventsByClassNames(array $eventClasses): EventStream
66
    {
67 1
        $result = [];
68
69 1
        foreach ($this->events as $aggregateKey => $events) {
70
            /** @var EventWithMetaData[] $events */
71 1
            foreach ($events as $eventWithMetaData) {
72 1
                if ($this->eventHasAnyOfThisClasses($eventWithMetaData->getEvent(), $eventClasses)) {
73 1
                    $result[] = $eventWithMetaData;
74
                }
75
            }
76
        }
77
78 1
        return new RawEventStream($result);
79
    }
80
81 1
    private function eventHasAnyOfThisClasses($event, array $eventClasses)
82
    {
83 1
        foreach ($eventClasses as $eventClass) {
84 1
            if (is_subclass_of($event, $eventClass) || get_class($event) === $eventClass) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $eventClass can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
85 1
                return true;
86
            }
87
        }
88
89 1
        return false;
90
    }
91
92 6
    public function getAggregateVersion(string $aggregateClass, $aggregateId)
93
    {
94 6
        $key = $this->constructKey($aggregateClass, $aggregateId);
95
96 6
        return isset($this->versions[$key]) ? $this->versions[$key] : 0;
97
    }
98
99
    /**
100
     * @param $aggregateClass
101
     * @param $aggregateId
102
     * @param Event[] $priorEvents
103
     * @return EventWithMetaData[]
104
     */
105
    public function decorateEventsWithMetadata($aggregateClass, $aggregateId, array $priorEvents)
106
    {
107 2
        return array_map(function (Event $event) use ($aggregateClass, $aggregateId) {
108 2
            return new EventWithMetaData($event, new MetaData(
109 2
                $aggregateId, $aggregateClass, new \DateTimeImmutable(), null
110
            ));
111 2
        }, $priorEvents);
112
    }
113
114 3
    public function fetchLatestSequence(): int
115
    {
116 3
        return $this->latestSequence;
117
    }
118
119 8
    private function constructKey(string $aggregateClass, $aggregateId): string
120
    {
121 8
        return $aggregateClass . '_' . (string)$aggregateId;
122
    }
123
}