|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Kemist\Cache; |
|
4
|
|
|
|
|
5
|
|
|
use Kemist\Cache\Storage\StorageInterface; |
|
6
|
|
|
|
|
7
|
|
|
/** |
|
8
|
|
|
* Cache object for caching variables |
|
9
|
|
|
* |
|
10
|
|
|
* @package Kemist\Cache |
|
11
|
|
|
* |
|
12
|
|
|
* @version 1.2.0 |
|
13
|
|
|
*/ |
|
14
|
|
|
class Cache { |
|
15
|
|
|
|
|
16
|
|
|
/** |
|
17
|
|
|
* Cache storage object |
|
18
|
|
|
* @var StorageInterface |
|
19
|
|
|
*/ |
|
20
|
|
|
protected $storage; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* Caching is enabled |
|
24
|
|
|
* @var bool |
|
25
|
|
|
*/ |
|
26
|
|
|
protected $enabled = true; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* Key name encryption |
|
30
|
|
|
* @var bool |
|
31
|
|
|
*/ |
|
32
|
|
|
protected $encryptKeys = true; |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Cache values information |
|
36
|
|
|
* @var Info |
|
37
|
|
|
*/ |
|
38
|
|
|
protected $info; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* Read key names |
|
42
|
|
|
* @var array |
|
43
|
|
|
*/ |
|
44
|
|
|
protected $readKeys = array(); |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* System reserved info key |
|
48
|
|
|
* @var string |
|
49
|
|
|
*/ |
|
50
|
|
|
protected $infoKey = '_system.info'; |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* Initialised (-1: not yet, 0: in progress, 1: initialised) |
|
54
|
|
|
* @var int |
|
55
|
|
|
*/ |
|
56
|
|
|
protected $initialised = -1; |
|
57
|
|
|
|
|
58
|
|
|
const STORE_METHOD_SERIALIZE = 1; |
|
59
|
|
|
const STORE_METHOD_JSON = 2; |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* Constructor |
|
63
|
|
|
* |
|
64
|
|
|
* @param StorageInterface $storage |
|
65
|
|
|
* @param array $options |
|
66
|
|
|
*/ |
|
67
|
|
|
public function __construct(StorageInterface $storage, array $options = array()) { |
|
68
|
|
|
$this->storage = $storage; |
|
69
|
|
|
$this->enabled = (isset($options['enabled']) ? $options['enabled'] : true); |
|
70
|
|
|
$this->encryptKeys = (isset($options['encrypt_keys']) ? $options['encrypt_keys'] : true); |
|
71
|
|
|
$this->info = new Info(); |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
/** |
|
75
|
|
|
* Initialise (lazy) |
|
76
|
|
|
*/ |
|
77
|
|
|
public function init() { |
|
78
|
|
|
if ($this->initialised > -1) { |
|
79
|
|
|
return true; |
|
80
|
|
|
} |
|
81
|
|
|
|
|
82
|
|
|
// Initialising in progress |
|
83
|
|
|
$this->initialised = 0; |
|
84
|
|
|
$this->storage->init(); |
|
85
|
|
|
|
|
86
|
|
|
if ($this->has($this->infoKey)) { |
|
87
|
|
|
$info = (array) $this->getOrStore($this->infoKey, array()); |
|
88
|
|
|
array_walk($info, array($this, 'handleExpiration')); |
|
89
|
|
|
$this->info->setData($info); |
|
90
|
|
|
} |
|
91
|
|
|
$this->initialised = 1; |
|
92
|
|
|
return true; |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
/** |
|
96
|
|
|
* Handles cached value expiration |
|
97
|
|
|
* |
|
98
|
|
|
* @param array $data |
|
99
|
|
|
* @param string $key |
|
100
|
|
|
* |
|
101
|
|
|
* @return boolean |
|
102
|
|
|
*/ |
|
103
|
|
|
protected function handleExpiration($data, $key) { |
|
104
|
|
|
if (!isset($data['expiry']) || $data['expiry'] == 0) { |
|
105
|
|
|
return true; |
|
106
|
|
|
} elseif (!$this->has($key)) { |
|
107
|
|
|
unset($this->info[$key]); |
|
108
|
|
|
} elseif (time() > $data['expiry']) { |
|
109
|
|
|
$this->delete($key); |
|
110
|
|
|
} |
|
111
|
|
|
} |
|
112
|
|
|
|
|
113
|
|
|
/** |
|
114
|
|
|
* Gets Cache info |
|
115
|
|
|
* |
|
116
|
|
|
* @param $name Cache key |
|
117
|
|
|
* |
|
118
|
|
|
* @return array |
|
119
|
|
|
*/ |
|
120
|
|
|
public function getInfo($name = '') { |
|
121
|
|
|
if (!$this->isEnabled()) { |
|
122
|
|
|
return false; |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
$this->init(); |
|
126
|
|
|
return $this->info->getData($name); |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* Check if Cache is enabled |
|
131
|
|
|
* |
|
132
|
|
|
* @return bool |
|
133
|
|
|
*/ |
|
134
|
|
|
public function isEnabled() { |
|
135
|
|
|
return $this->enabled; |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* Enable/disable caching |
|
140
|
|
|
* |
|
141
|
|
|
* @param bool $enabled |
|
142
|
|
|
*/ |
|
143
|
|
|
public function setEnabled($enabled) { |
|
144
|
|
|
$this->enabled = (bool) $enabled; |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
/** |
|
148
|
|
|
* Checks if the specified name in cache exists |
|
149
|
|
|
* |
|
150
|
|
|
* @param string $name cache name |
|
151
|
|
|
* |
|
152
|
|
|
* @return bool |
|
153
|
|
|
*/ |
|
154
|
|
|
public function has($name) { |
|
155
|
|
|
if (!$this->isEnabled()) { |
|
156
|
|
|
return false; |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
$this->init(); |
|
160
|
|
|
$secret = $this->encryptKey($name); |
|
161
|
|
|
return ($this->storage->has($secret) && ($name == $this->infoKey || isset($this->info[$name]))); |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* Deletes the specified cache or each one if '' given |
|
166
|
|
|
* |
|
167
|
|
|
* @param string $name cache name |
|
168
|
|
|
* |
|
169
|
|
|
* @return bool |
|
170
|
|
|
*/ |
|
171
|
|
|
public function delete($name = '') { |
|
172
|
|
|
if (!$this->isEnabled()) { |
|
173
|
|
|
return false; |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
$this->init(); |
|
177
|
|
|
$secret = ($name != '' ? $this->encryptKey($name) : $name); |
|
178
|
|
|
$ret = $this->storage->delete($secret); |
|
179
|
|
|
|
|
180
|
|
|
if ($name == '') { |
|
181
|
|
|
$this->info = new Info(); |
|
182
|
|
|
} elseif (isset($this->info[$name])) { |
|
183
|
|
|
unset($this->info[$name]); |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
return $ret; |
|
187
|
|
|
} |
|
188
|
|
|
|
|
189
|
|
|
/** |
|
190
|
|
|
* Flush all from cache |
|
191
|
|
|
* |
|
192
|
|
|
* @return bool |
|
193
|
|
|
*/ |
|
194
|
|
|
public function flush() { |
|
195
|
|
|
return $this->delete(); |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
/** |
|
199
|
|
|
* Stores the variable to the $name cache |
|
200
|
|
|
* |
|
201
|
|
|
* @param string $name cache name |
|
202
|
|
|
* @param mixed $val variable to be stored |
|
203
|
|
|
* @param bool $compressed Compressed storage |
|
204
|
|
|
* @param int|string $expiry Expires in the given seconds (0:never) or the time defined by valid date string (eg. '2014-10-01' or '1week' or '2hours') |
|
205
|
|
|
* @param string $storeMethod Storing method (serialize|json) |
|
206
|
|
|
* |
|
207
|
|
|
* @return bool |
|
208
|
|
|
*/ |
|
209
|
|
|
public function store($name, $val, $compressed = false, $expiry = 0, $storeMethod = self::STORE_METHOD_SERIALIZE) { |
|
210
|
|
|
if (!$this->isEnabled()) { |
|
211
|
|
|
return false; |
|
212
|
|
|
} |
|
213
|
|
|
|
|
214
|
|
|
$this->init(); |
|
215
|
|
|
$secret = $this->encryptKey($name); |
|
216
|
|
|
$data = $this->encode($val, $storeMethod); |
|
217
|
|
|
if (false !== $ret = $this->storage->store($secret, $data, $compressed)) { |
|
218
|
|
|
$expiry = ($expiry == 'never' ? 0 : $this->extractExpiryDate($expiry)); |
|
219
|
|
|
|
|
220
|
|
|
if (!isset($this->info[$name])) { |
|
221
|
|
|
$this->info->createData($name); |
|
222
|
|
|
} |
|
223
|
|
|
|
|
224
|
|
|
$this->info->touchItem($name, array('last_access', 'last_write')); |
|
225
|
|
|
$this->info->appendData($name, array( |
|
226
|
|
|
'expiry' => $expiry, |
|
227
|
|
|
'size' => strlen($data), |
|
228
|
|
|
'compressed' => $compressed, |
|
229
|
|
|
'store_method' => $storeMethod, |
|
230
|
|
|
)); |
|
231
|
|
|
$this->info->increaseItem($name, 'write_count'); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
return $ret; |
|
235
|
|
|
} |
|
236
|
|
|
|
|
237
|
|
|
/** |
|
238
|
|
|
* Extracts expiry by string |
|
239
|
|
|
* |
|
240
|
|
|
* @param mixed $expiry |
|
241
|
|
|
* |
|
242
|
|
|
* @return int |
|
243
|
|
|
*/ |
|
244
|
|
|
protected function extractExpiryDate($expiry) { |
|
245
|
|
|
if (is_string($expiry)) { |
|
246
|
|
|
if (strtotime($expiry) === false) { |
|
247
|
|
|
throw new \InvalidArgumentException('Invalid date format!'); |
|
248
|
|
|
} |
|
249
|
|
|
$date = new \DateTime($expiry); |
|
250
|
|
|
$expiry = $date->format('U') < time() ? 0 : $date->format('U'); |
|
251
|
|
|
} elseif ((int) $expiry > 0) { |
|
252
|
|
|
$expiry = ($expiry < time() ? time() + $expiry : $expiry); |
|
253
|
|
|
} else { |
|
254
|
|
|
$expiry = 0; |
|
255
|
|
|
} |
|
256
|
|
|
|
|
257
|
|
|
return $expiry; |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
/** |
|
261
|
|
|
* Retrieves the content of $name cache |
|
262
|
|
|
* |
|
263
|
|
|
* @param string $name cache name |
|
264
|
|
|
* @param mixed $default |
|
265
|
|
|
* |
|
266
|
|
|
* @return mixed |
|
267
|
|
|
*/ |
|
268
|
|
|
public function get($name, $default = null) { |
|
269
|
|
|
if (!$this->isEnabled() || ($this->init() && $name != $this->infoKey && !isset($this->info[$name]))) { |
|
270
|
|
|
$this->storage->miss(); |
|
271
|
|
|
return $this->processDefault($default); |
|
272
|
|
|
} |
|
273
|
|
|
|
|
274
|
|
|
list($compressed, $storeMethod) = $this->extractParameters($name); |
|
275
|
|
|
$secret = $this->encryptKey($name); |
|
276
|
|
|
$raw = $this->storage->get($secret, $compressed); |
|
|
|
|
|
|
277
|
|
|
$ret = $this->decode($raw, $storeMethod); |
|
278
|
|
|
|
|
279
|
|
|
if ($ret !== null) { |
|
280
|
|
|
$this->info->touchItem($name, array('last_access', 'last_read')); |
|
281
|
|
|
$this->info->increaseItem($name, 'read_count'); |
|
282
|
|
|
$this->readKeys[] = $name; |
|
283
|
|
|
array_unique($this->readKeys); |
|
284
|
|
|
} else { |
|
285
|
|
|
$this->info->deleteData($name); |
|
286
|
|
|
} |
|
287
|
|
|
|
|
288
|
|
|
return $ret; |
|
289
|
|
|
} |
|
290
|
|
|
|
|
291
|
|
|
/** |
|
292
|
|
|
* Extract cached value parameters |
|
293
|
|
|
* |
|
294
|
|
|
* @param string $name |
|
295
|
|
|
* |
|
296
|
|
|
* @return array |
|
297
|
|
|
*/ |
|
298
|
|
|
protected function extractParameters($name) { |
|
299
|
|
|
$compressed = ($name == $this->infoKey ? true : $this->info->getItem($name, 'compressed')); |
|
300
|
|
|
$storeMethod = ($name == $this->infoKey ? self::STORE_METHOD_JSON : $this->info->getItem($name, 'store_method')); |
|
301
|
|
|
return array($compressed, $storeMethod); |
|
302
|
|
|
} |
|
303
|
|
|
|
|
304
|
|
|
/** |
|
305
|
|
|
* Attempts to get a value and if not exists store the given default variable |
|
306
|
|
|
* |
|
307
|
|
|
* @param string $name cache name |
|
308
|
|
|
* @param mixed $default default value |
|
309
|
|
|
* @param bool $compressed Compressed storage |
|
310
|
|
|
* @param int|string $expiry Expires in the given seconds (0:never) or the time defined by valid date string (eg. '2014-10-01' or '1week' or '2hours') |
|
311
|
|
|
* @param int $storeMethod Storing method (serialize|json) |
|
312
|
|
|
* |
|
313
|
|
|
* @return mixed |
|
314
|
|
|
*/ |
|
315
|
|
|
public function getOrStore($name, $default, $compressed = false, $expiry = 0, $storeMethod = self::STORE_METHOD_SERIALIZE) { |
|
316
|
|
|
if ($this->has($name)) { |
|
317
|
|
|
return $this->get($name); |
|
318
|
|
|
} |
|
319
|
|
|
$value = $this->processDefault($default); |
|
320
|
|
|
$this->store($name, $value, $compressed, $expiry, $storeMethod); |
|
321
|
|
|
return $value; |
|
322
|
|
|
} |
|
323
|
|
|
|
|
324
|
|
|
/** |
|
325
|
|
|
* Retrieves and deletes value from cache |
|
326
|
|
|
* |
|
327
|
|
|
* @param string $name |
|
328
|
|
|
* |
|
329
|
|
|
* @return mixed |
|
330
|
|
|
*/ |
|
331
|
|
|
public function pull($name) { |
|
332
|
|
|
$ret = $this->get($name); |
|
333
|
|
|
$this->delete($name); |
|
334
|
|
|
return $ret; |
|
335
|
|
|
} |
|
336
|
|
|
|
|
337
|
|
|
/** |
|
338
|
|
|
* Retrieves information of Cache state |
|
339
|
|
|
* |
|
340
|
|
|
* @param bool $getFields |
|
341
|
|
|
* |
|
342
|
|
|
* @return array|bool |
|
343
|
|
|
*/ |
|
344
|
|
|
public function info($getFields = false) { |
|
345
|
|
|
if (!$this->isEnabled()) { |
|
346
|
|
|
return false; |
|
347
|
|
|
} |
|
348
|
|
|
$this->init(); |
|
349
|
|
|
return $this->storage->info($getFields); |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
/** |
|
353
|
|
|
* Encodes variable with the specified method |
|
354
|
|
|
* |
|
355
|
|
|
* @param mixed $var Variable |
|
356
|
|
|
* @param int $storeMethod serialize|json |
|
357
|
|
|
* |
|
358
|
|
|
* @return mixed |
|
359
|
|
|
*/ |
|
360
|
|
|
protected function encode($var, $storeMethod = self::STORE_METHOD_SERIALIZE) { |
|
361
|
|
|
switch ($storeMethod) { |
|
362
|
|
|
case self::STORE_METHOD_JSON: |
|
363
|
|
|
$var = json_encode($var); |
|
364
|
|
|
break; |
|
365
|
|
|
case self::STORE_METHOD_SERIALIZE: |
|
366
|
|
|
default: |
|
367
|
|
|
$var = serialize($var); |
|
368
|
|
|
} |
|
369
|
|
|
return $var; |
|
370
|
|
|
} |
|
371
|
|
|
|
|
372
|
|
|
/** |
|
373
|
|
|
* Decodes variable with the specified method |
|
374
|
|
|
* |
|
375
|
|
|
* @param mixed $var Variable |
|
376
|
|
|
* @param int $storeMethod serialize|json |
|
377
|
|
|
* |
|
378
|
|
|
* @return mixed |
|
379
|
|
|
*/ |
|
380
|
|
|
protected function decode($var, $storeMethod = self::STORE_METHOD_SERIALIZE) { |
|
381
|
|
|
if (!$var) { |
|
382
|
|
|
return null; |
|
383
|
|
|
} |
|
384
|
|
|
|
|
385
|
|
|
switch ($storeMethod) { |
|
386
|
|
|
case self::STORE_METHOD_JSON: |
|
387
|
|
|
$var = json_decode($var, true); |
|
388
|
|
|
break; |
|
389
|
|
|
case self::STORE_METHOD_SERIALIZE: |
|
390
|
|
|
default: |
|
391
|
|
|
$var = unserialize($var); |
|
392
|
|
|
} |
|
393
|
|
|
|
|
394
|
|
|
return $var; |
|
395
|
|
|
} |
|
396
|
|
|
|
|
397
|
|
|
/** |
|
398
|
|
|
* Encrypts key |
|
399
|
|
|
* |
|
400
|
|
|
* @param string $key |
|
401
|
|
|
* |
|
402
|
|
|
* @return string |
|
403
|
|
|
*/ |
|
404
|
|
|
protected function encryptKey($key) { |
|
405
|
|
|
return ($this->encryptKeys ? sha1($key) : $key); |
|
406
|
|
|
} |
|
407
|
|
|
|
|
408
|
|
|
/** |
|
409
|
|
|
* Gets cache hits |
|
410
|
|
|
* |
|
411
|
|
|
* @return int |
|
412
|
|
|
*/ |
|
413
|
|
|
public function getHits() { |
|
414
|
|
|
if (!$this->isEnabled()) { |
|
415
|
|
|
return 0; |
|
416
|
|
|
} |
|
417
|
|
|
$this->init(); |
|
418
|
|
|
return $this->storage->getHits(); |
|
419
|
|
|
} |
|
420
|
|
|
|
|
421
|
|
|
/** |
|
422
|
|
|
* Gets cache misses |
|
423
|
|
|
* |
|
424
|
|
|
* @return int |
|
425
|
|
|
*/ |
|
426
|
|
|
public function getMisses() { |
|
427
|
|
|
if (!$this->isEnabled()) { |
|
428
|
|
|
return 0; |
|
429
|
|
|
} |
|
430
|
|
|
$this->init(); |
|
431
|
|
|
return $this->storage->getMisses(); |
|
432
|
|
|
} |
|
433
|
|
|
|
|
434
|
|
|
/** |
|
435
|
|
|
* Stores cache values expiral information into cache |
|
436
|
|
|
*/ |
|
437
|
|
|
public function writeExpirals() { |
|
438
|
|
|
if (!$this->isEnabled() || $this->initialised < 1) { |
|
439
|
|
|
return false; |
|
440
|
|
|
} |
|
441
|
|
|
return $this->store($this->infoKey, $this->info->getData(), true, 0, self::STORE_METHOD_JSON); |
|
442
|
|
|
} |
|
443
|
|
|
|
|
444
|
|
|
/** |
|
445
|
|
|
* Gets expiry information of a cached value (0: never) |
|
446
|
|
|
* |
|
447
|
|
|
* @param string $name Cache name |
|
448
|
|
|
* @param string $format Date format |
|
449
|
|
|
* |
|
450
|
|
|
* @return string |
|
451
|
|
|
*/ |
|
452
|
|
|
public function getExpiry($name, $format = 'U') { |
|
453
|
|
|
if (!$this->isEnabled()) { |
|
454
|
|
|
return false; |
|
455
|
|
|
} |
|
456
|
|
|
$this->init(); |
|
457
|
|
|
return $this->info->getExpiry($name, $format); |
|
458
|
|
|
} |
|
459
|
|
|
|
|
460
|
|
|
/** |
|
461
|
|
|
* Calculates Time To Live |
|
462
|
|
|
* |
|
463
|
|
|
* @param string $name |
|
464
|
|
|
* |
|
465
|
|
|
* @return int |
|
466
|
|
|
*/ |
|
467
|
|
|
public function getTTL($name) { |
|
468
|
|
|
$expiry = $this->getExpiry($name); |
|
469
|
|
|
return ($expiry > 0 ? (int) $expiry - (int) $this->getCreated($name) : 0); |
|
470
|
|
|
} |
|
471
|
|
|
|
|
472
|
|
|
/** |
|
473
|
|
|
* Modifies expiry by setting Time To Live |
|
474
|
|
|
* |
|
475
|
|
|
* @param string $name |
|
476
|
|
|
* @param int $ttl |
|
477
|
|
|
*/ |
|
478
|
|
|
public function setTTL($name, $ttl) { |
|
479
|
|
|
if ($this->canModify($name)) { |
|
480
|
|
|
$created = (int) $this->getCreated($name); |
|
481
|
|
|
$ttl = (int) $ttl; |
|
482
|
|
|
$this->info->setItem($name, 'expiry', ($ttl <= 0 ? 0 : $created + $ttl)); |
|
483
|
|
|
} |
|
484
|
|
|
} |
|
485
|
|
|
|
|
486
|
|
|
/** |
|
487
|
|
|
* Modifies expiry |
|
488
|
|
|
* |
|
489
|
|
|
* @param string $name |
|
490
|
|
|
* @param mixed $expiry |
|
491
|
|
|
*/ |
|
492
|
|
|
public function setExpiry($name, $expiry) { |
|
493
|
|
|
if ($this->canModify($name)) { |
|
494
|
|
|
$this->info->setItem($name, 'expiry', $this->extractExpiryDate($expiry)); |
|
495
|
|
|
} |
|
496
|
|
|
} |
|
497
|
|
|
|
|
498
|
|
|
/** |
|
499
|
|
|
* Gets created (first write) time of a cached value |
|
500
|
|
|
* |
|
501
|
|
|
* @param string $name Cache name |
|
502
|
|
|
* @param string $format Date format |
|
503
|
|
|
* |
|
504
|
|
|
* @return string |
|
505
|
|
|
*/ |
|
506
|
|
|
public function getCreated($name, $format = 'U') { |
|
507
|
|
|
return $this->info->getItem($name, 'created', 'date', $format); |
|
508
|
|
|
} |
|
509
|
|
|
|
|
510
|
|
|
/** |
|
511
|
|
|
* Gets last access (either read or write) time of a cached value |
|
512
|
|
|
* |
|
513
|
|
|
* @param string $name Cache name |
|
514
|
|
|
* @param string $format Date format |
|
515
|
|
|
* |
|
516
|
|
|
* @return string |
|
517
|
|
|
*/ |
|
518
|
|
|
public function getLastAccess($name, $format = 'U') { |
|
519
|
|
|
return $this->info->getItem($name, 'last_access', 'date', $format); |
|
520
|
|
|
} |
|
521
|
|
|
|
|
522
|
|
|
/** |
|
523
|
|
|
* Gets last read time of a cached value |
|
524
|
|
|
* |
|
525
|
|
|
* @param string $name Cache name |
|
526
|
|
|
* @param string $format Date format |
|
527
|
|
|
* |
|
528
|
|
|
* @return string |
|
529
|
|
|
*/ |
|
530
|
|
|
public function getLastRead($name, $format = 'U') { |
|
531
|
|
|
return $this->info->getItem($name, 'last_read', 'date', $format); |
|
532
|
|
|
} |
|
533
|
|
|
|
|
534
|
|
|
/** |
|
535
|
|
|
* Gets last write time of a cached value |
|
536
|
|
|
* |
|
537
|
|
|
* @param string $name Cache name |
|
538
|
|
|
* @param string $format Date format |
|
539
|
|
|
* |
|
540
|
|
|
* @return string |
|
541
|
|
|
*/ |
|
542
|
|
|
public function getLastWrite($name, $format = 'U') { |
|
543
|
|
|
return $this->info->getItem($name, 'last_write', 'date', $format); |
|
544
|
|
|
} |
|
545
|
|
|
|
|
546
|
|
|
/** |
|
547
|
|
|
* Gets read count of a cached value |
|
548
|
|
|
* |
|
549
|
|
|
* @param string $name Cache name |
|
550
|
|
|
* |
|
551
|
|
|
* @return int |
|
552
|
|
|
*/ |
|
553
|
|
|
public function getReadCount($name) { |
|
554
|
|
|
return $this->info->getItem($name, 'read_count', 'int'); |
|
555
|
|
|
} |
|
556
|
|
|
|
|
557
|
|
|
/** |
|
558
|
|
|
* Gets write count of a cached value |
|
559
|
|
|
* |
|
560
|
|
|
* @param string $name Cache name |
|
561
|
|
|
* |
|
562
|
|
|
* @return int |
|
563
|
|
|
*/ |
|
564
|
|
|
public function getWriteCount($name) { |
|
565
|
|
|
return $this->info->getItem($name, 'write_count', 'int'); |
|
566
|
|
|
} |
|
567
|
|
|
|
|
568
|
|
|
/** |
|
569
|
|
|
* Gets all cache key names |
|
570
|
|
|
* |
|
571
|
|
|
* @return array |
|
572
|
|
|
*/ |
|
573
|
|
|
public function getKeys() { |
|
574
|
|
|
if (!$this->isEnabled()) { |
|
575
|
|
|
return false; |
|
576
|
|
|
} |
|
577
|
|
|
$this->init(); |
|
578
|
|
|
return $this->info->getKeys(); |
|
579
|
|
|
} |
|
580
|
|
|
|
|
581
|
|
|
/** |
|
582
|
|
|
* Gets cache key names which already read |
|
583
|
|
|
* |
|
584
|
|
|
* @return array |
|
585
|
|
|
*/ |
|
586
|
|
|
public function getReadKeys() { |
|
587
|
|
|
return $this->readKeys; |
|
588
|
|
|
} |
|
589
|
|
|
|
|
590
|
|
|
/** |
|
591
|
|
|
* Gets storage object |
|
592
|
|
|
* |
|
593
|
|
|
* @return StorageInterface |
|
594
|
|
|
*/ |
|
595
|
|
|
public function getStorage() { |
|
596
|
|
|
return $this->storage; |
|
597
|
|
|
} |
|
598
|
|
|
|
|
599
|
|
|
/** |
|
600
|
|
|
* Retrieves key encryption |
|
601
|
|
|
* |
|
602
|
|
|
* @return bool |
|
603
|
|
|
*/ |
|
604
|
|
|
public function getEncryptKeys() { |
|
605
|
|
|
return $this->encryptKeys; |
|
606
|
|
|
} |
|
607
|
|
|
|
|
608
|
|
|
/** |
|
609
|
|
|
* Sets key encryption |
|
610
|
|
|
* |
|
611
|
|
|
* @param bool $encryptKeys |
|
612
|
|
|
*/ |
|
613
|
|
|
public function setEncryptKeys($encryptKeys) { |
|
614
|
|
|
$this->encryptKeys = (bool) $encryptKeys; |
|
615
|
|
|
} |
|
616
|
|
|
|
|
617
|
|
|
/** |
|
618
|
|
|
* Sets cache storage |
|
619
|
|
|
* |
|
620
|
|
|
* @param StorageInterface $storage |
|
621
|
|
|
*/ |
|
622
|
|
|
public function setStorage(StorageInterface $storage) { |
|
623
|
|
|
$this->storage = $storage; |
|
624
|
|
|
} |
|
625
|
|
|
|
|
626
|
|
|
/** |
|
627
|
|
|
* Destructor |
|
628
|
|
|
*/ |
|
629
|
|
|
public function __destruct() { |
|
630
|
|
|
$this->writeExpirals(); |
|
631
|
|
|
} |
|
632
|
|
|
|
|
633
|
|
|
/** |
|
634
|
|
|
* Sets a tagged cache value |
|
635
|
|
|
* |
|
636
|
|
|
* @param string $name cache name |
|
637
|
|
|
* @param mixed $val variable to be stored |
|
638
|
|
|
* @param array $tags tags |
|
639
|
|
|
* @param bool $compressed Compressed storage |
|
640
|
|
|
* @param int|string $expiry Expires in the given seconds (0:never) or the time defined by valid date string (eg. '2014-10-01' or '1week' or '2hours') |
|
641
|
|
|
* @param int $storeMethod Storing method (serialize|json) |
|
642
|
|
|
* |
|
643
|
|
|
* @return bool |
|
644
|
|
|
*/ |
|
645
|
|
|
public function storeTagged($name, $val, $tags, $compressed = false, $expiry = 0, $storeMethod = self::STORE_METHOD_SERIALIZE) { |
|
646
|
|
|
if ($this->store($name, $val, $compressed, $expiry, $storeMethod)) { |
|
647
|
|
|
$this->prepareTags($tags); |
|
648
|
|
|
$this->info->setItem($name, 'tags', $tags); |
|
649
|
|
|
return true; |
|
650
|
|
|
} |
|
651
|
|
|
} |
|
652
|
|
|
|
|
653
|
|
|
/** |
|
654
|
|
|
* Gets tagged cache values |
|
655
|
|
|
* |
|
656
|
|
|
* @param array $tags |
|
657
|
|
|
* |
|
658
|
|
|
* @return array |
|
659
|
|
|
*/ |
|
660
|
|
|
public function getTagged($tags) { |
|
661
|
|
|
if (!$this->isEnabled()) { |
|
662
|
|
|
return false; |
|
663
|
|
|
} |
|
664
|
|
|
|
|
665
|
|
|
$this->init(); |
|
666
|
|
|
$this->prepareTags($tags); |
|
667
|
|
|
$filtered = (array) $this->info->filterByTags($tags); |
|
668
|
|
|
$ret = array(); |
|
669
|
|
|
foreach ($filtered as $key) { |
|
670
|
|
|
$ret[$key] = $this->get($key); |
|
671
|
|
|
} |
|
672
|
|
|
return $ret; |
|
673
|
|
|
} |
|
674
|
|
|
|
|
675
|
|
|
/** |
|
676
|
|
|
* Gets tags of a cached variable |
|
677
|
|
|
* |
|
678
|
|
|
* @param string $key |
|
679
|
|
|
* |
|
680
|
|
|
* @return array |
|
681
|
|
|
*/ |
|
682
|
|
|
public function getTags($key) { |
|
683
|
|
|
if (!$this->isEnabled()) { |
|
684
|
|
|
return false; |
|
685
|
|
|
} |
|
686
|
|
|
|
|
687
|
|
|
$this->init(); |
|
688
|
|
|
$ret = $this->info->getItem($key, 'tags', 'array'); |
|
689
|
|
|
sort($ret); |
|
690
|
|
|
return $ret; |
|
691
|
|
|
} |
|
692
|
|
|
|
|
693
|
|
|
/** |
|
694
|
|
|
* Sets tags of a cached variable |
|
695
|
|
|
* |
|
696
|
|
|
* @param string $name |
|
697
|
|
|
* @param array $tags |
|
698
|
|
|
* |
|
699
|
|
|
* @return array |
|
700
|
|
|
*/ |
|
701
|
|
|
public function setTags($name, $tags) { |
|
702
|
|
|
if ($this->canModify($name)) { |
|
703
|
|
|
$this->prepareTags($tags); |
|
704
|
|
|
return $this->info->setItem($name, 'tags', $tags); |
|
705
|
|
|
} |
|
706
|
|
|
return false; |
|
707
|
|
|
} |
|
708
|
|
|
|
|
709
|
|
|
/** |
|
710
|
|
|
* Adds tags for a cached variable |
|
711
|
|
|
* |
|
712
|
|
|
* @param string $name |
|
713
|
|
|
* @param array $tags |
|
714
|
|
|
* |
|
715
|
|
|
* @return array |
|
716
|
|
|
*/ |
|
717
|
|
|
public function addTags($name, $tags) { |
|
718
|
|
|
if ($this->canModify($name)) { |
|
719
|
|
|
$this->prepareTags($tags); |
|
720
|
|
|
$tags = array_unique(array_merge($this->getTags($name), $tags)); |
|
721
|
|
|
return $this->setTags($name, $tags); |
|
722
|
|
|
} |
|
723
|
|
|
return false; |
|
724
|
|
|
} |
|
725
|
|
|
|
|
726
|
|
|
/** |
|
727
|
|
|
* Deletes cache values matching the given tags |
|
728
|
|
|
* |
|
729
|
|
|
* @param array $tags |
|
730
|
|
|
* |
|
731
|
|
|
* @return array |
|
732
|
|
|
*/ |
|
733
|
|
|
public function deleteTagged($tags) { |
|
734
|
|
|
if (!$this->isEnabled()) { |
|
735
|
|
|
return false; |
|
736
|
|
|
} |
|
737
|
|
|
|
|
738
|
|
|
$this->init(); |
|
739
|
|
|
$this->prepareTags($tags); |
|
740
|
|
|
$filtered = (array) $this->info->filterByTags($tags); |
|
741
|
|
|
return array_map(array($this, 'delete'), $filtered); |
|
742
|
|
|
} |
|
743
|
|
|
|
|
744
|
|
|
/** |
|
745
|
|
|
* Gets all tags currently in use |
|
746
|
|
|
* |
|
747
|
|
|
* @return array |
|
748
|
|
|
*/ |
|
749
|
|
|
public function getAllTags() { |
|
750
|
|
|
if (!$this->isEnabled()) { |
|
751
|
|
|
return false; |
|
752
|
|
|
} |
|
753
|
|
|
|
|
754
|
|
|
$this->init(); |
|
755
|
|
|
$tags = array(); |
|
756
|
|
|
foreach ($this->info as $info) { |
|
757
|
|
|
$tags = array_unique(array_merge($tags, $info['tags'])); |
|
758
|
|
|
} |
|
759
|
|
|
sort($tags); |
|
760
|
|
|
return $tags; |
|
761
|
|
|
} |
|
762
|
|
|
|
|
763
|
|
|
/** |
|
764
|
|
|
* Prepares tags parameter |
|
765
|
|
|
* |
|
766
|
|
|
* @param array|string $tags |
|
767
|
|
|
*/ |
|
768
|
|
|
protected function prepareTags(&$tags) { |
|
769
|
|
|
if (!is_array($tags)) { |
|
770
|
|
|
$tags = array($tags); |
|
771
|
|
|
} |
|
772
|
|
|
$tags = array_unique($tags); |
|
773
|
|
|
} |
|
774
|
|
|
|
|
775
|
|
|
/** |
|
776
|
|
|
* Checks if cache value info can be modified (cache is enabled and value exists) |
|
777
|
|
|
* |
|
778
|
|
|
* @param string $name |
|
779
|
|
|
* |
|
780
|
|
|
* @return boolean |
|
781
|
|
|
*/ |
|
782
|
|
|
protected function canModify($name) { |
|
783
|
|
|
if (!$this->isEnabled()) { |
|
784
|
|
|
return false; |
|
785
|
|
|
} |
|
786
|
|
|
$this->init(); |
|
787
|
|
|
return $this->has($name); |
|
788
|
|
|
} |
|
789
|
|
|
|
|
790
|
|
|
/** |
|
791
|
|
|
* Processes default value |
|
792
|
|
|
* |
|
793
|
|
|
* @param \Closure|mixed $default |
|
794
|
|
|
* |
|
795
|
|
|
* @return mixed |
|
796
|
|
|
*/ |
|
797
|
|
|
protected function processDefault($default) { |
|
798
|
|
|
return ($default instanceof \Closure ? call_user_func($default) : $default); |
|
799
|
|
|
} |
|
800
|
|
|
|
|
801
|
|
|
} |
|
802
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.