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

DomainEventSequence   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Test Coverage

Coverage 35%

Importance

Changes 0
Metric Value
wmc 25
lcom 2
cbo 3
dl 0
loc 122
ccs 21
cts 60
cp 0.35
rs 10
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A fromArray() 0 7 1
A makeEmpty() 0 4 1
A __construct() 0 6 1
A push() 0 14 3
A append() 0 8 2
A toNative() 0 10 2
A getHeadRevision() 0 4 2
A getTailRevision() 0 4 2
A getTail() 0 4 1
A getHead() 0 4 1
A getLength() 0 4 1
A isEmpty() 0 4 1
A indexOf() 0 4 1
A count() 0 4 1
A getIterator() 0 4 1
A resolveEventFqcn() 0 11 3
A __clone() 0 4 1
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