Repository.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. <?php
  2. namespace Illuminate\Cache;
  3. use Closure;
  4. use ArrayAccess;
  5. use DateTimeInterface;
  6. use BadMethodCallException;
  7. use Illuminate\Support\Carbon;
  8. use Illuminate\Cache\Events\CacheHit;
  9. use Illuminate\Contracts\Cache\Store;
  10. use Illuminate\Cache\Events\KeyWritten;
  11. use Illuminate\Cache\Events\CacheMissed;
  12. use Illuminate\Support\Traits\Macroable;
  13. use Illuminate\Cache\Events\KeyForgotten;
  14. use Illuminate\Support\InteractsWithTime;
  15. use Illuminate\Contracts\Events\Dispatcher;
  16. use Illuminate\Contracts\Cache\Repository as CacheContract;
  17. /**
  18. * @mixin \Illuminate\Contracts\Cache\Store
  19. */
  20. class Repository implements CacheContract, ArrayAccess
  21. {
  22. use InteractsWithTime;
  23. use Macroable {
  24. __call as macroCall;
  25. }
  26. /**
  27. * The cache store implementation.
  28. *
  29. * @var \Illuminate\Contracts\Cache\Store
  30. */
  31. protected $store;
  32. /**
  33. * The event dispatcher implementation.
  34. *
  35. * @var \Illuminate\Contracts\Events\Dispatcher
  36. */
  37. protected $events;
  38. /**
  39. * The default number of minutes to store items.
  40. *
  41. * @var float|int
  42. */
  43. protected $default = 60;
  44. /**
  45. * Create a new cache repository instance.
  46. *
  47. * @param \Illuminate\Contracts\Cache\Store $store
  48. * @return void
  49. */
  50. public function __construct(Store $store)
  51. {
  52. $this->store = $store;
  53. }
  54. /**
  55. * Determine if an item exists in the cache.
  56. *
  57. * @param string $key
  58. * @return bool
  59. */
  60. public function has($key)
  61. {
  62. return ! is_null($this->get($key));
  63. }
  64. /**
  65. * Retrieve an item from the cache by key.
  66. *
  67. * @param string $key
  68. * @param mixed $default
  69. * @return mixed
  70. */
  71. public function get($key, $default = null)
  72. {
  73. if (is_array($key)) {
  74. return $this->many($key);
  75. }
  76. $value = $this->store->get($this->itemKey($key));
  77. // If we could not find the cache value, we will fire the missed event and get
  78. // the default value for this cache value. This default could be a callback
  79. // so we will execute the value function which will resolve it if needed.
  80. if (is_null($value)) {
  81. $this->event(new CacheMissed($key));
  82. $value = value($default);
  83. } else {
  84. $this->event(new CacheHit($key, $value));
  85. }
  86. return $value;
  87. }
  88. /**
  89. * Retrieve multiple items from the cache by key.
  90. *
  91. * Items not found in the cache will have a null value.
  92. *
  93. * @param array $keys
  94. * @return array
  95. */
  96. public function many(array $keys)
  97. {
  98. $values = $this->store->many(collect($keys)->map(function ($value, $key) {
  99. return is_string($key) ? $key : $value;
  100. })->values()->all());
  101. return collect($values)->map(function ($value, $key) use ($keys) {
  102. return $this->handleManyResult($keys, $key, $value);
  103. })->all();
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. public function getMultiple($keys, $default = null)
  109. {
  110. if (is_null($default)) {
  111. return $this->many($keys);
  112. }
  113. foreach ($keys as $key) {
  114. if (! isset($default[$key])) {
  115. $default[$key] = null;
  116. }
  117. }
  118. return $this->many($default);
  119. }
  120. /**
  121. * Handle a result for the "many" method.
  122. *
  123. * @param array $keys
  124. * @param string $key
  125. * @param mixed $value
  126. * @return mixed
  127. */
  128. protected function handleManyResult($keys, $key, $value)
  129. {
  130. // If we could not find the cache value, we will fire the missed event and get
  131. // the default value for this cache value. This default could be a callback
  132. // so we will execute the value function which will resolve it if needed.
  133. if (is_null($value)) {
  134. $this->event(new CacheMissed($key));
  135. return isset($keys[$key]) ? value($keys[$key]) : null;
  136. }
  137. // If we found a valid value we will fire the "hit" event and return the value
  138. // back from this function. The "hit" event gives developers an opportunity
  139. // to listen for every possible cache "hit" throughout this applications.
  140. $this->event(new CacheHit($key, $value));
  141. return $value;
  142. }
  143. /**
  144. * Retrieve an item from the cache and delete it.
  145. *
  146. * @param string $key
  147. * @param mixed $default
  148. * @return mixed
  149. */
  150. public function pull($key, $default = null)
  151. {
  152. return tap($this->get($key, $default), function ($value) use ($key) {
  153. $this->forget($key);
  154. });
  155. }
  156. /**
  157. * Store an item in the cache.
  158. *
  159. * @param string $key
  160. * @param mixed $value
  161. * @param \DateTimeInterface|\DateInterval|float|int|null $minutes
  162. * @return void
  163. */
  164. public function put($key, $value, $minutes = null)
  165. {
  166. if (is_array($key)) {
  167. return $this->putMany($key, $value);
  168. }
  169. if (! is_null($minutes = $this->getMinutes($minutes))) {
  170. $this->store->put($this->itemKey($key), $value, $minutes);
  171. $this->event(new KeyWritten($key, $value, $minutes));
  172. }
  173. }
  174. /**
  175. * {@inheritdoc}
  176. */
  177. public function set($key, $value, $ttl = null)
  178. {
  179. $this->put($key, $value, $ttl);
  180. }
  181. /**
  182. * Store multiple items in the cache for a given number of minutes.
  183. *
  184. * @param array $values
  185. * @param \DateTimeInterface|\DateInterval|float|int $minutes
  186. * @return void
  187. */
  188. public function putMany(array $values, $minutes)
  189. {
  190. if (! is_null($minutes = $this->getMinutes($minutes))) {
  191. $this->store->putMany($values, $minutes);
  192. foreach ($values as $key => $value) {
  193. $this->event(new KeyWritten($key, $value, $minutes));
  194. }
  195. }
  196. }
  197. /**
  198. * {@inheritdoc}
  199. */
  200. public function setMultiple($values, $ttl = null)
  201. {
  202. $this->putMany($values, $ttl);
  203. }
  204. /**
  205. * Store an item in the cache if the key does not exist.
  206. *
  207. * @param string $key
  208. * @param mixed $value
  209. * @param \DateTimeInterface|\DateInterval|float|int $minutes
  210. * @return bool
  211. */
  212. public function add($key, $value, $minutes)
  213. {
  214. if (is_null($minutes = $this->getMinutes($minutes))) {
  215. return false;
  216. }
  217. // If the store has an "add" method we will call the method on the store so it
  218. // has a chance to override this logic. Some drivers better support the way
  219. // this operation should work with a total "atomic" implementation of it.
  220. if (method_exists($this->store, 'add')) {
  221. return $this->store->add(
  222. $this->itemKey($key), $value, $minutes
  223. );
  224. }
  225. // If the value did not exist in the cache, we will put the value in the cache
  226. // so it exists for subsequent requests. Then, we will return true so it is
  227. // easy to know if the value gets added. Otherwise, we will return false.
  228. if (is_null($this->get($key))) {
  229. $this->put($key, $value, $minutes);
  230. return true;
  231. }
  232. return false;
  233. }
  234. /**
  235. * Increment the value of an item in the cache.
  236. *
  237. * @param string $key
  238. * @param mixed $value
  239. * @return int|bool
  240. */
  241. public function increment($key, $value = 1)
  242. {
  243. return $this->store->increment($key, $value);
  244. }
  245. /**
  246. * Decrement the value of an item in the cache.
  247. *
  248. * @param string $key
  249. * @param mixed $value
  250. * @return int|bool
  251. */
  252. public function decrement($key, $value = 1)
  253. {
  254. return $this->store->decrement($key, $value);
  255. }
  256. /**
  257. * Store an item in the cache indefinitely.
  258. *
  259. * @param string $key
  260. * @param mixed $value
  261. * @return void
  262. */
  263. public function forever($key, $value)
  264. {
  265. $this->store->forever($this->itemKey($key), $value);
  266. $this->event(new KeyWritten($key, $value, 0));
  267. }
  268. /**
  269. * Get an item from the cache, or store the default value.
  270. *
  271. * @param string $key
  272. * @param \DateTimeInterface|\DateInterval|float|int $minutes
  273. * @param \Closure $callback
  274. * @return mixed
  275. */
  276. public function remember($key, $minutes, Closure $callback)
  277. {
  278. $value = $this->get($key);
  279. // If the item exists in the cache we will just return this immediately and if
  280. // not we will execute the given Closure and cache the result of that for a
  281. // given number of minutes so it's available for all subsequent requests.
  282. if (! is_null($value)) {
  283. return $value;
  284. }
  285. $this->put($key, $value = $callback(), $minutes);
  286. return $value;
  287. }
  288. /**
  289. * Get an item from the cache, or store the default value forever.
  290. *
  291. * @param string $key
  292. * @param \Closure $callback
  293. * @return mixed
  294. */
  295. public function sear($key, Closure $callback)
  296. {
  297. return $this->rememberForever($key, $callback);
  298. }
  299. /**
  300. * Get an item from the cache, or store the default value forever.
  301. *
  302. * @param string $key
  303. * @param \Closure $callback
  304. * @return mixed
  305. */
  306. public function rememberForever($key, Closure $callback)
  307. {
  308. $value = $this->get($key);
  309. // If the item exists in the cache we will just return this immediately and if
  310. // not we will execute the given Closure and cache the result of that for a
  311. // given number of minutes so it's available for all subsequent requests.
  312. if (! is_null($value)) {
  313. return $value;
  314. }
  315. $this->forever($key, $value = $callback());
  316. return $value;
  317. }
  318. /**
  319. * Remove an item from the cache.
  320. *
  321. * @param string $key
  322. * @return bool
  323. */
  324. public function forget($key)
  325. {
  326. return tap($this->store->forget($this->itemKey($key)), function () use ($key) {
  327. $this->event(new KeyForgotten($key));
  328. });
  329. }
  330. /**
  331. * {@inheritdoc}
  332. */
  333. public function delete($key)
  334. {
  335. return $this->forget($key);
  336. }
  337. /**
  338. * {@inheritdoc}
  339. */
  340. public function deleteMultiple($keys)
  341. {
  342. foreach ($keys as $key) {
  343. $this->forget($key);
  344. }
  345. return true;
  346. }
  347. /**
  348. * {@inheritdoc}
  349. */
  350. public function clear()
  351. {
  352. return $this->store->flush();
  353. }
  354. /**
  355. * Begin executing a new tags operation if the store supports it.
  356. *
  357. * @param array|mixed $names
  358. * @return \Illuminate\Cache\TaggedCache
  359. *
  360. * @throws \BadMethodCallException
  361. */
  362. public function tags($names)
  363. {
  364. if (! method_exists($this->store, 'tags')) {
  365. throw new BadMethodCallException('This cache store does not support tagging.');
  366. }
  367. $cache = $this->store->tags($names);
  368. if (! is_null($this->events)) {
  369. $cache->setEventDispatcher($this->events);
  370. }
  371. return $cache->setDefaultCacheTime($this->default);
  372. }
  373. /**
  374. * Format the key for a cache item.
  375. *
  376. * @param string $key
  377. * @return string
  378. */
  379. protected function itemKey($key)
  380. {
  381. return $key;
  382. }
  383. /**
  384. * Get the default cache time.
  385. *
  386. * @return float|int
  387. */
  388. public function getDefaultCacheTime()
  389. {
  390. return $this->default;
  391. }
  392. /**
  393. * Set the default cache time in minutes.
  394. *
  395. * @param float|int $minutes
  396. * @return $this
  397. */
  398. public function setDefaultCacheTime($minutes)
  399. {
  400. $this->default = $minutes;
  401. return $this;
  402. }
  403. /**
  404. * Get the cache store implementation.
  405. *
  406. * @return \Illuminate\Contracts\Cache\Store
  407. */
  408. public function getStore()
  409. {
  410. return $this->store;
  411. }
  412. /**
  413. * Fire an event for this cache instance.
  414. *
  415. * @param string $event
  416. * @return void
  417. */
  418. protected function event($event)
  419. {
  420. if (isset($this->events)) {
  421. $this->events->dispatch($event);
  422. }
  423. }
  424. /**
  425. * Set the event dispatcher instance.
  426. *
  427. * @param \Illuminate\Contracts\Events\Dispatcher $events
  428. * @return void
  429. */
  430. public function setEventDispatcher(Dispatcher $events)
  431. {
  432. $this->events = $events;
  433. }
  434. /**
  435. * Determine if a cached value exists.
  436. *
  437. * @param string $key
  438. * @return bool
  439. */
  440. public function offsetExists($key)
  441. {
  442. return $this->has($key);
  443. }
  444. /**
  445. * Retrieve an item from the cache by key.
  446. *
  447. * @param string $key
  448. * @return mixed
  449. */
  450. public function offsetGet($key)
  451. {
  452. return $this->get($key);
  453. }
  454. /**
  455. * Store an item in the cache for the default time.
  456. *
  457. * @param string $key
  458. * @param mixed $value
  459. * @return void
  460. */
  461. public function offsetSet($key, $value)
  462. {
  463. $this->put($key, $value, $this->default);
  464. }
  465. /**
  466. * Remove an item from the cache.
  467. *
  468. * @param string $key
  469. * @return void
  470. */
  471. public function offsetUnset($key)
  472. {
  473. $this->forget($key);
  474. }
  475. /**
  476. * Calculate the number of minutes with the given duration.
  477. *
  478. * @param \DateTimeInterface|\DateInterval|float|int $duration
  479. * @return float|int|null
  480. */
  481. protected function getMinutes($duration)
  482. {
  483. $duration = $this->parseDateInterval($duration);
  484. if ($duration instanceof DateTimeInterface) {
  485. $duration = Carbon::now()->diffInSeconds(Carbon::createFromTimestamp($duration->getTimestamp()), false) / 60;
  486. }
  487. return (int) ($duration * 60) > 0 ? $duration : null;
  488. }
  489. /**
  490. * Handle dynamic calls into macros or pass missing methods to the store.
  491. *
  492. * @param string $method
  493. * @param array $parameters
  494. * @return mixed
  495. */
  496. public function __call($method, $parameters)
  497. {
  498. if (static::hasMacro($method)) {
  499. return $this->macroCall($method, $parameters);
  500. }
  501. return $this->store->$method(...$parameters);
  502. }
  503. /**
  504. * Clone cache repository instance.
  505. *
  506. * @return void
  507. */
  508. public function __clone()
  509. {
  510. $this->store = clone $this->store;
  511. }
  512. }