Cache.php 14 KB

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