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. abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiOperationCache
  11. {
  12. public const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]';
  13. /**
  14. * The namespace to prefix all cache ids with.
  15. *
  16. * @var string
  17. */
  18. private $namespace = '';
  19. /**
  20. * The namespace version.
  21. *
  22. * @var int|null
  23. */
  24. private $namespaceVersion;
  25. /**
  26. * Sets the namespace to prefix all cache ids with.
  27. *
  28. * @param string $namespace
  29. *
  30. * @return void
  31. */
  32. public function setNamespace($namespace)
  33. {
  34. $this->namespace = (string) $namespace;
  35. $this->namespaceVersion = null;
  36. }
  37. /**
  38. * Retrieves the namespace that prefixes all cache ids.
  39. *
  40. * @return string
  41. */
  42. public function getNamespace()
  43. {
  44. return $this->namespace;
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public function fetch($id)
  50. {
  51. return $this->doFetch($this->getNamespacedId($id));
  52. }
  53. /**
  54. * {@inheritdoc}
  55. */
  56. public function fetchMultiple(array $keys)
  57. {
  58. if (empty($keys)) {
  59. return [];
  60. }
  61. // note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys
  62. $namespacedKeys = array_combine($keys, array_map([$this, 'getNamespacedId'], $keys));
  63. $items = $this->doFetchMultiple($namespacedKeys);
  64. $foundItems = [];
  65. // no internal array function supports this sort of mapping: needs to be iterative
  66. // this filters and combines keys in one pass
  67. foreach ($namespacedKeys as $requestedKey => $namespacedKey) {
  68. if (! isset($items[$namespacedKey]) && ! array_key_exists($namespacedKey, $items)) {
  69. continue;
  70. }
  71. $foundItems[$requestedKey] = $items[$namespacedKey];
  72. }
  73. return $foundItems;
  74. }
  75. /**
  76. * {@inheritdoc}
  77. */
  78. public function saveMultiple(array $keysAndValues, $lifetime = 0)
  79. {
  80. $namespacedKeysAndValues = [];
  81. foreach ($keysAndValues as $key => $value) {
  82. $namespacedKeysAndValues[$this->getNamespacedId($key)] = $value;
  83. }
  84. return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime);
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. public function contains($id)
  90. {
  91. return $this->doContains($this->getNamespacedId($id));
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function save($id, $data, $lifeTime = 0)
  97. {
  98. return $this->doSave($this->getNamespacedId($id), $data, $lifeTime);
  99. }
  100. /**
  101. * {@inheritdoc}
  102. */
  103. public function deleteMultiple(array $keys)
  104. {
  105. return $this->doDeleteMultiple(array_map([$this, 'getNamespacedId'], $keys));
  106. }
  107. /**
  108. * {@inheritdoc}
  109. */
  110. public function delete($id)
  111. {
  112. return $this->doDelete($this->getNamespacedId($id));
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public function getStats()
  118. {
  119. return $this->doGetStats();
  120. }
  121. /**
  122. * {@inheritDoc}
  123. */
  124. public function flushAll()
  125. {
  126. return $this->doFlush();
  127. }
  128. /**
  129. * {@inheritDoc}
  130. */
  131. public function deleteAll()
  132. {
  133. $namespaceCacheKey = $this->getNamespaceCacheKey();
  134. $namespaceVersion = $this->getNamespaceVersion() + 1;
  135. if ($this->doSave($namespaceCacheKey, $namespaceVersion)) {
  136. $this->namespaceVersion = $namespaceVersion;
  137. return true;
  138. }
  139. return false;
  140. }
  141. /**
  142. * Prefixes the passed id with the configured namespace value.
  143. *
  144. * @param string $id The id to namespace.
  145. *
  146. * @return string The namespaced id.
  147. */
  148. private function getNamespacedId(string $id) : string
  149. {
  150. $namespaceVersion = $this->getNamespaceVersion();
  151. return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
  152. }
  153. /**
  154. * Returns the namespace cache key.
  155. */
  156. private function getNamespaceCacheKey() : string
  157. {
  158. return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
  159. }
  160. /**
  161. * Returns the namespace version.
  162. */
  163. private function getNamespaceVersion() : int
  164. {
  165. if ($this->namespaceVersion !== null) {
  166. return $this->namespaceVersion;
  167. }
  168. $namespaceCacheKey = $this->getNamespaceCacheKey();
  169. $this->namespaceVersion = (int) $this->doFetch($namespaceCacheKey) ?: 1;
  170. return $this->namespaceVersion;
  171. }
  172. /**
  173. * Default implementation of doFetchMultiple. Each driver that supports multi-get should owerwrite it.
  174. *
  175. * @param array $keys Array of keys to retrieve from cache
  176. *
  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. }