Passed
Push — master ( 0df4ae...0079ed )
by Terry
06:10
created

Mongo   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 282
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 88
c 1
b 0
f 0
dl 0
loc 282
ccs 73
cts 73
cp 1
rs 10
wmc 21

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getCollectionName() 0 3 1
A doSet() 0 26 1
A getKeyName() 0 3 1
A __construct() 0 21 3
A doHas() 0 17 2
A doDelete() 0 9 1
A doWriteOperation() 0 15 2
A doClear() 0 9 1
A doGet() 0 21 3
A connect() 0 36 6
1
<?php
2
/*
3
 * This file is part of the Shieldon Simple Cache package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace Shieldon\SimpleCache\Driver;
14
15
use Shieldon\SimpleCache\CacheProvider;
16
use Shieldon\SimpleCache\Exception\CacheException;
17
use MongoDB\Driver\BulkWrite as MongoWrite;
18
use MongoDB\Driver\Exception\BulkWriteException;
19
use MongoDB\Driver\Manager as MongoServer;
20
use MongoDB\Driver\Query as MongoQuery;
21
use MongoDB\Driver\WriteConcern;
22
use Exception;
23
use function array_keys;
24
use function extension_loaded;
25
use function unserialize;
26
use function serialize;
27
28
/**
29
 * A cache driver class used for MongoDB.
30
 */
