Failed Conditions
Push — master ( bba48b...029968 )
by Bernhard
16:13
created

MongoDbStore::exists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 13
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 13
loc 13
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of the vendor/project 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 Closure;
15
use Exception;
16
use MongoDB\BSON\Binary;
17
use MongoDB\Collection;
18
use MongoDB\Driver\Exception\UnexpectedValueException;
19
use Webmozart\KeyValueStore\Api\KeyValueStore;
20
use Webmozart\KeyValueStore\Api\NoSuchKeyException;
21
use Webmozart\KeyValueStore\Api\ReadException;
22
use Webmozart\KeyValueStore\Api\UnserializationFailedException;
23
use Webmozart\KeyValueStore\Api\UnsupportedValueException;
24
use Webmozart\KeyValueStore\Api\WriteException;
25
use Webmozart\KeyValueStore\Util\KeyUtil;
26
use Webmozart\KeyValueStore\Util\Serializer;
27
28
/**
29
 * A key-value-store backed by MongoDB.
30
 *
31
 * @since 1.0
32
 *
33
 * @author Bernhard Schussek <[email protected]>
34
 */
35
class MongoDbStore implements KeyValueStore
36
{
37
    /**
38
     * Flag: Disable serialization.
39
     */
40
    const NO_SERIALIZE = 1;
41
42
    /**
43
     * Flag: Support storage of binary data.
44
     */
45
    const SUPPORT_BINARY = 2;
46
47
    private static $typeMap = array(
48
        'root' => 'array',
49
        'document' => 'array',
50
        'array' => 'array',
51
    );
52
53
    /**
54
     * @var Collection
55
     */
56
    private $collection;
57
58
    /**
59
     * @var Closure
60
     */
61
    private $serialize;
62
63
    /**
64
     * @var Closure
65
     */
66
    private $unserialize;
67
68
    public function __construct(Collection $collection, $flags = 0)
69
    {
70
        $this->collection = $collection;
71
72
        if ($flags & self::NO_SERIALIZE) {
73
            if ($flags & self::SUPPORT_BINARY) {
74
                $this->serialize = function ($unserialized) {
75
                    if (!is_string($unserialized)) {
76
                        throw UnsupportedValueException::forValue($unserialized, $this);
77
                    }
78
79
                    return new Binary($unserialized, Binary::TYPE_GENERIC);
80
                };
81
                $this->unserialize = function (Binary $serialized) {
82
                    return $serialized->getData();
83
                };
84
            } else {
85
                $this->serialize = function ($unserialized) {
86
                    if (!is_scalar($unserialized) && !is_array($unserialized) && null !== $unserialized) {
87
                        throw UnsupportedValueException::forValue($unserialized, $this);
88
                    }
89
90
                    return $unserialized;
91
                };
92
                $this->unserialize = function ($serialized) {
93
                    return $serialized;
94
                };
95
            }
96
        } else {
97
            if ($flags & self::SUPPORT_BINARY) {
98
                $this->serialize = function ($unserialized) {
99
                    return new Binary(
100
                        Serializer::serialize($unserialized),
101
                        Binary::TYPE_GENERIC
102
                    );
103
                };
104
                $this->unserialize = function (Binary $serialized) {
105
                    return Serializer::unserialize($serialized->getData());
106
                };
107
            } else {
108
                $this->serialize = function ($unserialized) {
109
                    return Serializer::serialize($unserialized);
110
                };
111
                $this->unserialize = function ($serialized) {
112
                    return Serializer::unserialize($serialized);
113
                };
114
            }
115
        }
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function set($key, $value)
122
    {
123
        KeyUtil::validate($key);
124
125
        $serialized = $this->serialize->__invoke($value);
126
127
        try {
128
            $this->collection->replaceOne(
129
                array('_id' => $key),
130
                array('_id' => $key, 'value' => $serialized),
131
                array('upsert' => true)
132
            );
133
        } catch (UnexpectedValueException $e) {
0 ignored issues
show
Bug introduced by
The class MongoDB\Driver\Exception\UnexpectedValueException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
134
            throw UnsupportedValueException::forType('binary', $this, 0, $e);
135
        } catch (Exception $e) {
136
            throw WriteException::forException($e);
137
        }
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143 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...
144
    {
145
        KeyUtil::validate($key);
146
147
        try {
148
            $document = $this->collection->findOne(
149
                array('_id' => $key),
150
                array('typeMap' => self::$typeMap)
151
            );
152
        } catch (Exception $e) {
153
            throw ReadException::forException($e);
154
        }
155
156
        if (null === $document) {
157
            return $default;
158
        }
159
160
        return $this->unserialize->__invoke($document['value']);
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166 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...
167
    {
168
        KeyUtil::validate($key);
169
170
        try {
171
            $document = $this->collection->findOne(
172
                array('_id' => $key),
173
                array('typeMap' => self::$typeMap)
174
            );
175
        } catch (Exception $e) {
176
            throw ReadException::forException($e);
177
        }
178
179
        if (null === $document) {
180
            throw NoSuchKeyException::forKey($key);
181
        }
182
183
        return $this->unserialize->__invoke($document['value']);
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189
    public function getMultiple(array $keys, $default = null)
190
    {
191
        KeyUtil::validateMultiple($keys);
192
193
        $values = array_fill_keys($keys, $default);
194
195
        try {
196
            $cursor = $this->collection->find(
197
                array('_id' => array('$in' => array_values($keys))),
198
                array('typeMap' => self::$typeMap)
199
            );
200
201
            foreach ($cursor as $document) {
202
                $values[$document['_id']] = $this->unserialize->__invoke($document['value']);
203
            }
204
        } catch (UnserializationFailedException $e) {
205
            throw $e;
206
        } catch (Exception $e) {
207
            throw ReadException::forException($e);
208
        }
209
210
        return $values;
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function getMultipleOrFail(array $keys)
217
    {
218
        KeyUtil::validateMultiple($keys);
219
220
        $values = array();
221
222
        try {
223
            $cursor = $this->collection->find(
224
                array('_id' => array('$in' => array_values($keys))),
225
                array('typeMap' => self::$typeMap)
226
            );
227
228
            foreach ($cursor as $document) {
229
                $values[$document['_id']] = $this->unserialize->__invoke($document['value']);
230
            }
231
        } catch (UnserializationFailedException $e) {
232
            throw $e;
233
        } catch (Exception $e) {
234
            throw ReadException::forException($e);
235
        }
236
237
        $notFoundKeys = array_diff($keys, array_keys($values));
238
239
        if (count($notFoundKeys) > 0) {
240
            throw NoSuchKeyException::forKeys($notFoundKeys);
241
        }
242
243
        return $values;
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249 View Code Duplication
    public function remove($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...
250
    {
251
        KeyUtil::validate($key);
252
253
        try {
254
            $result = $this->collection->deleteOne(array('_id' => $key));
255
            $deletedCount = $result->getDeletedCount();
256
        } catch (Exception $e) {
257
            throw WriteException::forException($e);
258
        }
259
260
        return $deletedCount > 0;
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266 View Code Duplication
    public function exists($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...
267
    {
268
        KeyUtil::validate($key);
269
270
        try {
271
            $count = $this->collection->count(array('_id' => $key));
272
        } catch (Exception $e) {
273
            throw ReadException::forException($e);
274
        }
275
276
        return $count > 0;
277
278
    }
279
280
    /**
281
     * {@inheritdoc}
282
     */
283
    public function clear()
284
    {
285
        try {
286
            $this->collection->drop();
287
        } catch (Exception $e) {
288
            throw WriteException::forException($e);
289
        }
290
    }
291
292
    /**
293
     * {@inheritdoc}
294
     */
295
    public function keys()
296
    {
297
        try {
298
            $cursor = $this->collection->find(array(), array(
299
                'projection' => array('_id' => 1)
300
            ));
301
302
            $keys = array();
303
304
            foreach ($cursor as $document) {
305
                $keys[] = $document['_id'];
306
            }
307
        } catch (Exception $e) {
308
            throw ReadException::forException($e);
309
        }
310
311
        return $keys;
312
    }
313
}
314