1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Cache package. |
5
|
|
|
* |
6
|
|
|
* Copyright (c) Daniel González |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
* |
11
|
|
|
* @author Daniel González <[email protected]> |
12
|
|
|
* @author Arnold Daniels <[email protected]> |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
declare(strict_types=1); |
16
|
|
|
|
17
|
|
|
namespace Desarrolla2\Cache; |
18
|
|
|
|
19
|
|
|
use Desarrolla2\Cache\Packer\PackerInterface; |
20
|
|
|
use Desarrolla2\Cache\Packer\MongoDBBinaryPacker; |
21
|
|
|
use Desarrolla2\Cache\Option\InitializeTrait as InitializeOption; |
22
|
|
|
use MongoDB\Collection; |
23
|
|
|
use MongoDB\BSON\UTCDatetime as BSONUTCDateTime; |
24
|
|
|
use MongoDB\Driver\Exception\RuntimeException as MongoDBRuntimeException; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* MongoDB cache implementation |
28
|
|
|
*/ |
29
|
|
|
class MongoDB extends AbstractCache |
30
|
|
|
{ |
31
|
|
|
use InitializeOption; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var Collection |
35
|
|
|
*/ |
36
|
|
|
protected $collection; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Class constructor |
40
|
|
|
* |
41
|
|
|
* @param Collection $collection |
42
|
|
|
*/ |
43
|
198 |
|
public function __construct(Collection $collection) |
44
|
|
|
{ |
45
|
198 |
|
$this->collection = $collection; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Initialize the DB collection. |
50
|
|
|
* Set TTL index. |
51
|
|
|
*/ |
52
|
|
|
protected function initialize(): void |
53
|
|
|
{ |
54
|
|
|
$this->collection->createIndex(['ttl' => 1], ['expireAfterSeconds' => 0]); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Create the default packer for this cache implementation. |
60
|
|
|
* |
61
|
|
|
* @return PackerInterface |
62
|
|
|
*/ |
63
|
61 |
|
protected static function createDefaultPacker(): PackerInterface |
64
|
|
|
{ |
65
|
61 |
|
return new MongoDBBinaryPacker(); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Get filter for key and ttl. |
70
|
|
|
* |
71
|
|
|
* @param string|iterable $key |
72
|
|
|
* @return array |
73
|
|
|
*/ |
74
|
45 |
|
protected function filter($key) |
75
|
|
|
{ |
76
|
45 |
|
if (is_array($key)) { |
77
|
11 |
|
$key = ['$in' => $key]; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
return [ |
81
|
45 |
|
'_id' => $key, |
82
|
|
|
'$or' => [ |
83
|
45 |
|
['ttl' => ['$gt' => new BSONUTCDateTime($this->currentTimestamp() * 1000)]], |
84
|
|
|
['ttl' => null] |
85
|
|
|
] |
86
|
|
|
]; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* {@inheritdoc } |
91
|
|
|
*/ |
92
|
52 |
|
public function get($key, $default = null) |
93
|
|
|
{ |
94
|
52 |
|
$filter = $this->filter($this->keyToId($key)); |
95
|
|
|
|
96
|
|
|
try { |
97
|
34 |
|
$data = $this->collection->findOne($filter); |
98
|
|
|
} catch (MongoDBRuntimeException $e) { |
99
|
|
|
return $default; |
100
|
|
|
} |
101
|
|
|
|
102
|
34 |
|
return isset($data) ? $this->unpack($data['value']) : $default; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* {@inheritdoc} |
107
|
|
|
*/ |
108
|
30 |
|
public function getMultiple($keys, $default = null) |
109
|
|
|
{ |
110
|
30 |
|
$idKeyPairs = $this->mapKeysToIds($keys); |
111
|
|
|
|
112
|
11 |
|
if (empty($idKeyPairs)) { |
113
|
|
|
return []; |
114
|
|
|
} |
115
|
|
|
|
116
|
11 |
|
$filter = $this->filter(array_keys($idKeyPairs)); |
117
|
11 |
|
$items = array_fill_keys(array_values($idKeyPairs), $default); |
118
|
|
|
|
119
|
|
|
try { |
120
|
11 |
|
$rows = $this->collection->find($filter); |
121
|
|
|
} catch (MongoDBRuntimeException $e) { |
122
|
|
|
return $items; |
123
|
|
|
} |
124
|
|
|
|
125
|
11 |
|
foreach ($rows as $row) { |
126
|
11 |
|
$id = $row['_id']; |
127
|
11 |
|
$key = $idKeyPairs[$id]; |
128
|
|
|
|
129
|
11 |
|
$items[$key] = $this->unpack($row['value']); |
130
|
|
|
} |
131
|
|
|
|
132
|
11 |
|
return $items; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* {@inheritdoc } |
137
|
|
|
*/ |
138
|
22 |
|
public function has($key) |
139
|
|
|
{ |
140
|
22 |
|
$filter = $this->filter($this->keyToId($key)); |
141
|
|
|
|
142
|
|
|
try { |
143
|
4 |
|
$count = $this->collection->count($filter); |
|
|
|
|
144
|
|
|
} catch (MongoDBRuntimeException $e) { |
145
|
|
|
return false; |
146
|
|
|
} |
147
|
|
|
|
148
|
4 |
|
return $count > 0; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* {@inheritdoc } |
153
|
|
|
*/ |
154
|
58 |
|
public function set($key, $value, $ttl = null) |
155
|
|
|
{ |
156
|
58 |
|
$id = $this->keyToId($key); |
157
|
|
|
|
158
|
|
|
$item = [ |
159
|
|
|
'_id' => $id, |
160
|
40 |
|
'ttl' => $this->getTtlBSON($ttl), |
161
|
30 |
|
'value' => $this->pack($value) |
162
|
|
|
]; |
163
|
|
|
|
164
|
|
|
try { |
165
|
30 |
|
$this->collection->replaceOne(['_id' => $id], $item, ['upsert' => true]); |
166
|
|
|
} catch (MongoDBRuntimeException $e) { |
167
|
|
|
return false; |
168
|
|
|
} |
169
|
|
|
|
170
|
30 |
|
return true; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* {@inheritdoc} |
175
|
|
|
*/ |
176
|
42 |
|
public function setMultiple($values, $ttl = null) |
177
|
|
|
{ |
178
|
42 |
|
$this->assertIterable($values, 'values not iterable'); |
179
|
|
|
|
180
|
41 |
|
if (empty($values)) { |
181
|
|
|
return true; |
182
|
|
|
} |
183
|
|
|
|
184
|
41 |
|
$bsonTtl = $this->getTtlBSON($ttl); |
185
|
31 |
|
$items = []; |
186
|
|
|
|
187
|
31 |
|
foreach ($values as $key => $value) { |
188
|
31 |
|
$id = $this->keyToId(is_int($key) ? (string)$key : $key); |
189
|
|
|
|
190
|
31 |
|
$items[] = [ |
191
|
|
|
'replaceOne' => [ |
192
|
31 |
|
['_id' => $id], |
193
|
|
|
[ |
194
|
31 |
|
'_id' => $id, |
195
|
|
|
'ttl' => $bsonTtl, |
196
|
31 |
|
'value' => $this->pack($value) |
197
|
|
|
], |
198
|
|
|
[ 'upsert' => true ] |
199
|
|
|
] |
200
|
|
|
]; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
try { |
204
|
14 |
|
$this->collection->bulkWrite($items); |
205
|
|
|
} catch (MongoDBRuntimeException $e) { |
206
|
|
|
return false; |
207
|
|
|
} |
208
|
|
|
|
209
|
14 |
|
return true; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* {@inheritdoc} |
214
|
|
|
*/ |
215
|
20 |
|
public function delete($key) |
216
|
|
|
{ |
217
|
20 |
|
$id = $this->keyToId($key); |
218
|
|
|
|
219
|
|
|
try { |
220
|
2 |
|
$this->collection->deleteOne(['_id' => $id]); |
221
|
|
|
} catch (MongoDBRuntimeException $e) { |
222
|
|
|
return false; |
223
|
|
|
} |
224
|
|
|
|
225
|
2 |
|
return true; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* {@inheritdoc} |
230
|
|
|
*/ |
231
|
21 |
|
public function deleteMultiple($keys) |
232
|
|
|
{ |
233
|
21 |
|
$idKeyPairs = $this->mapKeysToIds($keys); |
234
|
|
|
|
235
|
|
|
try { |
236
|
2 |
|
if (!empty($idKeyPairs)) { |
237
|
2 |
|
$this->collection->deleteMany(['_id' => ['$in' => array_keys($idKeyPairs)]]); |
238
|
|
|
} |
239
|
|
|
} catch (MongoDBRuntimeException $e) { |
240
|
|
|
return false; |
241
|
|
|
} |
242
|
|
|
|
243
|
2 |
|
return true; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* {@inheritdoc} |
248
|
|
|
*/ |
249
|
198 |
|
public function clear() |
250
|
|
|
{ |
251
|
|
|
try { |
252
|
198 |
|
$this->collection->drop(); |
253
|
|
|
} catch (MongoDBRuntimeException $e) { |
254
|
|
|
return false; |
255
|
|
|
} |
256
|
|
|
|
257
|
198 |
|
$this->requireInitialization(); |
258
|
|
|
|
259
|
198 |
|
return true; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* Get TTL as Date type BSON object |
265
|
|
|
* |
266
|
|
|
* @param null|int|\DateInterval $ttl |
267
|
|
|
* @return BSONUTCDatetime|null |
268
|
|
|
*/ |
269
|
81 |
|
protected function getTtlBSON($ttl): ?BSONUTCDatetime |
270
|
|
|
{ |
271
|
81 |
|
return isset($ttl) ? new BSONUTCDateTime($this->ttlToTimestamp($ttl) * 1000) : null; |
272
|
|
|
} |
273
|
|
|
} |
274
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.