DbalStore   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 272
Duplicated Lines 11.76 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 88.98%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 35
c 1
b 0
f 0
lcom 1
cbo 10
dl 32
loc 272
ccs 105
cts 118
cp 0.8898
rs 9

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getTableName() 0 4 1
A getMultiple() 4 22 3
A __construct() 0 7 1
A set() 0 16 3
A get() 12 12 2
A getOrFail() 12 12 2
B getMultipleOrFail() 4 24 3
A remove() 0 12 2
A exists() 0 12 3
A clear() 0 9 2
A keys() 0 11 2
A getTableForCreate() 0 14 1
A doInsert() 0 13 2
A doUpdate() 0 14 2
A doGetMultiple() 0 14 3
A getDbRow() 0 14 3

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
/*
4
 * This file is part of the webmozart/key-value-store package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
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 Webmozart\KeyValueStore;
13
14
use Doctrine\DBAL\Connection;
15
use Doctrine\DBAL\Schema\Schema;
16
use Doctrine\DBAL\Schema\Table;
17
use Exception;
18
use PDO;
19
use Webmozart\Assert\Assert;
20
use Webmozart\KeyValueStore\Api\KeyValueStore;
21
use Webmozart\KeyValueStore\Api\NoSuchKeyException;
22
use Webmozart\KeyValueStore\Api\ReadException;
23
use Webmozart\KeyValueStore\Api\WriteException;
24
use Webmozart\KeyValueStore\Util\KeyUtil;
25
use Webmozart\KeyValueStore\Util\Serializer;
26
27
/**
28
 * A key-value store backed by Doctrine DBAL.
29
 *
30
 * @since  1.0
31
 *
32
 * @author Bernhard Schussek <[email protected]>
33
 * @author Michiel Boeckaert <[email protected]>
34
 */
