CacheProvider.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. namespace Doctrine\Common\Cache;
  3. use function array_combine;
  4. use function array_key_exists;
  5. use function array_map;
  6. use function sprintf;
  7. /**
  8. * Base class for cache provider implementations.
  9. *
  10. */
  11. abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiOperationCache
  12. {
  13. public const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]';
  14. /**
  15. * The namespace to prefix all cache ids with.
  16. *
  17. * @var string
  18. */
  19. private $namespace = '';
  20. /**
  21. * The namespace version.
  22. *
  23. * @var int|null
  24. */
  25. private $namespaceVersion;
  26. /**
  27. * Sets the namespace to prefix all cache ids with.
  28. *
  29. * @param string $namespace
  30. *
  31. * @return void
  32. */
  33. public function setNamespace($namespace)
  34. {
  35. $this->namespace = (string) $namespace;
  36. $this->namespaceVersion = null;
  37. }
  38. /**
  39. * Retrieves the namespace that prefixes all cache ids.
  40. *
  41. * @return string
  42. */
  43. public function getNamespace()
  44. {
  45. return $this->namespace;
  46. }
  47. /**
  48. * {@inheritdoc}
  49. */
  50. public function fetch($id)
  51. {
  52. return $this->doFetch($this->getNamespacedId($id));
  53. }
  54. /**
  55. * {@inheritdoc}
  56. */
  57. public function fetchMultiple(array $keys)
  58. {
  59. if (empty($keys)) {
  60. return [];
  61. }
  62. // note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys
  63. $namespacedKeys = array_combine($keys, array_map([$this, 'getNamespacedId'], $keys));
  64. $items = $this->doFetchMultiple($namespacedKeys);
  65. $foundItems = [];
  66. // no internal array function supports this sort of mapping: needs to be iterative
  67. // this filters and combines keys in one pass
  68. foreach ($namespacedKeys as $requestedKey => $namespacedKey) {
  69. if (! isset($items[$namespacedKey]) && ! array_key_exists($namespacedKey, $items)) {
  70. continue;
  71. }
  72. $foundItems[$requestedKey] = $items[$namespacedKey];
  73. }
  74. return $foundItems;
  75. }
  76. /**
  77. * {@inheritdoc}
  78. */
  79. public function saveMultiple(array $keysAndValues, $lifetime = 0)
  80. {
  81. $namespacedKeysAndValues = [];
  82. foreach ($keysAndValues as $key => $value) {
  83. $namespacedKeysAndValues[$this->getNamespacedId($key)] = $value;
  84. }
  85. return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime);
  86. }
  87. /**
  88. * {@inheritdoc}
  89. */
  90. public function contains($id)
  91. {
  92. return $this->doContains($this->getNamespacedId($id));
  93. }
  94. /**
  95. * {@inheritdoc}
  96. */
  97. public function save($id, $data, $lifeTime = 0)
  98. {
  99. return $this->doSave($this->getNamespacedId($id), $data, $lifeTime);
  100. }
  101. /**
  102. * {@inheritdoc}
  103. */
  104. public function deleteMultiple(array $keys)
  105. {
  106. return $this->doDeleteMultiple(array_map([$this, 'getNamespacedId'], $keys));
  107. }
  108. /**
  109. * {@inheritdoc}
  110. */
  111. public function delete($id)
  112. {
  113. return $this->doDelete($this->getNamespacedId($id));
  114. }
  115. /**
  116. * {@inheritdoc}
  117. */
  118. public function getStats()
  119. {
  120. return $this->doGetStats();
  121. }
  122. /**
  123. * {@inheritDoc}
  124. */
  125. public function flushAll()
  126. {
  127. return $this->doFlush();
  128. }
  129. /**
  130. * {@inheritDoc}
  131. */
  132. public function deleteAll()
  133. {
  134. $namespaceCacheKey = $this->getNamespaceCacheKey();
  135. $namespaceVersion = $this->getNamespaceVersion() + 1;
  136. if ($this->doSave($namespaceCacheKey, $namespaceVersion)) {
  137. $this->namespaceVersion = $namespaceVersion;
  138. return true;
  139. }
  140. return false;
  141. }
  142. /**
  143. * Prefixes the passed id with the configured namespace value.
  144. *
  145. * @param string $id The id to namespace.
  146. *
  147. * @return string The namespaced id.
  148. */
  149. private function getNamespacedId(string $id) : string
  150. {
  151. $namespaceVersion = $this->getNamespaceVersion();
  152. return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
  153. }
  154. /**
  155. * Returns the namespace cache key.
  156. */
  157. private function getNamespaceCacheKey() : string
  158. {
  159. return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
  160. }
  161. /**
  162. * Returns the namespace version.
  163. */
  164. private function getNamespaceVersion() : int
  165. {
  166. if ($this->namespaceVersion !== null) {
  167. return $this->namespaceVersion;
  168. }
  169. $namespaceCacheKey = $this->getNamespaceCacheKey();
  170. $this->namespaceVersion = (int) $this->doFetch($namespaceCacheKey) ?: 1;
  171. return $this->namespaceVersion;
  172. }
  173. /**
  174. * Default implementation of doFetchMultiple. Each driver that supports multi-get should owerwrite it.
  175. *
  176. * @param array $keys Array of keys to retrieve from cache
  177. * @return array Array of values retrieved for the given keys.
  178. */
  179. protected function doFetchMultiple(array $keys)
  180. {
  181. $returnValues = [];
  182. foreach ($keys as $key) {
  183. $item = $this->doFetch($key);
  184. if ($item === false && ! $this->doContains($key)) {
  185. continue;
  186. }
  187. $returnValues[$key] = $item;
  188. }
  189. return $returnValues;
  190. }
  191. /**
  192. * Fetches an entry from the cache.
  193. *
  194. * @param string $id The id of the cache entry to fetch.
  195. *
  196. * @return mixed|false The cached data or FALSE, if no cache entry exists for the given id.
  197. */
  198. abstract protected function doFetch($id);
  199. /**
  200. * Tests if an entry exists in the cache.
  201. *
  202. * @param string $id The cache id of the entry to check for.
  203. *
  204. * @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise.
  205. */
  206. abstract protected function doContains($id);
  207. /**
  208. * Default implementation of doSaveMultiple. Each driver that supports multi-put should override it.
  209. *
  210. * @param array $keysAndValues Array of keys and values to save in cache
  211. * @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these
  212. * cache entries (0 => infinite lifeTime).
  213. *
  214. * @return bool TRUE if the operation was successful, FALSE if it wasn't.
  215. */
  216. protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
  217. {
  218. $success = true;
  219. foreach ($keysAndValues as $key => $value) {
  220. if ($this->doSave($key, $value, $lifetime)) {
  221. continue;
  222. }
  223. $success = false;
  224. }
  225. return $success;
  226. }
  227. /**
  228. * Puts data into the cache.
  229. *
  230. * @param string $id The cache id.
  231. * @param string $data The cache entry/data.
  232. * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this
  233. * cache entry (0 => infinite lifeTime).
  234. *
  235. * @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
  236. */
  237. abstract protected function doSave($id, $data, $lifeTime = 0);
  238. /**
  239. * Default implementation of doDeleteMultiple. Each driver that supports multi-delete should override it.
  240. *
  241. * @param array $keys Array of keys to delete from cache
  242. *
  243. * @return bool TRUE if the operation was successful, FALSE if it wasn't
  244. */
  245. protected function doDeleteMultiple(array $keys)
  246. {
  247. $success = true;
  248. foreach ($keys as $key) {
  249. if ($this->doDelete($key)) {
  250. continue;
  251. }
  252. $success = false;
  253. }
  254. return $success;
  255. }
  256. /**
  257. * Deletes a cache entry.
  258. *
  259. * @param string $id The cache id.
  260. *
  261. * @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
  262. */
  263. abstract protected function doDelete($id);
  264. /**
  265. * Flushes all cache entries.
  266. *
  267. * @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise.
  268. */
  269. abstract protected function doFlush();
  270. /**
  271. * Retrieves cached information from the data store.
  272. *
  273. * @return array|null An associative array with server's statistics if available, NULL otherwise.
  274. */
  275. abstract protected function doGetStats();
  276. }