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

MySqlJsonEventStore   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 209
Duplicated Lines 56.94 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 93.59%

Importance

Changes 0
Metric Value
dl 119
loc 209
c 0
b 0
f 0
wmc 14
lcom 1
cbo 5
ccs 73
cts 78
cp 0.9359
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
B readStreamEventsForward() 32 32 2
B readFullStream() 25 25 1
A readAllStreams() 0 4 1
A readAllEvents() 0 4 1
B appendStoredEvents() 19 36 5
A streamExists() 8 8 1
A streamVersion() 8 8 1
B readStoredEventsOfTypeAndVersion() 27 27 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace DDDominio\EventSourcing\EventStore\Vendor;
4
5
use DDDominio\EventSourcing\Common\EventStream;
6
use DDDominio\EventSourcing\Common\EventStreamInterface;
7
use DDDominio\EventSourcing\EventStore\AbstractEventStore;
8
use DDDominio\EventSourcing\EventStore\ConcurrencyException;
9
use DDDominio\EventSourcing\EventStore\StoredEvent;
10
use DDDominio\EventSourcing\Serialization\SerializerInterface;
11
use DDDominio\EventSourcing\Versioning\EventUpgrader;
12
use DDDominio\EventSourcing\Versioning\Version;
13
14
class MySqlJsonEventStore extends AbstractEventStore
15
{
16
    const MAX_UNSIGNED_BIG_INT = 9223372036854775807;
17
18
    /**
19
     * @var \PDO
20
     */
21
    private $connection;
22
23
    /**
24
     * @param \PDO $connection
25
     * @param SerializerInterface $serializer
26
     * @param EventUpgrader $eventUpgrader
27
     */
28 11
    public function __construct(
29
        \PDO $connection,
30
        SerializerInterface $serializer,
31
        $eventUpgrader
32
    ) {
33 11
        $this->connection = $connection;
34 11
        parent::__construct($serializer, $eventUpgrader);
35 11
    }
36
37
    /**
38
     * @param string $streamId
39
     * @param int $start
40
     * @param int $count
41
     * @return EventStreamInterface
42
     */
43 4 View Code Duplication
    public function readStreamEventsForward($streamId, $start = 1, $count = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
44
    {
45 4
        if (!isset($count)) {
46 3
            $count = self::MAX_UNSIGNED_BIG_INT;
47
        }
48 4
        $stmt = $this->connection->prepare(
49
            'SELECT *
50
             FROM events
51
             WHERE stream_id = :streamId
52
             LIMIT :limit
53 4
             OFFSET :offset'
54
        );
55 4
        $stmt->bindValue(':streamId', $streamId);
56 4
        $stmt->bindValue(':offset', (int) $start - 1, \PDO::PARAM_INT);
57 4
        $stmt->bindValue(':limit', $count, \PDO::PARAM_INT);
58 4
        $stmt->execute();
59 4
        $results = $stmt->fetchAll();
60
61
        $storedEvents = array_map(function($event) {
62 3
            return new StoredEvent(
63 3
                $event['id'],
64 3
                $event['stream_id'],
65 3
                $event['type'],
66 3
                $event['event'],
67 3
                $event['metadata'],
68 3
                new \DateTimeImmutable($event['occurred_on']),
69 3
                Version::fromString($event['version'])
70
            );
71 4
        }, $results);
72
73 4
        return $this->domainEventStreamFromStoredEvents($storedEvents);
74
    }
75
76
    /**
77
     * @param string $streamId
78
     * @return EventStreamInterface
79
     */
80 5 View Code Duplication
    public function readFullStream($streamId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
81
    {
82 5
        $stmt = $this->connection->prepare(
83
            'SELECT *
84
             FROM events
85 5
             WHERE stream_id = :streamId'
86
        );
87 5
        $stmt->bindValue(':streamId', $streamId);
88 5
        $stmt->execute();
89 5
        $results = $stmt->fetchAll();
90
91
        $storedEvents = array_map(function($event) {
92 4
            return new StoredEvent(
93 4
                $event['id'],
94 4
                $event['stream_id'],
95 4
                $event['type'],
96 4
                $event['event'],
97 4
                $event['metadata'],
98 4
                new \DateTimeImmutable($event['occurred_on']),
99 4
                Version::fromString($event['version'])
100
            );
101 5
        }, $results);
102
103 5
        return $this->domainEventStreamFromStoredEvents($storedEvents);
104
    }
105
106
    /**
107
     * @return EventStreamInterface[]
108
     */
109
    public function readAllStreams()
110
    {
111
        // TODO: Implement readAllStreams() method.
112
    }
113
114
    /**
115
     * @return EventStreamInterface
116
     */
117
    public function readAllEvents()
118
    {
119
        // TODO: Implement readAllEvents() method.
120
    }
121
122
    /**
123
     * @param string $streamId
124
     * @param StoredEvent[] $storedEvents
125
     * @param int $expectedVersion
126
     * @throws \Exception
127
     */
128 7
    protected function appendStoredEvents($streamId, $storedEvents, $expectedVersion)
129
    {
130 7
        $this->connection->beginTransaction();
131
        try {
132 7 View Code Duplication
            if (!$this->streamExists($streamId)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
133 7
                $stmt = $this->connection
134 7
                    ->prepare('INSERT INTO streams (id) VALUES (:streamId)');
135 7
                $stmt->bindValue(':streamId', $streamId);
136 7
                $stmt->execute();
137
            }
138 7 View Code Duplication
            foreach ($storedEvents as $storedEvent) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
139 7
                $stmt = $this->connection->prepare(
140
                    'INSERT INTO events (stream_id, type, event, metadata, occurred_on, version)
141 7
                 VALUES (:streamId, :type, :event, :metadata, :occurredOn, :version)'
142
                );
143 7
                $stmt->bindValue(':streamId', $streamId);
144 7
                $stmt->bindValue(':type', $storedEvent->type());
145 7
                $stmt->bindValue(':event', $storedEvent->data());
146 7
                $stmt->bindValue(':metadata', $storedEvent->metadata());
147 7
                $stmt->bindValue(':occurredOn', $storedEvent->occurredOn()->format('Y-m-d H:i:s'));
148 7
                $stmt->bindValue(':version', $storedEvent->version());
149 7
                $stmt->execute();
150
            }
151 7
            $streamFinalVersion = $this->streamVersion($streamId);
152 7
            if (count($storedEvents) !== $streamFinalVersion - $expectedVersion) {
153
                throw ConcurrencyException::fromVersions(
154
                    $this->streamVersion($streamId),
155
                    $expectedVersion
156
                );
157
            }
158 7
            $this->connection->commit();
159
        } catch (\Exception $e) {
160
            $this->connection->rollBack();
161
            throw $e;
162
        }
163 7
    }
164
165
    /**
166
     * @param string $streamId
167
     * @return bool
168
     */
169 8 View Code Duplication
    protected function streamExists($streamId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
170
    {
171 8
        $stmt = $this->connection
172 8
            ->prepare('SELECT COUNT(*) FROM streams WHERE id = :streamId');
173 8
        $stmt->bindValue(':streamId', $streamId);
174 8
        $stmt->execute();
175 8
        return boolval($stmt->fetchColumn());
176
    }
177
178
    /**
179
     * @param string $streamId
180
     * @return int
181
     */
182 7 View Code Duplication
    protected function streamVersion($streamId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
183
    {
184 7
        $stmt = $this->connection
185 7
            ->prepare('SELECT COUNT(*) FROM events WHERE stream_id = :streamId');
186 7
        $stmt->bindValue(':streamId', $streamId);
187 7
        $stmt->execute();
188 7
        return intval($stmt->fetchColumn());
189
    }
190
    /**
191
     * @param string $type
192
     * @param Version $version
193
     * @return EventStreamInterface
194
     */
195 View Code Duplication
    protected function readStoredEventsOfTypeAndVersion($type, $version)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
196
    {
197
        $stmt = $this->connection->prepare(
198
            'SELECT *
199
             FROM events
200
             WHERE type = :type
201
             AND version = :version'
202
        );
203
        $stmt->bindValue(':type', $type);
204
        $stmt->bindValue(':version', $version);
205
        $stmt->execute();
206
        $results = $stmt->fetchAll();
207
208
        $storedEvents = array_map(function($result) {
209
            return new StoredEvent(
210
                $result['id'],
211
                $result['stream_id'],
212
                $result['type'],
213
                $result['event'],
214
                $result['metadata'],
215
                new \DateTimeImmutable($result['occurred_on']),
216
                Version::fromString($result['version'])
217
            );
218
        }, $results);
219
220
        return new EventStream($storedEvents);
221
    }
222
}
223