Completed
Push — master ( ba82d8...306a50 )
by Daniel
03:11
created

ProjectionBuilder::fromAll()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
3
namespace DDDominio\EventSourcing\EventStore\Projection;
4
5
use DDDominio\Common\EventInterface;
6
use DDDominio\EventSourcing\Common\EventStreamInterface;
7
use DDDominio\EventSourcing\EventStore\EventStoreInterface;
8
9
class ProjectionBuilder
10
{
11
    /**
12
     * @var EventStoreInterface
13
     */
14
    private $eventStore;
15
16
    /**
17
     * @var callable
18
     */
19
    private $stateInitializer;
20
21
    /**
22
     * @var string
23
     */
24
    private $from;
25
26
    /**
27
     * @var bool
28
     */
29
    private $forEachStream;
30
31
    /**
32
     * @var array
33
     */
34
    private $eventHandlers;
35
36
    /**
37
     * @var Projector
38
     */
39
    private $projector;
40
41
    /**
42
     * @param EventStoreInterface $eventStore
43
     */
44 8
    public function __construct(EventStoreInterface $eventStore)
45
    {
46 8
        $this->eventStore = $eventStore;
47 4
        $this->stateInitializer = function() {
48 4
            return new \stdClass();
49
        };
50 8
        $this->forEachStream = false;
51 8
        $this->projector = new Projector();
52 8
    }
53
54
    /**
55
     * @param callable $stateInitializer
56
     * @return $this
57
     */
58 4
    public function init(callable $stateInitializer)
59
    {
60 4
        $this->stateInitializer = $stateInitializer;
61 4
        return $this;
62
    }
63
64
    /**
65
     * @param string $streamId
66
     * @return $this
67
     */
68 8
    public function from($streamId)
69
    {
70 8
        $this->from = $streamId;
71 8
        return $this;
72
    }
73
74
    /**
75
     * @return $this
76
     */
77 2
    public function fromAll()
78
    {
79 2
        $this->from('');
80 2
        return $this;
81
    }
82
83
    /**
84
     * @return $this
85
     */
86 2
    public function forEachStream()
87
    {
88 2
        $this->forEachStream = true;
89 2
        return $this;
90
    }
91
92
    /**
93
     * @param string $eventClass
94
     * @param callable $eventHandler
95
     * @return $this
96
     */
97 6
    public function when($eventClass, callable $eventHandler)
98
    {
99 6
        $this->eventHandlers[$eventClass] = $eventHandler;
100 6
        return $this;
101
    }
102
103
    /**
104
     * @return \stdClass
105
     */
106 8
    public function execute()
107
    {
108 8
        $state = $this->initState();
109 8
        if ($this->forEachStream) {
110 2
            $streams = $this->eventStore->readAllStreams();
111 2
            foreach ($streams as $stream) {
112 2
                $state = $this->runStreamProjection($stream);
113
            }
114
        } else {
115 6
            $stream = $this->executeStreamEventsQuery();
116 6
            $state = $this->runStreamProjection($stream);
117
        }
118 8
        foreach ($this->projector->emittedEventsByStream() as $streamId => $events) {
119 3
            $this->eventStore->appendToStream($streamId, $events);
120
        }
121 8
        return $state;
122
    }
123
124
    /**
125
     * @return \DDDominio\EventSourcing\Common\EventStreamInterface
126
     */
127 6
    private function executeStreamEventsQuery()
128
    {
129 6
        return empty($this->from) ?
130 1
            $stream = $this->eventStore->readAllEvents() :
131 6
            $stream = $this->eventStore->readFullStream($this->from);
132
    }
133
134
    /**
135
     * @param EventStreamInterface $stream
136
     * @return \stdClass
137
     */
138 7
    private function runStreamProjection($stream)
139
    {
140 7
        $state = $this->initState();
141 7
        foreach ($stream as $event) {
142
            /** @var EventInterface $event */
143 5
            if (isset($this->eventHandlers[get_class($event->data())])) {
144 5
                $this->eventHandlers[get_class($event->data())]($event->data(), $state, $this->projector);
145
            }
146
        }
147 7
        return $state;
148
    }
149
150
    /**
151
     * @return \stdClass
152
     */
153 8
    private function initState()
154
    {
155 8
        $stateInitializer = $this->stateInitializer;
156 8
        return $stateInitializer(new \stdClass());
157
    }
158
}
159