Cache.php 22 KB

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