Passed
Push — master ( e12bb8...365767 )
by Thorsten
01:58
created

DomainEventSequence::push()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.576

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 6
cts 10
cp 0.6
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 2
nop 1
crap 3.576
1
<?php
2
/**
3
 * This file is part of the daikon-cqrs/cqrs 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
declare(strict_types=1);
10
11
namespace Daikon\EventSourcing\Aggregate\Event;
12
13
use Daikon\EventSourcing\Aggregate\AggregateRevision;
14
use Ds\Vector;
15
use Iterator;
16
17
final class DomainEventSequence implements DomainEventSequenceInterface
18
{
19
    /** @var Vector */
20
    private $compositeVector;
21
22
    public static function fromArray(array $eventsArray): DomainEventSequenceInterface
23
    {
24
        return new static(array_map(function (array $eventState): DomainEventInterface {
25
            $eventFqcn = self::resolveEventFqcn($eventState);
26
            return call_user_func([ $eventFqcn, 'fromArray' ], $eventState);
27
        }, $eventsArray));
28
    }
29
30 5
    public static function makeEmpty(): DomainEventSequenceInterface
31
    {
32 5
        return new self;
33
    }
34
35
    public function __construct(array $events = [])
36
    {
37 5
        $this->compositeVector = (function (DomainEventInterface ...$events): Vector {
38 5
            return new Vector($events);
39 5
        })(...$events);
40 5
    }
41
42 2
    public function push(DomainEventInterface $event): DomainEventSequenceInterface
43
    {
44 2
        $expectedRevision = $this->getHeadRevision()->increment();
45 2
        if (!$this->isEmpty() && !$expectedRevision->equals($event->getAggregateRevision())) {
46
            throw new \Exception(sprintf(
47
                'Trying to add unexpected revision %s to event-sequence. Expected revision is %s',
48
                $event->getAggregateRevision(),
49
                $expectedRevision
50
            ));
51
        }
52 2
        $eventSequence = clone $this;
53 2
        $eventSequence->compositeVector->push($event);
54 2
        return $eventSequence;
55
    }
56
57
    public function append(DomainEventSequenceInterface $events): DomainEventSequenceInterface
58
    {
59
        $eventSequence = clone $this;
60
        foreach ($events as $event) {
61
            $eventSequence = $eventSequence->push($event);
62
        }
63
        return $eventSequence;
64
    }
65
66
    public function toNative(): array
67
    {
68
        $nativeList = [];
69
        foreach ($this as $event) {
70
            $nativeRep = $event->toArray();
71
            $nativeRep['@type'] = get_class($event);
72
            $nativeList[] = $nativeRep;
73
        }
74
        return $nativeList;
75
    }
76
77 2
    public function getHeadRevision(): AggregateRevision
78
    {
79 2
        return $this->isEmpty() ? AggregateRevision::makeEmpty() : $this->getHead()->getAggregateRevision();
80
    }
81
82
    public function getTailRevision(): AggregateRevision
83
    {
84
        return $this->isEmpty() ? AggregateRevision::makeEmpty() : $this->getTail()->getAggregateRevision();
85
    }
86
87
    public function getTail(): ?DomainEventInterface
88
    {
89
        return $this->compositeVector->first();
90
    }
91
92
    public function getHead(): ?DomainEventInterface
93
    {
94
        return $this->compositeVector->last();
95
    }
96
97
    public function getLength(): int
98
    {
99
        return $this->count();
100
    }
101
102 2
    public function isEmpty(): bool
103
    {
104 2
        return $this->compositeVector->isEmpty();
105
    }
106
107
    public function indexOf(DomainEventInterface $event): int
108
    {
109
        return $this->compositeVector->find($event);
110
    }
111
112 3
    public function count(): int
113
    {
114 3
        return $this->compositeVector->count();
115
    }
116
117
    public function getIterator(): Iterator
118
    {
119
        return $this->compositeVector->getIterator();
120
    }
121
122
    private static function resolveEventFqcn(array $eventState): string
123
    {
124
        if (!isset($eventState['@type'])) {
125
            throw new \Exception('Missing expected typeinfo for event at key "@type" within given state-array.');
126
        }
127
        $eventFqcn = $eventState['@type'];
128
        if (!class_exists($eventFqcn)) {
129
            throw new \Exception(sprintf('Can not load event-class "%s" given within state-array.', $eventFqcn));
130
        }
131
        return $eventFqcn;
132
    }
133
134 2
    private function __clone()
135
    {
136 2
        $this->compositeVector = clone $this->compositeVector;
137 2
    }
138
}
139