Completed
Pull Request — master (#264)
by Kristof
05:22
created

EventSourcedAggregateRoot::getApplyMethod()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace CultuurNet\UDB3\EventSourcing;
4
5
use Broadway\EventSourcing\EventSourcedAggregateRoot as OriginalEventSourcedAggregateRoot;
6
use Broadway\Domain\AggregateRoot as AggregateRootInterface;
7
use Broadway\Domain\DomainEventStream;
8
use Broadway\Domain\DomainEventStreamInterface;
9
use Broadway\Domain\DomainMessage;
10
use Broadway\Domain\Metadata;
11
use RuntimeException;
12
13
/**
14
 * Base class for event sourced aggregate roots, with copy functionality.
15
 *
16
 * Based on Broadways EventSourcedAggregateRoot. In addition it provides
17
 * a copy functionality which maintains the state of the object, but resets
18
 * the playhead. We could not change the playhead in a child class, because it
19
 * is declared private.
20
 *
21
 * Unfortunately we need to extend Broadways EventSourcedAggregateRoot because
22
 * it is required in the EventSourcingRepository.
23
 */
24
abstract class EventSourcedAggregateRoot extends OriginalEventSourcedAggregateRoot implements AggregateRootInterface
25
{
26
    /**
27
     * @var array
28
     */
29
    private $uncommittedEvents = array();
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
30
    private $playhead = -1; // 0-based playhead allows events[0] to contain playhead 0
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
31
32
    /**
33
     * Applies an event. The event is added to the AggregateRoot's list of uncommited events.
34
     *
35
     * @param $event
36
     * @internal
37
     */
38
    public function apply($event)
39
    {
40
        $this->handleRecursively($event);
41
42
        $this->playhead++;
43
        $this->uncommittedEvents[] = DomainMessage::recordNow(
44
            $this->getAggregateRootId(),
45
            $this->playhead,
46
            new Metadata(array()),
47
            $event
48
        );
49
    }
50
51
    /**
52
     * {@inheritDoc}
53
     */
54
    public function getUncommittedEvents()
55
    {
56
        $stream = new DomainEventStream($this->uncommittedEvents);
57
58
        $this->uncommittedEvents = array();
59
60
        return $stream;
61
    }
62
63
    /**
64
     * Initializes the aggregate using the given "history" of events.
65
     */
66
    public function initializeState(DomainEventStreamInterface $stream)
67
    {
68
        foreach ($stream as $message) {
69
            $this->playhead++;
70
            $this->handleRecursively($message->getPayload());
71
        }
72
    }
73
74
    /**
75
     * Handles event if capable.
76
     *
77
     * @param $event
78
     */
79
    protected function handle($event)
80
    {
81
        $method = $this->getApplyMethod($event);
82
83
        if (! method_exists($this, $method)) {
84
            return;
85
        }
86
87
        $this->$method($event);
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     */
93
    protected function handleRecursively($event)
94
    {
95
        $this->handle($event);
96
97
        foreach ($this->getChildEntities() as $entity) {
98
            $entity->registerAggregateRoot($this);
99
            $entity->handleRecursively($event);
100
        }
101
    }
102
103
    /**
104
     * Returns all child entities
105
     *
106
     * Override this method if your aggregate root contains child entities.
107
     *
108
     * @return array
109
     */
110
    protected function getChildEntities()
111
    {
112
        return array();
113
    }
114
115
    private function getApplyMethod($event)
0 ignored issues
show
Bug introduced by
Consider using a different method name as you override a private method of the parent class.

Overwriting private methods is generally fine as long as you also use private visibility. It might still be preferable for understandability to use a different method name.

Loading history...
116
    {
117
        $classParts = explode('\\', get_class($event));
118
119
        return 'apply' . end($classParts);
120
    }
121
122
    /**
123
     * Creates a copy with the playhead reset.
124
     *
125
     * @throws RuntimeException When there are any uncommitted events.
126
     *
127
     * @return static
128
     */
129
    protected function copyWithoutHistory()
130
    {
131
        if (!empty($this->uncommittedEvents)) {
132
            throw new RuntimeException('I refuse to copy, there are uncommitted events present.');
133
        }
134
135
        $copy = clone $this;
136
        $copy->playhead = -1;
137
138
        return $copy;
139
    }
140
}
141