31
class Mongo extends CacheProvider
32
{
33
    /**
34
     * The MongoDB Manager instance.
35
     *
36
     * @var \MongoDB\Driver\Manager|null
37
     */
38
    protected $mongo = null;
39
40
    /**
41
     * Use the default "test" dbname, if not specify any.
42
     *
43
     * @var string
44
     */
45
    protected $dbname = 'test';
46
47
    /**
48
     * Collection name.
49
     *
50
     * @var string
51
     */
52
    protected $collection = 'cache_data';
53
54
    /**
55
     * The write concern.
56
     *
57
     * @var \MongoDB\Driver\WriteConcern|null
58
     * @see https://www.php.net/manual/en/class.mongodb-driver-writeconcern.php
59
     */
60
    protected $concern;
61
62
    /**
63
     * Constructor.
64
     *
65
     * @param array $setting The settings.
66
     * 
67
     * @throws CacheException
68
     */
69 10
    public function __construct(array $setting = [])
70
    {
71
        $config = [
72 10
            'host'       => '127.0.0.1',
73
            'port'       => 27017,
74
            'user'       => null,
75
            'pass'       => null,
76
            'dbname'     => 'test',
77
            'collection' => 'cache_data',
78
        ];
79
80 10
        foreach (array_keys($config) as $key) {
81 10
            if (isset($setting[$key])) {
82 10
                $config[$key] = $setting[$key];
83
            }
84
        }
85
86 10
        $this->connect($config);
87
88 10
        $this->dbname     = $config['dbname'];
89 10
        $this->collection = $config['collection'];
90 10
    }
91
92
    /**
93
     * Connect to MongoDB server.
94
     *
95
     * @param array $config The settings.
96
     * 
97
     * @return void
98
     * 
99
     * @throws CacheException
100
     */
101 10
    protected function connect(array $config): void
102
    {
103 10
        if (extension_loaded('mongodb')) {
104
            try {
105 10
                $auth = '';
106 10
                $dababase = '';
107
108
                if (
109 10
                    !empty($config['user']) && 
110 10
                    !empty($config['pass'])
111
                ) {
112 2
                    $auth = $config['user'] . ':' . $config['pass'] . '@';
113
                }
114
115 10
                if (!empty($config['dbname'])) {
116 10
                    $dababase = '/' . $config['dbname'];
117
                }
118
119
                // Basic => mongodb://127.0.0.1:27017
120
                // mongodb://user:[email protected]:27017/dbname
121 10
                $command = 'mongodb://' . $auth . $config['host'] . ':' . $config['port'] . $dababase;
122
    
123 10
                $this->mongo = new MongoServer($command);
124 10
                $this->concern = new WriteConcern(WriteConcern::MAJORITY, 1000);
125
126
            // @codeCoverageIgnoreStart
127
            } catch (Exception $e) {
128
                throw new CacheException($e->getMessage());
129
            }
130
            // @codeCoverageIgnoreEnd
131 10
            return;
132
        }
133
134
        // @codeCoverageIgnoreStart
135
        throw new CacheException(
136
            'PHP MongoDB extension is not installed on your system.'
137
        );
138
        // @codeCoverageIgnoreEnd
139
    }
140
141
    /**
142
     * Fetch a cache by an extended Cache Driver.
143
     *
144
     * @param string $key The key of a cache.
145
     *
146
     * @return array
147
     */
148 6
    protected function doGet(string $key): array
149
    {
150
        $filter = [
151 6
            '_id' => $this->getKeyName($key),
152
        ];
153
154 6
        $option = [];
155
156 6
        $query = new MongoQuery($filter, $option);
157 6
        $cursor = $this->mongo->executeQuery($this->getCollectionName(), $query);
0 ignored issues
show
Bug introduced by
The method executeQuery() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

157
        /** @scrutinizer ignore-call */ 
158
        $cursor = $this->mongo->executeQuery($this->getCollectionName(), $query);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
158
159 6
        $data = [];
160 6
        foreach($cursor as $document) {
161 6
            $data[] = unserialize($document->content);
162
        }
163
164 6
        if (empty($data)) {
165 4
            return [];
166
        }
167
168 6
        return $data[0];
169
    }
170
171
    /**
172
     * Set a cache by an extended Cache Driver.
173
     *
174
     * @param string $key       The key of a cache.
175
     * @param mixed  $value     The value of a cache. (serialized)
176
     * @param int    $ttl       The time to live for a cache.
177
     * @param int    $timestamp The time to store a cache.
178
     *
179
     * @return bool
180
     */
181 8
    protected function doSet(string $key, $value, int $ttl, int $timestamp): bool
182
    {
183
        $contents = [
184 8
            'timestamp' => $timestamp,
185 8
            'ttl'       => $ttl,
186 8
            'value'     => $value,
187
        ];
188
189
        $filter = [
190 8
            '_id'=> $this->getKeyName($key),
191
        ];
192
193
        $data = [
194 8
            'content'  => serialize($contents),
195 8
            'sc_cache' => 1,
196
        ];
197
198
        $option = [
199 8
            'multi'  => false, 
200
            'upsert' => true,
201
        ];
202
203 8
        $bulk = new MongoWrite();
204 8
        $bulk->update($filter, $data, $option);
205
206 8
        return $this->doWriteOperation($bulk);
207
    }
208
209
    /**
210
     * Delete a cache by an extended Cache Driver.
211
     *
212
     * @param string $key The key of a cache.
213
     * 
214
     * @return bool
215
     */
216 4
    protected function doDelete(string $key): bool
217
    {
218 4
        $bulk = new MongoWrite();
219
220 4
        $bulk->delete([
221 4
            '_id' => $this->getKeyName($key),
222
        ]);
223
224 4
        return $this->doWriteOperation($bulk);
225
    }
226
227
    /**
228
     * Delete all caches by an extended Cache Driver.
229
     * 
230
     * @return bool
231
     */
232 2
    protected function doClear(): bool
233
    {
234 2
        $bulk = new MongoWrite();
235
236 2
        $bulk->delete([
237 2
            'sc_cache' => 1,
238
        ]);
239
240 2
        return $this->doWriteOperation($bulk);
241
    }
242
243
    /**
244
     * Check if the cache exists or not.
245
     *
246
     * @param string $key The key of a cache.
247
     *
248
     * @return bool
249
     */
250 4
    protected function doHas(string $key): bool
251
    {
252
        $filter = [
253 4
            '_id' => $this->getKeyName($key),
254
        ];
255
256 4
        $option = [];
257
258 4
        $query = new MongoQuery($filter, $option);
259 4
        $cursor = $this->mongo->executeQuery($this->getCollectionName(), $query);
260 4
        $results = $cursor->toArray();
261
262 4
        if (empty($results)) {
263 4
            return false;
264
        }
265
266 4
        return true;
267
    }
268
269
    /**
270
     * Perform the write operation and return the result.
271
     * 
272
     * @param object $bulk The \MongoDB\Driver\BulkWrite instance.
273
     *
274
     * @return bool
275
     */
276 8
    private function doWriteOperation(MongoWrite $bulk): bool
277
    {
278
        try {
279 8
            $this->mongo->executeBulkWrite(
280 8
                $this->getCollectionName(),
281 8
                $bulk,
282 8
                $this->concern
283
            );
284
        // @codeCoverageIgnoreStart
285
        } catch (BulkWriteException $e) {
286
            return false;
287
        }
288
        // @codeCoverageIgnoreEnd
289
290 6
        return true;
291
    }
292
293
    /**
294
     * Get the key name of a cache.
295
     *
296
     * @param string $key The key of a cache.
297
     *
298
     * @return string
299
     */
300 8
    private function getKeyName(string $key): string
301
    {
302 8
        return 'sc_' . md5($key);
303
    }
304
305
    /**
306
     * Get the collection name.
307
     *
308
     * @return string
309
     */
310 8
    private function getCollectionName(): string
311
    {
312 8
        return $this->dbname . '.' . $this->collection; 
313
    }
314
}
315