Passed
Push — master ( 134841...7712b0 )
by Mr
02:17
created

AggregateRoot::getIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
ccs 2
cts 2
cp 1
crap 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;
10
11
use Daikon\EventSourcing\Aggregate\Event\DomainEventInterface;
12
use Daikon\EventSourcing\Aggregate\Event\DomainEventSequence;
13
use Daikon\EventSourcing\Aggregate\Event\DomainEventSequenceInterface;
14
use Daikon\Interop\Assertion;
15
use Daikon\Interop\RuntimeException;
16
use ReflectionClass;
17
18
abstract class AggregateRoot implements AggregateRootInterface
19
{
20
    private AggregateIdInterface $identifier;
21
22
    private AggregateRevision $revision;
23
24
    private DomainEventSequenceInterface $trackedEvents;
25
26
    /** @return static */
27 3
    public static function reconstituteFromHistory(
28
        AggregateIdInterface $aggregateId,
29
        DomainEventSequenceInterface $history
30
    ): self {
31 3
        $aggregateRoot = new static($aggregateId);
32 3
        foreach ($history as $historicalEvent) {
33 3
            $aggregateRoot = $aggregateRoot->reconstitute($historicalEvent);
34
        }
35 1
        return $aggregateRoot;
36
    }
37
38 4
    public function getIdentifier(): AggregateIdInterface
39
    {
40 4
        return $this->identifier;
41
    }
42
43 2
    public function getRevision(): AggregateRevision
44
    {
45 2
        return $this->revision;
46
    }
47
48 2
    public function getTrackedEvents(): DomainEventSequenceInterface
49
    {
50 2
        return $this->trackedEvents;
51
    }
52
53 4
    protected function __construct(AggregateIdInterface $aggregateId)
54
    {
55 4
        $this->identifier = $aggregateId;
56 4
        $this->revision = AggregateRevision::makeEmpty();
57 4
        $this->trackedEvents = DomainEventSequence::makeEmpty();
58 4
    }
59
60 1
    protected function reflectThat(DomainEventInterface $eventOccurred): self
61
    {
62 1
        $this->assertExpectedIdentifier($eventOccurred, $this->getIdentifier());
63 1
        $aggregateRoot = clone $this;
64 1
        $aggregateRoot->revision = $aggregateRoot->revision->increment();
65 1
        $eventOccurred = $eventOccurred->withAggregateRevision($aggregateRoot->revision);
66 1
        $aggregateRoot->trackedEvents = $aggregateRoot->trackedEvents->push($eventOccurred);
67 1
        $aggregateRoot->invokeEventHandler($eventOccurred);
68 1
        return $aggregateRoot;
69
    }
70
71 3
    private function reconstitute(DomainEventInterface $historicalEvent): self
72
    {
73 3
        $this->assertExpectedIdentifier($historicalEvent, $this->getIdentifier());
74 2
        $aggregateRoot = clone $this;
75 2
        $expectedAggregateRevision = $aggregateRoot->revision->increment();
76 2
        $this->assertExpectedRevision($historicalEvent, $expectedAggregateRevision);
77 1
        $aggregateRoot->revision = $expectedAggregateRevision;
78 1
        $aggregateRoot->invokeEventHandler($historicalEvent);
79 1
        return $aggregateRoot;
80
    }
81
82 2
    private function assertExpectedRevision(DomainEventInterface $event, AggregateRevision $expectedRevision): void
83
    {
84 2
        Assertion::true($expectedRevision->equals($event->getAggregateRevision()), sprintf(
85 2
            "Given event revision '%s' does not match expected AR revision at '%s'.",
86 2
            (string)$event->getAggregateRevision(),
87 2
            (string)$expectedRevision
88
        ));
89 1
    }
90
91 4
    private function assertExpectedIdentifier(DomainEventInterface $event, AggregateIdInterface $expectedId): void
92
    {
93 4
        Assertion::true($expectedId->equals($event->getAggregateId()), sprintf(
94 4
            "Given event identifier '%s' does not match expected AR identifier at '%s'.",
95 4
            (string)$event->getAggregateId(),
96 4
            (string)$expectedId
97
        ));
98 3
    }
99
100 2
    private function invokeEventHandler(DomainEventInterface $event): void
101
    {
102 2
        $handlerName = (new ReflectionClass($event))->getShortName();
103 2
        $handlerMethod = 'when'.ucfirst($handlerName);
104 2
        $handler = [$this, $handlerMethod];
105 2
        if (!is_callable($handler)) {
106
            throw new RuntimeException(
107
                sprintf("Handler '%s' is not callable on '%s'.", $handlerMethod, static::class)
108
            );
109
        }
110 2
        $handler($event);
111 2
    }
112
}
113