/
Cache.php
426 lines (388 loc) · 12 KB
/
Cache.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 1.2.0.4933
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Cache;
use Cake\Core\App;
use Cake\Core\Configure;
use Cake\Core\StaticConfigTrait;
use Cake\Error;
use Cake\Utility\Inflector;
/**
* Cache provides a consistent interface to Caching in your application. It allows you
* to use several different Cache engines, without coupling your application to a specific
* implementation. It also allows you to change out cache storage or configuration without effecting
* the rest of your application.
*
* ### Configuring Cache engines
*
* You can configure Cache engines in your application's `Config/cache.php` file.
* A sample configuration would be:
*
* {{{
* Cache::config('shared', [
* 'engine' => 'Cake\Cache\Engine\ApcEngine',
* 'prefix' => 'my_app_'
* ]);
* }}}
*
* This would configure an APC cache engine to the 'shared' alias. You could then read and write
* to that cache alias by using it for the `$config` parameter in the various Cache methods.
*
* In general all Cache operations are supported by all cache engines.
* However, Cache::increment() and Cache::decrement() are not supported by File caching.
*
* There are 5 built-in caching engines:
*
* - `FileEngine` - Uses simple files to store content. Poor performance, but good for
* storing large objects, or things that are not IO sensitive. Well suited to development
* as it is an easy cache to inspect and manually flush.
* - `ApcEngine` - Uses the APC object cache, one of the fastest caching engines.
* - `MemcacheEngine` - Uses the PECL::Memcache extension and Memcached for storage.
* Fast reads/writes, and benefits from memcache being distributed.
* - `XcacheEngine` - Uses the Xcache extension, an alternative to APC.
* - `WincacheEngine` - Uses Windows Cache Extension for PHP. Supports wincache 1.1.0 and higher.
* This engine is recommended to people deploying on windows with IIS.
* - `RedisEngine` - Uses redis and php-redis extension to store cache data.
*
* See Cache engine documentation for expected configuration keys.
*
* @see app/Config/core.php for configuration settings
* @param string $name Name of the configuration
* @param array $config Optional associative array of settings passed to the engine
* @return array [engine, settings] on success, false on failure
* @throws Cake\Error\Exception
*/
class Cache {
use StaticConfigTrait;
/**
* Flag for tracking whether or not caching is enabled.
*
* @var boolean
*/
protected static $_enabled = true;
/**
* Cache configuration.
*
* Keeps the permanent/default settings for each cache engine.
* These settings are used to reset the engines after temporary modification.
*
* @var array
*/
protected static $_config = [];
/**
* Group to Config mapping
*
* @var array
*/
protected static $_groups = [];
/**
* Whether to reset the settings with the next call to Cache::set();
*
* @var array
*/
protected static $_reset = false;
/**
* Cache Registry used for creating and using cache adapters.
*
* @var Cake\Cache\CacheRegistry
*/
protected static $_registry;
/**
* Finds and builds the instance of the required engine class.
*
* @param string $name Name of the config array that needs an engine instance built
* @throws Cake\Error\Exception When a cache engine cannot be created.
*/
protected static function _buildEngine($name) {
if (empty(static::$_registry)) {
static::$_registry = new CacheRegistry();
}
if (empty(static::$_config[$name]['className'])) {
throw new Error\Exception(sprintf('The "%s" cache configuration does not exist.', $name));
}
$config = static::$_config[$name];
static::$_registry->load($name, $config);
if (!empty($config['groups'])) {
foreach ($config['groups'] as $group) {
static::$_groups[$group][] = $name;
static::$_groups[$group] = array_unique(static::$_groups[$group]);
sort(static::$_groups[$group]);
}
}
}
/**
* Fetch the engine attached to a specific configuration name.
*
* If the cache engine & configuration are missing an error will be
* triggered.
*
* @param string $config The configuration name you want an engine for.
* @return Cake\Cache\Engine
*/
public static function engine($config) {
if (!static::$_enabled) {
return false;
}
if (isset(static::$_registry->{$config})) {
return static::$_registry->{$config};
}
static::_buildEngine($config);
return static::$_registry->{$config};
}
/**
* Garbage collection
*
* Permanently remove all expired and deleted data
*
* @param string $config [optional] The config name you wish to have garbage collected. Defaults to 'default'
* @param integer $expires [optional] An expires timestamp. Defaults to NULL
* @return void
*/
public static function gc($config = 'default', $expires = null) {
$engine = static::engine($config);
if (!$engine) {
return;
}
$engine->gc($expires);
}
/**
* Write data for key into cache.
*
* ### Usage:
*
* Writing to the active cache config:
*
* `Cache::write('cached_data', $data);`
*
* Writing to a specific cache config:
*
* `Cache::write('cached_data', $data, 'long_term');`
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached - anything except a resource
* @param string $config Optional string configuration name to write to. Defaults to 'default'
* @return boolean True if the data was successfully cached, false on failure
*/
public static function write($key, $value, $config = 'default') {
$engine = static::engine($config);
if (!$engine || is_resource($value)) {
return false;
}
$success = $engine->write($key, $value);
if ($success === false && $value !== '') {
trigger_error(
sprintf(
"%s cache was unable to write '%s' to %s cache",
$config,
$key,
get_class($engine)
),
E_USER_WARNING
);
}
return $success;
}
/**
* Read a key from the cache.
*
* ### Usage:
*
* Reading from the active cache configuration.
*
* `Cache::read('my_data');`
*
* Reading from a specific cache configuration.
*
* `Cache::read('my_data', 'long_term');`
*
* @param string $key Identifier for the data
* @param string $config optional name of the configuration to use. Defaults to 'default'
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public static function read($key, $config = 'default') {
$engine = static::engine($config);
if (!$engine) {
return false;
}
return $engine->read($key);
}
/**
* Increment a number under the key and return incremented value.
*
* @param string $key Identifier for the data
* @param integer $offset How much to add
* @param string $config Optional string configuration name. Defaults to 'default'
* @return mixed new value, or false if the data doesn't exist, is not integer,
* or if there was an error fetching it.
*/
public static function increment($key, $offset = 1, $config = 'default') {
$engine = static::engine($config);
if (!$engine || !is_int($offset) || $offset < 0) {
return false;
}
return $engine->increment($key, $offset);
}
/**
* Decrement a number under the key and return decremented value.
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @param string $config Optional string configuration name. Defaults to 'default'
* @return mixed new value, or false if the data doesn't exist, is not integer,
* or if there was an error fetching it
*/
public static function decrement($key, $offset = 1, $config = 'default') {
$engine = static::engine($config);
if (!$engine || !is_int($offset) || $offset < 0) {
return false;
}
return $engine->decrement($key, $offset);
}
/**
* Delete a key from the cache.
*
* ### Usage:
*
* Deleting from the active cache configuration.
*
* `Cache::delete('my_data');`
*
* Deleting from a specific cache configuration.
*
* `Cache::delete('my_data', 'long_term');`
*
* @param string $key Identifier for the data
* @param string $config name of the configuration to use. Defaults to 'default'
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public static function delete($key, $config = 'default') {
$engine = static::engine($config);
if (!$engine) {
return false;
}
return $engine->delete($key);
}
/**
* Delete all keys from the cache.
*
* @param boolean $check if true will check expiration, otherwise delete all
* @param string $config name of the configuration to use. Defaults to 'default'
* @return boolean True if the cache was successfully cleared, false otherwise
*/
public static function clear($check = false, $config = 'default') {
$engine = static::engine($config);
if (!$engine) {
return false;
}
return $engine->clear($check);
}
/**
* Delete all keys from the cache belonging to the same group.
*
* @param string $group name of the group to be cleared
* @param string $config name of the configuration to use. Defaults to 'default'
* @return boolean True if the cache group was successfully cleared, false otherwise
*/
public static function clearGroup($group, $config = 'default') {
$engine = static::engine($config);
if (!$engine) {
return false;
}
return $engine->clearGroup($group);
}
/**
* Retrieve group names to config mapping.
*
* {{{
* Cache::config('daily', ['duration' => '1 day', 'groups' => ['posts']]);
* Cache::config('weekly', ['duration' => '1 week', 'groups' => ['posts', 'archive']]);
* $configs = Cache::groupConfigs('posts');
* }}}
*
* $config will equal to `['posts' => ['daily', 'weekly']]`
*
* @param string $group group name or null to retrieve all group mappings
* @return array map of group and all configuration that has the same group
* @throws Cake\Error\Exception
*/
public static function groupConfigs($group = null) {
if ($group === null) {
return static::$_groups;
}
if (isset(self::$_groups[$group])) {
return [$group => self::$_groups[$group]];
}
throw new Error\Exception(sprintf('Invalid cache group %s', $group));
}
/**
* Re-enable caching.
*
* If caching has been disabled with Cache::disable() this method will reverse that effect.
*
* @return void
*/
public static function enable() {
static::$_enabled = true;
}
/**
* Disable caching.
*
* When disabled all cache operations will return null.
*
* @return void
*/
public static function disable() {
static::$_enabled = false;
}
/**
* Check whether or not caching is enabled.
*
* @return boolean
*/
public static function enabled() {
return static::$_enabled;
}
/**
* Provides the ability to easily do read-through caching.
*
* When called if the $key is not set in $config, the $callable function
* will be invoked. The results will then be stored into the cache config
* at key.
*
* Examples:
*
* Using a Closure to provide data, assume `$this` is a Table object:
*
* {{{
* $results = Cache::remember('all_articles', function() {
* return $this->find('all');
* });
* }}}
*
* @param string $key The cache key to read/store data at.
* @param callable $callable The callable that provides data in the case when
* the cache key is empty. Can be any callable type supported by your PHP.
* @param string $config The cache configuration to use for this operation.
* Defaults to default.
*/
public static function remember($key, $callable, $config = 'default') {
$existing = self::read($key, $config);
if ($existing !== false) {
return $existing;
}
$results = call_user_func($callable);
self::write($key, $results, $config);
return $results;
}
}