DomainEventSequence   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Test Coverage

Coverage 32.31%

Importance

Changes 0
Metric Value
eloc 50
dl 0
loc 127
ccs 21
cts 65
cp 0.3231
rs 10
c 0
b 0
f 0
wmc 24

17 Methods

Rating   Name   Duplication   Size   Complexity  
A count() 0 3 1
A getTail() 0 3 1
A getHeadRevision() 0 6 2
A toNative() 0 9 2
A getIterator() 0 3 1
A indexOf() 0 3 1
A __clone() 0 3 1
A push() 0 13 3
A fromNative() 0 5 1
A resequence() 0 8 2
A makeEmpty() 0 3 1
A getHead() 0 3 1
A append() 0 7 2
A getTailRevision() 0 6 2
A resolveEventFqcn() 0 6 1
A isEmpty() 0 3 1
A __construct() 0 5 1
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/event-sourcing project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\EventSourcing\Aggregate\Event;
10
11
use Daikon\EventSourcing\Aggregate\AggregateRevision;
12
use Daikon\Interop\Assertion;
13
use Daikon\Interop\RuntimeException;
14
use Ds\Vector;
15
16
final class DomainEventSequence implements DomainEventSequenceInterface
17
{
18
    private Vector $compositeVector;
19
20
    /** @param array $events */
21
    public static function fromNative($events): self
22
    {
23
        return new self(array_map(
24
            fn(array $state): DomainEventInterface => ([self::resolveEventFqcn($state), 'fromNative'])($state),
25
            $events
26
        ));
27
    }
28
29 4
    public static function makeEmpty(): self
30
    {
31 4
        return new self;
32
    }
33
34 4
    public function __construct(iterable $events = [])
35
    {
36 4
        $this->compositeVector = (
37 4
            fn(DomainEventInterface ...$events): Vector => new Vector($events)
38
        )(...$events);
39 4
    }
40
41 1
    public function push(DomainEventInterface $event): self
42
    {
43 1
        $expectedRevision = $this->getHeadRevision()->increment();
44 1
        if (!$this->isEmpty() && !$expectedRevision->equals($event->getAggregateRevision())) {
45
            throw new RuntimeException(sprintf(
46
                'Trying to add invalid revision %s to event-sequence, expected revision is %s.',
47
                (string)$event->getAggregateRevision(),
48
                (string)$expectedRevision
49
            ));
50
        }
51 1
        $eventSequence = clone $this;
52 1
        $eventSequence->compositeVector->push($event);
53 1
        return $eventSequence;
54
    }
55
56
    public function append(DomainEventSequenceInterface $events): self
57
    {
58
        $eventSequence = $this;
59
        foreach ($events as $event) {
60
            $eventSequence = $eventSequence->push($event);
61
        }
62
        return $eventSequence;
63
    }
64
65
    public function resequence(AggregateRevision $aggregateRevision): self
66
    {
67
        $eventSequence = self::makeEmpty();
68
        foreach ($this as $event) {
69
            $aggregateRevision = $aggregateRevision->increment();
70
            $eventSequence->compositeVector->push($event->withAggregateRevision($aggregateRevision));
71
        }
72
        return $eventSequence;
73
    }
74
75
    public function toNative(): array
76
    {
77
        $nativeList = [];
78
        foreach ($this as $event) {
79
            $nativeRep = $event->toNative();
80
            $nativeRep['@type'] = get_class($event);
81
            $nativeList[] = $nativeRep;
82
        }
83
        return $nativeList;
84
    }
85
86 1
    public function getHeadRevision(): AggregateRevision
87
    {
88 1
        if ($this->isEmpty()) {
89 1
            return AggregateRevision::makeEmpty();
90
        }
91
        return $this->getHead()->getAggregateRevision();
92
    }
93
94
    public function getTailRevision(): AggregateRevision
95
    {
96
        if ($this->isEmpty()) {
97
            return AggregateRevision::makeEmpty();
98
        }
99
        return $this->getTail()->getAggregateRevision();
100
    }
101
102
    public function getTail(): DomainEventInterface
103
    {
104
        return $this->compositeVector->first();
105
    }
106
107
    public function getHead(): DomainEventInterface
108
    {
109
        return $this->compositeVector->last();
110
    }
111
112 1
    public function isEmpty(): bool
113
    {
114 1
        return $this->compositeVector->isEmpty();
115
    }
116
117
    public function indexOf(DomainEventInterface $event)
118
    {
119
        return $this->compositeVector->find($event);
120
    }
121
122 2
    public function count(): int
123
    {
124 2
        return $this->compositeVector->count();
125
    }
126
127
    public function getIterator(): Vector
128
    {
129
        return $this->compositeVector;
130
    }
131
132
    private static function resolveEventFqcn(array $eventState): string
133
    {
134
        Assertion::keyIsset($eventState, '@type', "Missing expected key '@type' within given state array.");
135
        $eventFqcn = $eventState['@type'];
136
        Assertion::classExists($eventFqcn, "Cannot find event class '$eventFqcn' given within state array.");
137
        return $eventFqcn;
138
    }
139
140 1
    private function __clone()
141
    {
142 1
        $this->compositeVector = clone $this->compositeVector;
143 1
    }
144
}
145