Cache.php 18 KB

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