Passed
Push — master ( 4bba79...d3b029 )
by Terry
17:12
created

Mongo::getAll()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 0
dl 0
loc 13
ccs 9
cts 9
cp 1
crap 2
rs 10
c 0
b 0
f 0
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 14
    public function __construct(array $setting = [])
70
    {
71
        $config = [
72 14
            'host'       => '127.0.0.1',
73
            'port'       => 27017,
74
            'user'       => null,
75
            'pass'       => null,
76
            'dbname'     => 'test',
77
            'collection' => 'cache_data',
78
        ];
79
80 14
        foreach (array_keys($config) as $key) {
81 14
            if (isset($setting[$key])) {
82 14
                $config[$key] = $setting[$key];
83
            }
84
        }
85
86 14
        $this->connect($config);
87
88 14
        $this->dbname     = $config['dbname'];
89 14
        $this->collection = $config['collection'];
90 14
    }
91
92
    /**
93
     * Connect to MongoDB server.
94
     *
95
     * @param array $config The settings.
96
     * 
97
     * @return void
98
     * 
99
     * @throws CacheException
100
     */
101 14
    protected function connect(array $config): void
102
    {
103 14
        if (extension_loaded('mongodb')) {
104
            try {
105 14
                $auth = '';
106 14
                $dababase = '';
107
108
                if (
109 14
                    !empty($config['user']) && 
110 14
                    !empty($config['pass'])
111
                ) {
112 2
                    $auth = $config['user'] . ':' . $config['pass'] . '@';
113
                }
114
115 14
                if (!empty($config['dbname'])) {
116 14
                    $dababase = '/' . $config['dbname'];
117
                }
118
119
                // Basic => mongodb://127.0.0.1:27017
120
                // mongodb://user:[email protected]:27017/dbname
121 14
                $command = 'mongodb://' . $auth . $config['host'] . ':' . $config['port'] . $dababase;
122
    
123 14
                $this->mongo = new MongoServer($command);
124 14
                $this->concern = new WriteConcern(WriteConcern::MAJORITY, 1000);
125
126
            // @codeCoverageIgnoreStart
127
            } catch (Exception $e) {
128
                throw new CacheException($e->getMessage());
129
            }
130
            // @codeCoverageIgnoreEnd
131 14
            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 8
    protected function doGet(string $key): array
149
    {
150
        $filter = [
151 8
            '_id' => $this->getKeyName($key),
152
        ];
153
154 8
        $option = [];
155
156 8
        $query = new MongoQuery($filter, $option);
157 8
        $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 8
        $data = [];
160 8
        foreach($cursor as $document) {
161 8
            $data[] = unserialize($document->content);
162
        }
163
164 8
        if (empty($data)) {
165 6
            return [];
166
        }
167
168 8
        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 12
    protected function doSet(string $key, $value, int $ttl, int $timestamp): bool
182
    {
183
        $contents = [
184 12
            'timestamp' => $timestamp,
185 12
            'ttl'       => $ttl,
186 12
            'value'     => $value,
187
        ];
188
189
        $filter = [
190 12
            '_id'=> $this->getKeyName($key),
191
        ];
192
193
        $data = [
194 12
            'content'  => serialize($contents),
195 12
            'sc_cache' => 1,
196
        ];
197
198
        $option = [
199 12
            'multi'  => false, 
200
            'upsert' => true,
201
        ];
202
203 12
        $bulk = new MongoWrite();
204 12
        $bulk->update($filter, $data, $option);
205
206 12
        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 6
    protected function doDelete(string $key): bool
217
    {
218 6
        $bulk = new MongoWrite();
219
220 6
        $bulk->delete([
221 6
            '_id' => $this->getKeyName($key),
222
        ]);
223
224 6
        return $this->doWriteOperation($bulk);
225
    }
226
227
    /**
228
     * Delete all caches by an extended Cache Driver.
229
     * 
230
     * @return bool
231
     */
232 6
    protected function doClear(): bool
233
    {
234 6
        $bulk = new MongoWrite();
235
236 6
        $bulk->delete([
237 6
            'sc_cache' => 1,
238
        ]);
239
240 6
        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
     * Fetch all cache items.
271
     *
272
     * @return array
273
     */
274 4
    protected function getAll(): array
275
    {
276 4
        $list = [];
277
278 4
        $query = new MongoQuery([]);
279 4
        $cursor = $this->mongo->executeQuery($this->getCollectionName(), $query);
280
281 4
        foreach ($cursor as $document) {
282 4
            $key = str_replace('sc_', '', $document->_id);
283 4
            $value = unserialize($document->content);
284 4
            $list[$key] = $value;
285
        }
286 4
        return $list;
287
    }
288
289
    /**
290
     * Perform the write operation and return the result.
291
     * 
292
     * @param object $bulk The \MongoDB\Driver\BulkWrite instance.
293
     *
294
     * @return bool
295
     */
296 12
    private function doWriteOperation(MongoWrite $bulk): bool
297
    {
298
        try {
299 12
            $this->mongo->executeBulkWrite(
300 12
                $this->getCollectionName(),
301 12
                $bulk,
302 12
                $this->concern
303
            );
304
        // @codeCoverageIgnoreStart
305
        } catch (BulkWriteException $e) {
306
            return false;
307
        }
308
        // @codeCoverageIgnoreEnd
309
310 10
        return true;
311
    }
312
313
    /**
314
     * Get the key name of a cache.
315
     *
316
     * @param string $key The key of a cache.
317
     *
318
     * @return string
319
     */
320 12
    private function getKeyName(string $key): string
321
    {
322 12
        return 'sc_' . $key;
323
    }
324
325
    /**
326
     * Get the collection name.
327
     *
328
     * @return string
329
     */
330 12
    private function getCollectionName(): string
331
    {
332 12
        return $this->dbname . '.' . $this->collection; 
333
    }
334
}
335