35
class DbalStore implements KeyValueStore
36
{
37
    private $connection;
38
    private $tableName;
39
40
    /**
41
     * @param Connection $connection A doctrine connection instance
42
     * @param string     $tableName  The name of the database table
43
     */
44 19
    public function __construct(Connection $connection, $tableName = 'store')
45
    {
46 19
        Assert::stringNotEmpty($tableName, 'The table must be a string. Got: %s');
47
48 15
        $this->connection = $connection;
49 15
        $this->tableName = $tableName;
50 15
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55 59
    public function set($key, $value)
56
    {
57 59
        KeyUtil::validate($key);
58
59
        try {
60 57
            $existing = $this->exists($key);
61 1
        } catch (Exception $e) {
62 1
            throw WriteException::forException($e);
63
        }
64
65 56
        if (false === $existing) {
66 56
            $this->doInsert($key, $value);
67
        } else {
68 1
            $this->doUpdate($key, $value);
69
        }
70 54
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75 8 View Code Duplication
    public function get($key, $default = 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...
76
    {
77 8
        KeyUtil::validate($key);
78
79 6
        $dbResult = $this->getDbRow($key);
80
81 5
        if (null === $dbResult) {
82 1
            return $default;
83
        }
84
85 4
        return Serializer::unserialize($dbResult['meta_value']);
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91 32 View Code Duplication
    public function getOrFail($key)
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...
92
    {
93 32
        KeyUtil::validate($key);
94
95 30
        $dbResult = $this->getDbRow($key);
96
97 29
        if (null === $dbResult) {
98 1
            throw NoSuchKeyException::forKey($key);
99
        }
100
101 28
        return Serializer::unserialize($dbResult['meta_value']);
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107 7
    public function getMultiple(array $keys, $default = null)
108
    {
109 7
        KeyUtil::validateMultiple($keys);
110
111
        // Normalize indices of the array
112 5
        $keys = array_values($keys);
113 5
        $data = $this->doGetMultiple($keys);
114
115 3
        $results = array();
116 3
        $resolved = array();
117 3 View Code Duplication
        foreach ($data as $row) {
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...
118 3
            $results[$row['meta_key']] = Serializer::unserialize($row['meta_value']);
119 2
            $resolved[$row['meta_key']] = $row['meta_key'];
120
        }
121
122 2
        $notResolvedArr = array_diff($keys, $resolved);
123 2
        foreach ($notResolvedArr as $notResolved) {
124 1
            $results[$notResolved] = $default;
125
        }
126
127 2
        return $results;
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 31
    public function getMultipleOrFail(array $keys)
134
    {
135 31
        KeyUtil::validateMultiple($keys);
136
137
        // Normalize indices of the array
138 29
        $keys = array_values($keys);
139
140 29
        $data = $this->doGetMultiple($keys);
141
142 29
        $results = array();
143 29
        $resolved = array();
144 29 View Code Duplication
        foreach ($data as $row) {
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...
145 29
            $results[$row['meta_key']] = Serializer::unserialize($row['meta_value']);
146 28
            $resolved[] = $row['meta_key'];
147
        }
148
149 28
        $notResolvedArr = array_diff($keys, $resolved);
150
151 28
        if (!empty($notResolvedArr)) {
152 1
            throw NoSuchKeyException::forKeys($notResolvedArr);
153
        }
154
155 27
        return $results;
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161 10
    public function remove($key)
162
    {
163 10
        KeyUtil::validate($key);
164
165
        try {
166 8
            $result = $this->connection->delete($this->tableName, array('meta_key' => $key));
167 1
        } catch (Exception $e) {
168 1
            throw WriteException::forException($e);
169
        }
170
171 7
        return $result === 1;
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177 60
    public function exists($key)
178
    {
179 60
        KeyUtil::validate($key);
180
181
        try {
182 58
            $result = $this->connection->fetchAssoc('SELECT * FROM '.$this->tableName.' WHERE meta_key = ?', array($key));
183 2
        } catch (Exception $e) {
184 2
            throw ReadException::forException($e);
185
        }
186
187 56
        return $result ? true : false;
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193 89
    public function clear()
194
    {
195
        try {
196 89
            $stmt = $this->connection->query('DELETE FROM '.$this->tableName);
197 89
            $stmt->execute();
198 1
        } catch (Exception $e) {
199 1
            throw WriteException::forException($e);
200
        }
201 89
    }
202
203
    /**
204
     * {@inheritdoc}
205
     */
206 4
    public function keys()
207
    {
208
        try {
209 4
            $stmt = $this->connection->query('SELECT meta_key FROM '.$this->tableName);
210 3
            $result = $stmt->fetchAll(PDO::FETCH_COLUMN);
211 1
        } catch (Exception $e) {
212 1
            throw ReadException::forException($e);
213
        }
214
215 3
        return $result;
216
    }
217
218
    /**
219
     * The name for our DBAL database table.
220
     *
221
     * @return string
222
     */
223 2
    public function getTableName()
224
    {
225 2
        return $this->tableName;
226
    }
227
228
    /**
229
     * Object Representation of the table used in this class.
230
     *
231
     * @return Table
232
     */
233
    public function getTableForCreate()
234
    {
235
        $schema = new Schema();
236
237
        $table = $schema->createTable($this->getTableName());
238
239
        $table->addColumn('id', 'integer', array('autoincrement' => true));
240
        $table->addColumn('meta_key', 'string', array('length' => 255));
241
        $table->addColumn('meta_value', 'object');
242
        $table->setPrimaryKey(array('id'));
243
        $table->addUniqueIndex(array('meta_key'));
244
245
        return $table;
246
    }
247
248 56
    private function doInsert($key, $value)
249
    {
250 56
        $serialized = Serializer::serialize($value);
251
252
        try {
253 54
            $this->connection->insert($this->tableName, array(
254 54
                'meta_key' => $key,
255 54
                'meta_value' => $serialized,
256
            ));
257
        } catch (Exception $e) {
258
            throw WriteException::forException($e);
259
        }
260 54
    }
261
262 1
    private function doUpdate($key, $value)
263
    {
264 1
        $serialized = Serializer::serialize($value);
265
266
        try {
267 1
            $this->connection->update($this->tableName, array(
268 1
                'meta_value' => $serialized,
269
            ), array(
270 1
                'meta_key' => $key,
271
            ));
272
        } catch (Exception $e) {
273
            throw WriteException::forException($e);
274
        }
275 1
    }
276
277 34
    private function doGetMultiple(array $keys)
278
    {
279
        try {
280 34
            $stmt = $this->connection->executeQuery('SELECT * FROM '.$this->tableName.' WHERE meta_key IN (?)',
281 34
                array($keys),
282 34
                array(Connection::PARAM_STR_ARRAY)
283
            );
284 32
            $data = $stmt->fetchAll();
285 2
        } catch (Exception $e) {
286 2
            throw ReadException::forException($e);
287
        }
288
289 32
        return is_array($data) ? $data : array();
290
    }
291
292 36
    private function getDbRow($key)
293
    {
294
        try {
295 36
            $dbResult = $this->connection->fetchAssoc('SELECT meta_value, meta_key FROM '.$this->tableName.' WHERE meta_key = ?', array($key));
296 2
        } catch (Exception $e) {
297 2
            throw ReadException::forException($e);
298
        }
299
300 34
        if (empty($dbResult)) {
301 2
            return null;
302
        }
303
304 32
        return $dbResult;
305
    }
306
}
307