EventSourcedAggregateRoot   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 6
dl 0
loc 135
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A recordApplyAndPublishEvent() 0 11 1
A applyEvent() 0 14 2
A publishEvent() 0 4 1
A recordEvent() 0 4 1
A recordedEvents() 0 4 1
A clearEvents() 0 4 1
A loadFromHistory() 0 11 1
A replay() 0 6 2
A version() 0 8 2
A incrementVersion() 0 7 1
A setVersion() 0 4 1
1
<?php
2
3
/**
4
 * This file is part of the Cubiche package.
5
 *
6
 * Copyright (c) Cubiche
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Cubiche\Domain\EventSourcing;
13
14
use Cubiche\Core\Validator\Validator;
15
use Cubiche\Domain\EventPublisher\DomainEventPublisher;
16
use Cubiche\Domain\EventSourcing\Versioning\Version;
17
use Cubiche\Domain\EventSourcing\Versioning\VersionManager;
18
use Cubiche\Domain\EventSourcing\EventStore\EventStream;
19
20
/**
21
 * EventSourcedAggregateRoot trait.
22
 *
23
 * @author Ivannis Suárez Jerez <[email protected]>
24
 */
25
trait EventSourcedAggregateRoot
26
{
27
    /**
28
     * @var int
29
     */
30
    protected $version;
31
32
    /**
33
     * @var DomainEventInterface[]
34
     */
35
    protected $recordedEvents = [];
36
37
    /**
38
     * @param DomainEventInterface $event
39
     */
40
    protected function recordApplyAndPublishEvent(DomainEventInterface $event)
41
    {
42
        Validator::assert($event);
43
44
        $this->incrementVersion();
45
        $event->setVersion($this->version());
46
47
        $this->recordEvent($event);
48
        $this->applyEvent($event);
49
        $this->publishEvent($event);
50
    }
51
52
    /**
53
     * @param DomainEventInterface $event
54
     */
55
    protected function applyEvent(DomainEventInterface $event)
56
    {
57
        $classParts = explode('\\', get_class($event));
58
        $method = 'apply'.end($classParts);
59
60
        if (!method_exists($this, $method)) {
61
            throw new \BadMethodCallException(
62
                "There is no method named '$method' that can be applied to '".get_class($this)."'. "
63
            );
64
        }
65
66
        $this->$method($event);
67
        $this->setVersion($event->version());
68
    }
69
70
    /**
71
     * @param DomainEventInterface $event
72
     */
73
    protected function publishEvent(DomainEventInterface $event)
74
    {
75
        DomainEventPublisher::publish($event);
76
    }
77
78
    /**
79
     * @param DomainEventInterface $event
80
     */
81
    protected function recordEvent(DomainEventInterface $event)
82
    {
83
        $this->recordedEvents[] = $event;
84
    }
85
86
    /**
87
     * @return DomainEventInterface[]
88
     */
89
    public function recordedEvents()
90
    {
91
        return $this->recordedEvents;
92
    }
93
94
    /**
95
     * Clear recorded events.
96
     */
97
    public function clearEvents()
98
    {
99
        $this->recordedEvents = [];
100
    }
101
102
    /**
103
     * @param EventStream $history
104
     *
105
     * @return AggregateRootInterface
106
     */
107
    public static function loadFromHistory(EventStream $history)
108
    {
109
        $reflector = new \ReflectionClass(static::class);
110
111
        /** @var EventSourcedAggregateRootInterface $aggregateRoot */
112
        $aggregateRoot = $reflector->newInstanceWithoutConstructor();
113
        $aggregateRoot->id = $history->aggregateId();
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cubiche\Domain\EventSour...dAggregateRootInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
114
        $aggregateRoot->replay($history);
115
116
        return $aggregateRoot;
117
    }
118
119
    /**
120
     * @param EventStream $history
121
     */
122
    public function replay(EventStream $history)
123
    {
124
        foreach ($history->events() as $event) {
125
            $this->applyEvent($event);
126
        }
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function version()
133
    {
134
        if ($this->version === null) {
135
            $this->version = VersionManager::versionOf($this);
136
        }
137
138
        return $this->version;
139
    }
140
141
    /**
142
     * Increment the current version.
143
     */
144
    protected function incrementVersion()
145
    {
146
        $version = $this->version();
147
        ++$version;
148
149
        $this->setVersion($version);
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     */
155
    public function setVersion($version)
156
    {
157
        $this->version = $version;
158
    }
159
}
160