Passed
Push — master ( 977f82...f4c7d5 )
by Mr
07:24
created

AggregateRootTrait::invokeEventHandler()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2.0625

Importance

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