Cache.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://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. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 1.2.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Cache;
  16. use Cake\Cache\Engine\NullEngine;
  17. use Cake\Core\ObjectRegistry;
  18. use Cake\Core\StaticConfigTrait;
  19. use InvalidArgumentException;
  20. use RuntimeException;
  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\ApcuEngine',
  35. * 'prefix' => 'my_app_'
  36. * ]);
  37. * ```
  38. *
  39. * This would configure an APCu 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 6 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. * - `ApcuEngine` - Uses the APCu 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 APCu.
  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 config/app.php for configuration settings
  61. */
  62. class Cache
  63. {
  64. use StaticConfigTrait;
  65. /**
  66. * An array mapping url schemes to fully qualified caching engine
  67. * class names.
  68. *
  69. * @var array
  70. */
  71. protected static $_dsnClassMap = [
  72. 'apc' => 'Cake\Cache\Engine\ApcuEngine', // @deprecated Since 3.6. Use apcu instead.
  73. 'apcu' => 'Cake\Cache\Engine\ApcuEngine',
  74. 'file' => 'Cake\Cache\Engine\FileEngine',
  75. 'memcached' => 'Cake\Cache\Engine\MemcachedEngine',
  76. 'null' => 'Cake\Cache\Engine\NullEngine',
  77. 'redis' => 'Cake\Cache\Engine\RedisEngine',
  78. 'wincache' => 'Cake\Cache\Engine\WincacheEngine',
  79. 'xcache' => 'Cake\Cache\Engine\XcacheEngine',
  80. ];
  81. /**
  82. * Flag for tracking whether or not caching is enabled.
  83. *
  84. * @var bool
  85. */
  86. protected static $_enabled = true;
  87. /**
  88. * Group to Config mapping
  89. *
  90. * @var array
  91. */
  92. protected static $_groups = [];
  93. /**
  94. * Cache Registry used for creating and using cache adapters.
  95. *
  96. * @var \Cake\Core\ObjectRegistry
  97. */
  98. protected static $_registry;
  99. /**
  100. * Returns the Cache Registry instance used for creating and using cache adapters.
  101. *
  102. * @return \Cake\Core\ObjectRegistry
  103. */
  104. public static function getRegistry()
  105. {
  106. if (!static::$_registry) {
  107. static::$_registry = new CacheRegistry();
  108. }
  109. return static::$_registry;
  110. }
  111. /**
  112. * Sets the Cache Registry instance used for creating and using cache adapters.
  113. *
  114. * Also allows for injecting of a new registry instance.
  115. *
  116. * @param \Cake\Core\ObjectRegistry $registry Injectable registry object.
  117. * @return void
  118. */
  119. public static function setRegistry(ObjectRegistry $registry)
  120. {
  121. static::$_registry = $registry;
  122. }
  123. /**
  124. * Returns the Cache Registry instance used for creating and using cache adapters.
  125. * Also allows for injecting of a new registry instance.
  126. *
  127. * @param \Cake\Core\ObjectRegistry|null $registry Injectable registry object.
  128. * @return \Cake\Core\ObjectRegistry
  129. * @deprecated Deprecated since 3.5. Use getRegistry() and setRegistry() instead.
  130. */
  131. public static function registry(ObjectRegistry $registry = null)
  132. {
  133. deprecationWarning('Use Cache::getRegistry() and Cache::setRegistry() instead.');
  134. if ($registry) {
  135. static::setRegistry($registry);
  136. }
  137. return static::getRegistry();
  138. }
  139. /**
  140. * Finds and builds the instance of the required engine class.
  141. *
  142. * @param string $name Name of the config array that needs an engine instance built
  143. * @return void
  144. * @throws \InvalidArgumentException When a cache engine cannot be created.
  145. */
  146. protected static function _buildEngine($name)
  147. {
  148. $registry = static::getRegistry();
  149. if (empty(static::$_config[$name]['className'])) {
  150. throw new InvalidArgumentException(
  151. sprintf('The "%s" cache configuration does not exist.', $name)
  152. );
  153. }
  154. $config = static::$_config[$name];
  155. try {
  156. $registry->load($name, $config);
  157. } catch (RuntimeException $e) {
  158. if (!array_key_exists('fallback', $config)) {
  159. $registry->set($name, new NullEngine());
  160. trigger_error($e->getMessage(), E_USER_WARNING);
  161. return;
  162. }
  163. if ($config['fallback'] === false) {
  164. throw $e;
  165. }
  166. if ($config['fallback'] === $name) {
  167. throw new InvalidArgumentException(sprintf('"%s" cache configuration cannot fallback to itself.', $name), null, $e);
  168. }
  169. $fallbackEngine = clone static::engine($config['fallback']);
  170. $newConfig = $config + ['groups' => [], 'prefix' => null];
  171. $fallbackEngine->setConfig('groups', $newConfig['groups'], false);
  172. if ($newConfig['prefix']) {
  173. $fallbackEngine->setConfig('prefix', $newConfig['prefix'], false);
  174. }
  175. $registry->set($name, $fallbackEngine);
  176. }
  177. if ($config['className'] instanceof CacheEngine) {
  178. $config = $config['className']->getConfig();
  179. }
  180. if (!empty($config['groups'])) {
  181. foreach ($config['groups'] as $group) {
  182. static::$_groups[$group][] = $name;
  183. static::$_groups[$group] = array_unique(static::$_groups[$group]);
  184. sort(static::$_groups[$group]);
  185. }
  186. }
  187. }
  188. /**
  189. * Fetch the engine attached to a specific configuration name.
  190. *
  191. * If the cache engine & configuration are missing an error will be
  192. * triggered.
  193. *
  194. * @param string $config The configuration name you want an engine for.
  195. * @return \Cake\Cache\CacheEngine When caching is disabled a null engine will be returned.
  196. * @deprecated 3.7.0 Use Cache::pool() instead. In 4.0 all cache engines will implement the
  197. * PSR16 interface and this method does not return objects implementing that interface.
  198. */
  199. public static function engine($config)
  200. {
  201. if (!static::$_enabled) {
  202. return new NullEngine();
  203. }
  204. $registry = static::getRegistry();
  205. if (isset($registry->{$config})) {
  206. return $registry->{$config};
  207. }
  208. static::_buildEngine($config);
  209. return $registry->{$config};
  210. }
  211. /**
  212. * Get a SimpleCacheEngine object for the named cache pool.
  213. *
  214. * @param string $config The name of the configured cache backend.
  215. * @return \Cake\Cache\SimpleCacheEngine
  216. */
  217. public static function pool($config)
  218. {
  219. return new SimpleCacheEngine(static::engine($config));
  220. }
  221. /**
  222. * Garbage collection
  223. *
  224. * Permanently remove all expired and deleted data
  225. *
  226. * @param string $config [optional] The config name you wish to have garbage collected. Defaults to 'default'
  227. * @param int|null $expires [optional] An expires timestamp. Defaults to NULL
  228. * @return void
  229. * @deprecated 3.7.0 Will be removed in 4.0
  230. */
  231. public static function gc($config = 'default', $expires = null)
  232. {
  233. $engine = static::engine($config);
  234. $engine->gc($expires);
  235. }
  236. /**
  237. * Write data for key into cache.
  238. *
  239. * ### Usage:
  240. *
  241. * Writing to the active cache config:
  242. *
  243. * ```
  244. * Cache::write('cached_data', $data);
  245. * ```
  246. *
  247. * Writing to a specific cache config:
  248. *
  249. * ```
  250. * Cache::write('cached_data', $data, 'long_term');
  251. * ```
  252. *
  253. * @param string $key Identifier for the data
  254. * @param mixed $value Data to be cached - anything except a resource
  255. * @param string $config Optional string configuration name to write to. Defaults to 'default'
  256. * @return bool True if the data was successfully cached, false on failure
  257. */
  258. public static function write($key, $value, $config = 'default')
  259. {
  260. if (is_resource($value)) {
  261. return false;
  262. }
  263. $backend = static::pool($config);
  264. $success = $backend->set($key, $value);
  265. if ($success === false && $value !== '') {
  266. trigger_error(
  267. sprintf(
  268. "%s cache was unable to write '%s' to %s cache",
  269. $config,
  270. $key,
  271. get_class($backend)
  272. ),
  273. E_USER_WARNING
  274. );
  275. }
  276. return $success;
  277. }
  278. /**
  279. * Write data for many keys into cache.
  280. *
  281. * ### Usage:
  282. *
  283. * Writing to the active cache config:
  284. *
  285. * ```
  286. * Cache::writeMany(['cached_data_1' => 'data 1', 'cached_data_2' => 'data 2']);
  287. * ```
  288. *
  289. * Writing to a specific cache config:
  290. *
  291. * ```
  292. * Cache::writeMany(['cached_data_1' => 'data 1', 'cached_data_2' => 'data 2'], 'long_term');
  293. * ```
  294. *
  295. * @param array $data An array of data to be stored in the cache
  296. * @param string $config Optional string configuration name to write to. Defaults to 'default'
  297. * @return array of bools for each key provided, indicating true for success or false for fail
  298. * @throws \RuntimeException
  299. */
  300. public static function writeMany($data, $config = 'default')
  301. {
  302. $engine = static::engine($config);
  303. $return = $engine->writeMany($data);
  304. foreach ($return as $key => $success) {
  305. if ($success === false && $data[$key] !== '') {
  306. throw new RuntimeException(sprintf(
  307. '%s cache was unable to write \'%s\' to %s cache',
  308. $config,
  309. $key,
  310. get_class($engine)
  311. ));
  312. }
  313. }
  314. return $return;
  315. }
  316. /**
  317. * Read a key from the cache.
  318. *
  319. * ### Usage:
  320. *
  321. * Reading from the active cache configuration.
  322. *
  323. * ```
  324. * Cache::read('my_data');
  325. * ```
  326. *
  327. * Reading from a specific cache configuration.
  328. *
  329. * ```
  330. * Cache::read('my_data', 'long_term');
  331. * ```
  332. *
  333. * @param string $key Identifier for the data
  334. * @param string $config optional name of the configuration to use. Defaults to 'default'
  335. * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
  336. */
  337. public static function read($key, $config = 'default')
  338. {
  339. // TODO In 4.x this needs to change to use pool()
  340. $engine = static::engine($config);
  341. return $engine->read($key);
  342. }
  343. /**
  344. * Read multiple keys from the cache.
  345. *
  346. * ### Usage:
  347. *
  348. * Reading multiple keys from the active cache configuration.
  349. *
  350. * ```
  351. * Cache::readMany(['my_data_1', 'my_data_2]);
  352. * ```
  353. *
  354. * Reading from a specific cache configuration.
  355. *
  356. * ```
  357. * Cache::readMany(['my_data_1', 'my_data_2], 'long_term');
  358. * ```
  359. *
  360. * @param array $keys an array of keys to fetch from the cache
  361. * @param string $config optional name of the configuration to use. Defaults to 'default'
  362. * @return array An array containing, for each of the given $keys, the cached data or false if cached data could not be
  363. * retrieved.
  364. */
  365. public static function readMany($keys, $config = 'default')
  366. {
  367. // In 4.x this needs to change to use pool()
  368. $engine = static::engine($config);
  369. return $engine->readMany($keys);
  370. }
  371. /**
  372. * Increment a number under the key and return incremented value.
  373. *
  374. * @param string $key Identifier for the data
  375. * @param int $offset How much to add
  376. * @param string $config Optional string configuration name. Defaults to 'default'
  377. * @return mixed new value, or false if the data doesn't exist, is not integer,
  378. * or if there was an error fetching it.
  379. */
  380. public static function increment($key, $offset = 1, $config = 'default')
  381. {
  382. $engine = static::pool($config);
  383. if (!is_int($offset) || $offset < 0) {
  384. return false;
  385. }
  386. return $engine->increment($key, $offset);
  387. }
  388. /**
  389. * Decrement a number under the key and return decremented value.
  390. *
  391. * @param string $key Identifier for the data
  392. * @param int $offset How much to subtract
  393. * @param string $config Optional string configuration name. Defaults to 'default'
  394. * @return mixed new value, or false if the data doesn't exist, is not integer,
  395. * or if there was an error fetching it
  396. */
  397. public static function decrement($key, $offset = 1, $config = 'default')
  398. {
  399. $engine = static::pool($config);
  400. if (!is_int($offset) || $offset < 0) {
  401. return false;
  402. }
  403. return $engine->decrement($key, $offset);
  404. }
  405. /**
  406. * Delete a key from the cache.
  407. *
  408. * ### Usage:
  409. *
  410. * Deleting from the active cache configuration.
  411. *
  412. * ```
  413. * Cache::delete('my_data');
  414. * ```
  415. *
  416. * Deleting from a specific cache configuration.
  417. *
  418. * ```
  419. * Cache::delete('my_data', 'long_term');
  420. * ```
  421. *
  422. * @param string $key Identifier for the data
  423. * @param string $config name of the configuration to use. Defaults to 'default'
  424. * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
  425. */
  426. public static function delete($key, $config = 'default')
  427. {
  428. $backend = static::pool($config);
  429. return $backend->delete($key);
  430. }
  431. /**
  432. * Delete many keys from the cache.
  433. *
  434. * ### Usage:
  435. *
  436. * Deleting multiple keys from the active cache configuration.
  437. *
  438. * ```
  439. * Cache::deleteMany(['my_data_1', 'my_data_2']);
  440. * ```
  441. *
  442. * Deleting from a specific cache configuration.
  443. *
  444. * ```
  445. * Cache::deleteMany(['my_data_1', 'my_data_2], 'long_term');
  446. * ```
  447. *
  448. * @param array $keys Array of cache keys to be deleted
  449. * @param string $config name of the configuration to use. Defaults to 'default'
  450. * @return array of boolean values that are true if the value was successfully deleted, false if it didn't exist or
  451. * couldn't be removed
  452. */
  453. public static function deleteMany($keys, $config = 'default')
  454. {
  455. $backend = static::pool($config);
  456. return $backend->deleteMultiple($keys);
  457. }
  458. /**
  459. * Delete all keys from the cache.
  460. *
  461. * @param bool $check if true will check expiration, otherwise delete all. This parameter
  462. * will become a no-op value in 4.0 as it is deprecated.
  463. * @param string $config name of the configuration to use. Defaults to 'default'
  464. * @return bool True if the cache was successfully cleared, false otherwise
  465. */
  466. public static function clear($check = false, $config = 'default')
  467. {
  468. $engine = static::engine($config);
  469. return $engine->clear($check);
  470. }
  471. /**
  472. * Delete all keys from the cache from all configurations.
  473. *
  474. * @param bool $check if true will check expiration, otherwise delete all. This parameter
  475. * will become a no-op value in 4.0 as it is deprecated.
  476. * @return array Status code. For each configuration, it reports the status of the operation
  477. */
  478. public static function clearAll($check = false)
  479. {
  480. $status = [];
  481. foreach (self::configured() as $config) {
  482. $status[$config] = self::clear($check, $config);
  483. }
  484. return $status;
  485. }
  486. /**
  487. * Delete all keys from the cache belonging to the same group.
  488. *
  489. * @param string $group name of the group to be cleared
  490. * @param string $config name of the configuration to use. Defaults to 'default'
  491. * @return bool True if the cache group was successfully cleared, false otherwise
  492. */
  493. public static function clearGroup($group, $config = 'default')
  494. {
  495. $engine = static::pool($config);
  496. return $engine->clearGroup($group);
  497. }
  498. /**
  499. * Retrieve group names to config mapping.
  500. *
  501. * ```
  502. * Cache::config('daily', ['duration' => '1 day', 'groups' => ['posts']]);
  503. * Cache::config('weekly', ['duration' => '1 week', 'groups' => ['posts', 'archive']]);
  504. * $configs = Cache::groupConfigs('posts');
  505. * ```
  506. *
  507. * $configs will equal to `['posts' => ['daily', 'weekly']]`
  508. * Calling this method will load all the configured engines.
  509. *
  510. * @param string|null $group group name or null to retrieve all group mappings
  511. * @return array map of group and all configuration that has the same group
  512. * @throws \InvalidArgumentException
  513. */
  514. public static function groupConfigs($group = null)
  515. {
  516. foreach (array_keys(static::$_config) as $config) {
  517. static::engine($config);
  518. }
  519. if ($group === null) {
  520. return static::$_groups;
  521. }
  522. if (isset(self::$_groups[$group])) {
  523. return [$group => self::$_groups[$group]];
  524. }
  525. throw new InvalidArgumentException(sprintf('Invalid cache group %s', $group));
  526. }
  527. /**
  528. * Re-enable caching.
  529. *
  530. * If caching has been disabled with Cache::disable() this method will reverse that effect.
  531. *
  532. * @return void
  533. */
  534. public static function enable()
  535. {
  536. static::$_enabled = true;
  537. }
  538. /**
  539. * Disable caching.
  540. *
  541. * When disabled all cache operations will return null.
  542. *
  543. * @return void
  544. */
  545. public static function disable()
  546. {
  547. static::$_enabled = false;
  548. }
  549. /**
  550. * Check whether or not caching is enabled.
  551. *
  552. * @return bool
  553. */
  554. public static function enabled()
  555. {
  556. return static::$_enabled;
  557. }
  558. /**
  559. * Provides the ability to easily do read-through caching.
  560. *
  561. * When called if the $key is not set in $config, the $callable function
  562. * will be invoked. The results will then be stored into the cache config
  563. * at key.
  564. *
  565. * Examples:
  566. *
  567. * Using a Closure to provide data, assume `$this` is a Table object:
  568. *
  569. * ```
  570. * $results = Cache::remember('all_articles', function () {
  571. * return $this->find('all');
  572. * });
  573. * ```
  574. *
  575. * @param string $key The cache key to read/store data at.
  576. * @param callable $callable The callable that provides data in the case when
  577. * the cache key is empty. Can be any callable type supported by your PHP.
  578. * @param string $config The cache configuration to use for this operation.
  579. * Defaults to default.
  580. * @return mixed If the key is found: the cached data, false if the data
  581. * missing/expired, or an error. If the key is not found: boolean of the
  582. * success of the write
  583. */
  584. public static function remember($key, $callable, $config = 'default')
  585. {
  586. $existing = self::read($key, $config);
  587. if ($existing !== false) {
  588. return $existing;
  589. }
  590. $results = call_user_func($callable);
  591. self::write($key, $results, $config);
  592. return $results;
  593. }
  594. /**
  595. * Write data for key into a cache engine if it doesn't exist already.
  596. *
  597. * ### Usage:
  598. *
  599. * Writing to the active cache config:
  600. *
  601. * ```
  602. * Cache::add('cached_data', $data);
  603. * ```
  604. *
  605. * Writing to a specific cache config:
  606. *
  607. * ```
  608. * Cache::add('cached_data', $data, 'long_term');
  609. * ```
  610. *
  611. * @param string $key Identifier for the data.
  612. * @param mixed $value Data to be cached - anything except a resource.
  613. * @param string $config Optional string configuration name to write to. Defaults to 'default'.
  614. * @return bool True if the data was successfully cached, false on failure.
  615. * Or if the key existed already.
  616. */
  617. public static function add($key, $value, $config = 'default')
  618. {
  619. $pool = static::pool($config);
  620. if (is_resource($value)) {
  621. return false;
  622. }
  623. return $pool->add($key, $value);
  624. }
  625. }