1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Rawkode\Eidetic\EventStore\InMemoryEventStore; |
4
|
|
|
|
5
|
|
|
use Rawkode\Eidetic\EventStore\InvalidEventException; |
6
|
|
|
use Rawkode\Eidetic\EventStore\EventStore; |
7
|
|
|
use Rawkode\Eidetic\EventStore\EventPublisherMixin; |
8
|
|
|
use Rawkode\Eidetic\EventStore\NoEventsFoundForKeyException; |
9
|
|
|
use Rawkode\Eidetic\EventStore\Subscriber; |
10
|
|
|
use Rawkode\Eidetic\EventStore\VerifyEventIsAClassTrait; |
11
|
|
|
use Rawkode\Eidetic\EventStore\InMemoryEventStore\TransactionAlreadyInProgressException; |
12
|
|
|
use Rawkode\Eidetic\EventStore\EventPublisher; |
13
|
|
|
use Doctrine\Common\EventSubscriber; |
14
|
|
|
|
15
|
|
|
final class InMemoryEventStore implements EventStore |
16
|
|
|
{ |
17
|
|
|
use EventPublisherMixin; |
18
|
|
|
use VerifyEventIsAClassTrait; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var int |
22
|
|
|
*/ |
23
|
|
|
private $serialNumber = 0; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var array |
27
|
|
|
*/ |
28
|
|
|
private $events = []; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var array |
32
|
|
|
*/ |
33
|
|
|
private $transactionBackup = []; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var array |
37
|
|
|
*/ |
38
|
|
|
private $stagedEvents = []; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @param string $key |
42
|
|
|
* |
43
|
|
|
* @return array |
44
|
|
|
*/ |
45
|
2 |
|
public function retrieve($key) |
46
|
|
|
{ |
47
|
2 |
|
$eventLogs = $this->eventLogs($key); |
48
|
|
|
|
49
|
1 |
|
return array_map(function ($eventLog) { |
50
|
1 |
|
return $eventLog['event']; |
51
|
1 |
|
}, $eventLogs); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @param string $key |
56
|
|
|
* |
57
|
|
|
* @return array |
58
|
|
|
*/ |
59
|
1 |
|
public function retrieveLogs($key) |
60
|
|
|
{ |
61
|
1 |
|
return $this->eventLogs($key); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @param string $key |
66
|
|
|
* |
67
|
|
|
* @throws NoEventsFoundForKeyException |
68
|
|
|
* |
69
|
|
|
* @return array |
70
|
|
|
*/ |
71
|
3 |
|
private function eventLogs($key) |
72
|
|
|
{ |
73
|
3 |
|
$this->verifyEventExistsForKey($key); |
74
|
|
|
|
75
|
2 |
|
return $this->events[$key]; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @param string $key |
80
|
|
|
* @param array $events |
81
|
|
|
* |
82
|
|
|
* @throws TransactionAlreadyInProgressException |
83
|
|
|
* @throws InvalidEventException |
84
|
|
|
*/ |
85
|
5 |
View Code Duplication |
public function store($key, array $events) |
|
|
|
|
86
|
|
|
{ |
87
|
|
|
try { |
88
|
5 |
|
$this->startTransaction(); |
89
|
|
|
|
90
|
5 |
|
foreach ($events as $event) { |
91
|
5 |
|
$this->persistEvent($key, $event); |
92
|
5 |
|
} |
93
|
5 |
|
} catch (InvalidEventException $invalidEventException) { |
94
|
2 |
|
$this->abortTransaction(); |
95
|
|
|
|
96
|
2 |
|
throw $invalidEventException; |
97
|
|
|
} |
98
|
|
|
|
99
|
4 |
|
$this->completeTransaction(); |
100
|
4 |
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* @throws TransactionAlreadyInProgressException |
104
|
|
|
*/ |
105
|
5 |
|
private function startTransaction() |
106
|
|
|
{ |
107
|
5 |
|
$this->transactionBackup = $this->events; |
108
|
5 |
|
$this->stagedEvents = []; |
109
|
5 |
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
*/ |
113
|
2 |
|
private function abortTransaction() |
114
|
|
|
{ |
115
|
2 |
|
$this->events = $this->transactionBackup; |
116
|
2 |
|
$this->stagedEvents = []; |
117
|
2 |
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
*/ |
121
|
4 |
|
private function completeTransaction() |
122
|
|
|
{ |
123
|
4 |
|
$this->transactionBackup = []; |
124
|
|
|
|
125
|
4 |
|
foreach ($this->stagedEvents as $event) { |
126
|
4 |
|
$this->publish(self::EVENT_STORED, $event); |
127
|
4 |
|
} |
128
|
|
|
|
129
|
4 |
|
$this->stagedEvents = []; |
130
|
4 |
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @param string $key |
134
|
|
|
* @param $event |
135
|
|
|
* |
136
|
|
|
* @throws InvalidEventException |
137
|
|
|
*/ |
138
|
5 |
|
private function persistEvent($key, $event) |
139
|
|
|
{ |
140
|
5 |
|
$this->verifyEventIsAClass($event); |
141
|
|
|
|
142
|
5 |
|
$this->events[$key][] = [ |
143
|
5 |
|
'serial_number' => ++$this->serialNumber, |
144
|
5 |
|
'key' => $key, |
145
|
5 |
|
'recorded_at' => new \DateTime('now', new \DateTimeZone('UTC')), |
146
|
5 |
|
'event_class' => get_class($event), |
147
|
5 |
|
'event' => $event, |
148
|
|
|
]; |
149
|
|
|
|
150
|
5 |
|
array_push($this->stagedEvents, $event); |
151
|
5 |
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* @param $key |
155
|
|
|
* @throws NoEventsFoundForKeyException |
156
|
|
|
*/ |
157
|
3 |
|
private function verifyEventExistsForKey($key) |
158
|
|
|
{ |
159
|
3 |
|
if (false === array_key_exists($key, $this->events)) { |
160
|
1 |
|
throw new NoEventsFoundForKeyException(); |
161
|
|
|
} |
162
|
2 |
|
} |
163
|
|
|
} |
164
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.