├── LICENSE ├── README.md ├── UPGRADE-1.11.md ├── UPGRADE-1.4.md ├── composer.json └── lib └── Doctrine └── Common └── Cache ├── Cache.php ├── CacheProvider.php ├── ClearableCache.php ├── FlushableCache.php ├── MultiDeleteCache.php ├── MultiGetCache.php ├── MultiOperationCache.php ├── MultiPutCache.php └── Psr6 ├── CacheAdapter.php ├── CacheItem.php ├── DoctrineProvider.php ├── InvalidArgument.php └── TypedCacheItem.php /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2015 Doctrine Project 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Doctrine Cache 2 | 3 | [![Build Status](https://github.com/doctrine/cache/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/cache/actions) 4 | [![Code Coverage](https://codecov.io/gh/doctrine/cache/branch/1.10.x/graph/badge.svg)](https://codecov.io/gh/doctrine/cache/branch/1.10.x) 5 | 6 | [![Latest Stable Version](https://img.shields.io/packagist/v/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache) 7 | [![Total Downloads](https://img.shields.io/packagist/dt/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache) 8 | 9 | Cache component extracted from the Doctrine Common project. [Documentation](https://www.doctrine-project.org/projects/doctrine-cache/en/current/index.html) 10 | 11 | This library is deprecated and will no longer receive bug fixes from the 12 | Doctrine Project. Please use a different cache library, preferably PSR-6 or 13 | PSR-16 instead. 14 | -------------------------------------------------------------------------------- /UPGRADE-1.11.md: -------------------------------------------------------------------------------- 1 | # Upgrade to 1.11 2 | 3 | doctrine/cache will no longer be maintained and all cache implementations have 4 | been marked as deprecated. These implementations will be removed in 2.0, which 5 | will only contain interfaces to provide a lightweight package for backward 6 | compatibility. 7 | 8 | There are two new classes to use in the `Doctrine\Common\Cache\Psr6` namespace: 9 | * The `CacheAdapter` class allows using any Doctrine Cache as PSR-6 cache. This 10 | is useful to provide a forward compatibility layer in libraries that accept 11 | Doctrine cache implementations and switch to PSR-6. 12 | * The `DoctrineProvider` class allows using any PSR-6 cache as Doctrine cache. 13 | This implementation is designed for libraries that leak the cache and want to 14 | switch to allowing PSR-6 implementations. This class is design to be used 15 | during the transition phase of sunsetting doctrine/cache support. 16 | 17 | A full example to setup a filesystem based PSR-6 cache with symfony/cache 18 | using the `DoctrineProvider` to convert back to Doctrine's `Cache` interface: 19 | 20 | ```php 21 | use Doctrine\Common\Cache\Psr6\DoctrineProvider; 22 | use Symfony\Component\Cache\Adapter\FilesystemAdapter; 23 | 24 | $cachePool = new FilesystemAdapter(); 25 | $cache = DoctrineProvider::wrap($cachePool); 26 | // $cache instanceof \Doctrine\Common\Cache\Cache 27 | ``` 28 | -------------------------------------------------------------------------------- /UPGRADE-1.4.md: -------------------------------------------------------------------------------- 1 | # Upgrade to 1.4 2 | 3 | ## Minor BC Break: `Doctrine\Common\Cache\FileCache#$extension` is now `private`. 4 | 5 | If you need to override the value of `Doctrine\Common\Cache\FileCache#$extension`, then use the 6 | second parameter of `Doctrine\Common\Cache\FileCache#__construct()` instead of overriding 7 | the property in your own implementation. 8 | 9 | ## Minor BC Break: file based caches paths changed 10 | 11 | `Doctrine\Common\Cache\FileCache`, `Doctrine\Common\Cache\PhpFileCache` and 12 | `Doctrine\Common\Cache\FilesystemCache` are using a different cache paths structure. 13 | 14 | If you rely on warmed up caches for deployments, consider that caches generated 15 | with `doctrine/cache` `<1.4` are not compatible with the new directory structure, 16 | and will be ignored. 17 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "doctrine/cache", 3 | "type": "library", 4 | "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", 5 | "keywords": [ 6 | "php", 7 | "cache", 8 | "caching", 9 | "abstraction", 10 | "redis", 11 | "memcached", 12 | "couchdb", 13 | "xcache", 14 | "apcu" 15 | ], 16 | "homepage": "https://www.doctrine-project.org/projects/cache.html", 17 | "license": "MIT", 18 | "authors": [ 19 | {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, 20 | {"name": "Roman Borschel", "email": "roman@code-factory.org"}, 21 | {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, 22 | {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, 23 | {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} 24 | ], 25 | "require": { 26 | "php": "~7.1 || ^8.0" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", 30 | "doctrine/coding-standard": "^9", 31 | "psr/cache": "^1.0 || ^2.0 || ^3.0", 32 | "cache/integration-tests": "dev-master", 33 | "symfony/cache": "^4.4 || ^5.4 || ^6", 34 | "symfony/var-exporter": "^4.4 || ^5.4 || ^6" 35 | }, 36 | "conflict": { 37 | "doctrine/common": ">2.2,<2.4" 38 | }, 39 | "autoload": { 40 | "psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" } 41 | }, 42 | "autoload-dev": { 43 | "psr-4": { "Doctrine\\Tests\\": "tests/Doctrine/Tests" } 44 | }, 45 | "config": { 46 | "allow-plugins": { 47 | "dealerdirect/phpcodesniffer-composer-installer": true 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/Doctrine/Common/Cache/Cache.php: -------------------------------------------------------------------------------- 1 | hits 73 | * Number of keys that have been requested and found present. 74 | * 75 | * - misses 76 | * Number of items that have been requested and not found. 77 | * 78 | * - uptime 79 | * Time that the server is running. 80 | * 81 | * - memory_usage 82 | * Memory used by this server to store items. 83 | * 84 | * - memory_available 85 | * Memory allowed to use for storage. 86 | * 87 | * @return mixed[]|null An associative array with server's statistics if available, NULL otherwise. 88 | */ 89 | public function getStats(); 90 | } 91 | -------------------------------------------------------------------------------- /lib/Doctrine/Common/Cache/CacheProvider.php: -------------------------------------------------------------------------------- 1 | namespace = (string) $namespace; 41 | $this->namespaceVersion = null; 42 | } 43 | 44 | /** 45 | * Retrieves the namespace that prefixes all cache ids. 46 | * 47 | * @return string 48 | */ 49 | public function getNamespace() 50 | { 51 | return $this->namespace; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function fetch($id) 58 | { 59 | return $this->doFetch($this->getNamespacedId($id)); 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | public function fetchMultiple(array $keys) 66 | { 67 | if (empty($keys)) { 68 | return []; 69 | } 70 | 71 | // note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys 72 | $namespacedKeys = array_combine($keys, array_map([$this, 'getNamespacedId'], $keys)); 73 | $items = $this->doFetchMultiple($namespacedKeys); 74 | $foundItems = []; 75 | 76 | // no internal array function supports this sort of mapping: needs to be iterative 77 | // this filters and combines keys in one pass 78 | foreach ($namespacedKeys as $requestedKey => $namespacedKey) { 79 | if (! isset($items[$namespacedKey]) && ! array_key_exists($namespacedKey, $items)) { 80 | continue; 81 | } 82 | 83 | $foundItems[$requestedKey] = $items[$namespacedKey]; 84 | } 85 | 86 | return $foundItems; 87 | } 88 | 89 | /** 90 | * {@inheritdoc} 91 | */ 92 | public function saveMultiple(array $keysAndValues, $lifetime = 0) 93 | { 94 | $namespacedKeysAndValues = []; 95 | foreach ($keysAndValues as $key => $value) { 96 | $namespacedKeysAndValues[$this->getNamespacedId($key)] = $value; 97 | } 98 | 99 | return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime); 100 | } 101 | 102 | /** 103 | * {@inheritdoc} 104 | */ 105 | public function contains($id) 106 | { 107 | return $this->doContains($this->getNamespacedId($id)); 108 | } 109 | 110 | /** 111 | * {@inheritdoc} 112 | */ 113 | public function save($id, $data, $lifeTime = 0) 114 | { 115 | return $this->doSave($this->getNamespacedId($id), $data, $lifeTime); 116 | } 117 | 118 | /** 119 | * {@inheritdoc} 120 | */ 121 | public function deleteMultiple(array $keys) 122 | { 123 | return $this->doDeleteMultiple(array_map([$this, 'getNamespacedId'], $keys)); 124 | } 125 | 126 | /** 127 | * {@inheritdoc} 128 | */ 129 | public function delete($id) 130 | { 131 | return $this->doDelete($this->getNamespacedId($id)); 132 | } 133 | 134 | /** 135 | * {@inheritdoc} 136 | */ 137 | public function getStats() 138 | { 139 | return $this->doGetStats(); 140 | } 141 | 142 | /** 143 | * {@inheritDoc} 144 | */ 145 | public function flushAll() 146 | { 147 | return $this->doFlush(); 148 | } 149 | 150 | /** 151 | * {@inheritDoc} 152 | */ 153 | public function deleteAll() 154 | { 155 | $namespaceCacheKey = $this->getNamespaceCacheKey(); 156 | $namespaceVersion = $this->getNamespaceVersion() + 1; 157 | 158 | if ($this->doSave($namespaceCacheKey, $namespaceVersion)) { 159 | $this->namespaceVersion = $namespaceVersion; 160 | 161 | return true; 162 | } 163 | 164 | return false; 165 | } 166 | 167 | /** 168 | * Prefixes the passed id with the configured namespace value. 169 | * 170 | * @param string $id The id to namespace. 171 | * 172 | * @return string The namespaced id. 173 | */ 174 | private function getNamespacedId(string $id): string 175 | { 176 | $namespaceVersion = $this->getNamespaceVersion(); 177 | 178 | return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion); 179 | } 180 | 181 | /** 182 | * Returns the namespace cache key. 183 | */ 184 | private function getNamespaceCacheKey(): string 185 | { 186 | return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace); 187 | } 188 | 189 | /** 190 | * Returns the namespace version. 191 | */ 192 | private function getNamespaceVersion(): int 193 | { 194 | if ($this->namespaceVersion !== null) { 195 | return $this->namespaceVersion; 196 | } 197 | 198 | $namespaceCacheKey = $this->getNamespaceCacheKey(); 199 | $this->namespaceVersion = (int) $this->doFetch($namespaceCacheKey) ?: 1; 200 | 201 | return $this->namespaceVersion; 202 | } 203 | 204 | /** 205 | * Default implementation of doFetchMultiple. Each driver that supports multi-get should owerwrite it. 206 | * 207 | * @param string[] $keys Array of keys to retrieve from cache 208 | * 209 | * @return mixed[] Array of values retrieved for the given keys. 210 | */ 211 | protected function doFetchMultiple(array $keys) 212 | { 213 | $returnValues = []; 214 | 215 | foreach ($keys as $key) { 216 | $item = $this->doFetch($key); 217 | if ($item === false && ! $this->doContains($key)) { 218 | continue; 219 | } 220 | 221 | $returnValues[$key] = $item; 222 | } 223 | 224 | return $returnValues; 225 | } 226 | 227 | /** 228 | * Fetches an entry from the cache. 229 | * 230 | * @param string $id The id of the cache entry to fetch. 231 | * 232 | * @return mixed|false The cached data or FALSE, if no cache entry exists for the given id. 233 | */ 234 | abstract protected function doFetch($id); 235 | 236 | /** 237 | * Tests if an entry exists in the cache. 238 | * 239 | * @param string $id The cache id of the entry to check for. 240 | * 241 | * @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise. 242 | */ 243 | abstract protected function doContains($id); 244 | 245 | /** 246 | * Default implementation of doSaveMultiple. Each driver that supports multi-put should override it. 247 | * 248 | * @param mixed[] $keysAndValues Array of keys and values to save in cache 249 | * @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these 250 | * cache entries (0 => infinite lifeTime). 251 | * 252 | * @return bool TRUE if the operation was successful, FALSE if it wasn't. 253 | */ 254 | protected function doSaveMultiple(array $keysAndValues, $lifetime = 0) 255 | { 256 | $success = true; 257 | 258 | foreach ($keysAndValues as $key => $value) { 259 | if ($this->doSave($key, $value, $lifetime)) { 260 | continue; 261 | } 262 | 263 | $success = false; 264 | } 265 | 266 | return $success; 267 | } 268 | 269 | /** 270 | * Puts data into the cache. 271 | * 272 | * @param string $id The cache id. 273 | * @param string $data The cache entry/data. 274 | * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this 275 | * cache entry (0 => infinite lifeTime). 276 | * 277 | * @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise. 278 | */ 279 | abstract protected function doSave($id, $data, $lifeTime = 0); 280 | 281 | /** 282 | * Default implementation of doDeleteMultiple. Each driver that supports multi-delete should override it. 283 | * 284 | * @param string[] $keys Array of keys to delete from cache 285 | * 286 | * @return bool TRUE if the operation was successful, FALSE if it wasn't 287 | */ 288 | protected function doDeleteMultiple(array $keys) 289 | { 290 | $success = true; 291 | 292 | foreach ($keys as $key) { 293 | if ($this->doDelete($key)) { 294 | continue; 295 | } 296 | 297 | $success = false; 298 | } 299 | 300 | return $success; 301 | } 302 | 303 | /** 304 | * Deletes a cache entry. 305 | * 306 | * @param string $id The cache id. 307 | * 308 | * @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise. 309 | */ 310 | abstract protected function doDelete($id); 311 | 312 | /** 313 | * Flushes all cache entries. 314 | * 315 | * @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise. 316 | */ 317 | abstract protected function doFlush(); 318 | 319 | /** 320 | * Retrieves cached information from the data store. 321 | * 322 | * @return mixed[]|null An associative array with server's statistics if available, NULL otherwise. 323 | */ 324 | abstract protected function doGetStats(); 325 | } 326 | -------------------------------------------------------------------------------- /lib/Doctrine/Common/Cache/ClearableCache.php: -------------------------------------------------------------------------------- 1 | infinite lifeTime). 20 | * 21 | * @return bool TRUE if the operation was successful, FALSE if it wasn't. 22 | */ 23 | public function saveMultiple(array $keysAndValues, $lifetime = 0); 24 | } 25 | -------------------------------------------------------------------------------- /lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php: -------------------------------------------------------------------------------- 1 | */ 36 | private $deferredItems = []; 37 | 38 | public static function wrap(Cache $cache): CacheItemPoolInterface 39 | { 40 | if ($cache instanceof DoctrineProvider && ! $cache->getNamespace()) { 41 | return $cache->getPool(); 42 | } 43 | 44 | if ($cache instanceof SymfonyDoctrineProvider && ! $cache->getNamespace()) { 45 | $getPool = function () { 46 | // phpcs:ignore Squiz.Scope.StaticThisUsage.Found 47 | return $this->pool; 48 | }; 49 | 50 | return $getPool->bindTo($cache, SymfonyDoctrineProvider::class)(); 51 | } 52 | 53 | return new self($cache); 54 | } 55 | 56 | private function __construct(Cache $cache) 57 | { 58 | $this->cache = $cache; 59 | } 60 | 61 | /** @internal */ 62 | public function getCache(): Cache 63 | { 64 | return $this->cache; 65 | } 66 | 67 | /** 68 | * {@inheritDoc} 69 | */ 70 | public function getItem($key): CacheItemInterface 71 | { 72 | assert(self::validKey($key)); 73 | 74 | if (isset($this->deferredItems[$key])) { 75 | $this->commit(); 76 | } 77 | 78 | $value = $this->cache->fetch($key); 79 | 80 | if (PHP_VERSION_ID >= 80000) { 81 | if ($value !== false) { 82 | return new TypedCacheItem($key, $value, true); 83 | } 84 | 85 | return new TypedCacheItem($key, null, false); 86 | } 87 | 88 | if ($value !== false) { 89 | return new CacheItem($key, $value, true); 90 | } 91 | 92 | return new CacheItem($key, null, false); 93 | } 94 | 95 | /** 96 | * {@inheritDoc} 97 | */ 98 | public function getItems(array $keys = []): array 99 | { 100 | if ($this->deferredItems) { 101 | $this->commit(); 102 | } 103 | 104 | assert(self::validKeys($keys)); 105 | 106 | $values = $this->doFetchMultiple($keys); 107 | $items = []; 108 | 109 | if (PHP_VERSION_ID >= 80000) { 110 | foreach ($keys as $key) { 111 | if (array_key_exists($key, $values)) { 112 | $items[$key] = new TypedCacheItem($key, $values[$key], true); 113 | } else { 114 | $items[$key] = new TypedCacheItem($key, null, false); 115 | } 116 | } 117 | 118 | return $items; 119 | } 120 | 121 | foreach ($keys as $key) { 122 | if (array_key_exists($key, $values)) { 123 | $items[$key] = new CacheItem($key, $values[$key], true); 124 | } else { 125 | $items[$key] = new CacheItem($key, null, false); 126 | } 127 | } 128 | 129 | return $items; 130 | } 131 | 132 | /** 133 | * {@inheritDoc} 134 | */ 135 | public function hasItem($key): bool 136 | { 137 | assert(self::validKey($key)); 138 | 139 | if (isset($this->deferredItems[$key])) { 140 | $this->commit(); 141 | } 142 | 143 | return $this->cache->contains($key); 144 | } 145 | 146 | public function clear(): bool 147 | { 148 | $this->deferredItems = []; 149 | 150 | if (! $this->cache instanceof ClearableCache) { 151 | return false; 152 | } 153 | 154 | return $this->cache->deleteAll(); 155 | } 156 | 157 | /** 158 | * {@inheritDoc} 159 | */ 160 | public function deleteItem($key): bool 161 | { 162 | assert(self::validKey($key)); 163 | unset($this->deferredItems[$key]); 164 | 165 | return $this->cache->delete($key); 166 | } 167 | 168 | /** 169 | * {@inheritDoc} 170 | */ 171 | public function deleteItems(array $keys): bool 172 | { 173 | foreach ($keys as $key) { 174 | assert(self::validKey($key)); 175 | unset($this->deferredItems[$key]); 176 | } 177 | 178 | return $this->doDeleteMultiple($keys); 179 | } 180 | 181 | public function save(CacheItemInterface $item): bool 182 | { 183 | return $this->saveDeferred($item) && $this->commit(); 184 | } 185 | 186 | public function saveDeferred(CacheItemInterface $item): bool 187 | { 188 | if (! $item instanceof CacheItem && ! $item instanceof TypedCacheItem) { 189 | return false; 190 | } 191 | 192 | $this->deferredItems[$item->getKey()] = $item; 193 | 194 | return true; 195 | } 196 | 197 | public function commit(): bool 198 | { 199 | if (! $this->deferredItems) { 200 | return true; 201 | } 202 | 203 | $now = microtime(true); 204 | $itemsCount = 0; 205 | $byLifetime = []; 206 | $expiredKeys = []; 207 | 208 | foreach ($this->deferredItems as $key => $item) { 209 | $lifetime = ($item->getExpiry() ?? $now) - $now; 210 | 211 | if ($lifetime < 0) { 212 | $expiredKeys[] = $key; 213 | 214 | continue; 215 | } 216 | 217 | ++$itemsCount; 218 | $byLifetime[(int) $lifetime][$key] = $item->get(); 219 | } 220 | 221 | $this->deferredItems = []; 222 | 223 | switch (count($expiredKeys)) { 224 | case 0: 225 | break; 226 | case 1: 227 | $this->cache->delete(current($expiredKeys)); 228 | break; 229 | default: 230 | $this->doDeleteMultiple($expiredKeys); 231 | break; 232 | } 233 | 234 | if ($itemsCount === 1) { 235 | return $this->cache->save($key, $item->get(), (int) $lifetime); 236 | } 237 | 238 | $success = true; 239 | foreach ($byLifetime as $lifetime => $values) { 240 | $success = $this->doSaveMultiple($values, $lifetime) && $success; 241 | } 242 | 243 | return $success; 244 | } 245 | 246 | public function __destruct() 247 | { 248 | $this->commit(); 249 | } 250 | 251 | /** 252 | * @param mixed $key 253 | */ 254 | private static function validKey($key): bool 255 | { 256 | if (! is_string($key)) { 257 | throw new InvalidArgument(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key))); 258 | } 259 | 260 | if ($key === '') { 261 | throw new InvalidArgument('Cache key length must be greater than zero.'); 262 | } 263 | 264 | if (strpbrk($key, self::RESERVED_CHARACTERS) !== false) { 265 | throw new InvalidArgument(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS)); 266 | } 267 | 268 | return true; 269 | } 270 | 271 | /** 272 | * @param mixed[] $keys 273 | */ 274 | private static function validKeys(array $keys): bool 275 | { 276 | foreach ($keys as $key) { 277 | self::validKey($key); 278 | } 279 | 280 | return true; 281 | } 282 | 283 | /** 284 | * @param mixed[] $keys 285 | */ 286 | private function doDeleteMultiple(array $keys): bool 287 | { 288 | if ($this->cache instanceof MultiDeleteCache) { 289 | return $this->cache->deleteMultiple($keys); 290 | } 291 | 292 | $success = true; 293 | foreach ($keys as $key) { 294 | $success = $this->cache->delete($key) && $success; 295 | } 296 | 297 | return $success; 298 | } 299 | 300 | /** 301 | * @param mixed[] $keys 302 | * 303 | * @return mixed[] 304 | */ 305 | private function doFetchMultiple(array $keys): array 306 | { 307 | if ($this->cache instanceof MultiGetCache) { 308 | return $this->cache->fetchMultiple($keys); 309 | } 310 | 311 | $values = []; 312 | foreach ($keys as $key) { 313 | $value = $this->cache->fetch($key); 314 | if (! $value) { 315 | continue; 316 | } 317 | 318 | $values[$key] = $value; 319 | } 320 | 321 | return $values; 322 | } 323 | 324 | /** 325 | * @param mixed[] $keysAndValues 326 | */ 327 | private function doSaveMultiple(array $keysAndValues, int $lifetime = 0): bool 328 | { 329 | if ($this->cache instanceof MultiPutCache) { 330 | return $this->cache->saveMultiple($keysAndValues, $lifetime); 331 | } 332 | 333 | $success = true; 334 | foreach ($keysAndValues as $key => $value) { 335 | $success = $this->cache->save($key, $value, $lifetime) && $success; 336 | } 337 | 338 | return $success; 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /lib/Doctrine/Common/Cache/Psr6/CacheItem.php: -------------------------------------------------------------------------------- 1 | key = $key; 37 | $this->value = $data; 38 | $this->isHit = $isHit; 39 | } 40 | 41 | public function getKey(): string 42 | { 43 | return $this->key; 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | * 49 | * @return mixed 50 | */ 51 | public function get() 52 | { 53 | return $this->value; 54 | } 55 | 56 | public function isHit(): bool 57 | { 58 | return $this->isHit; 59 | } 60 | 61 | /** 62 | * {@inheritDoc} 63 | */ 64 | public function set($value): self 65 | { 66 | $this->value = $value; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | public function expiresAt($expiration): self 75 | { 76 | if ($expiration === null) { 77 | $this->expiry = null; 78 | } elseif ($expiration instanceof DateTimeInterface) { 79 | $this->expiry = (float) $expiration->format('U.u'); 80 | } else { 81 | throw new TypeError(sprintf( 82 | 'Expected $expiration to be an instance of DateTimeInterface or null, got %s', 83 | is_object($expiration) ? get_class($expiration) : gettype($expiration) 84 | )); 85 | } 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * {@inheritDoc} 92 | */ 93 | public function expiresAfter($time): self 94 | { 95 | if ($time === null) { 96 | $this->expiry = null; 97 | } elseif ($time instanceof DateInterval) { 98 | $this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); 99 | } elseif (is_int($time)) { 100 | $this->expiry = $time + microtime(true); 101 | } else { 102 | throw new TypeError(sprintf( 103 | 'Expected $time to be either an integer, an instance of DateInterval or null, got %s', 104 | is_object($time) ? get_class($time) : gettype($time) 105 | )); 106 | } 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * @internal 113 | */ 114 | public function getExpiry(): ?float 115 | { 116 | return $this->expiry; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/Doctrine/Common/Cache/Psr6/DoctrineProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Doctrine\Common\Cache\Psr6; 13 | 14 | use Doctrine\Common\Cache\Cache; 15 | use Doctrine\Common\Cache\CacheProvider; 16 | use Psr\Cache\CacheItemPoolInterface; 17 | use Symfony\Component\Cache\Adapter\DoctrineAdapter as SymfonyDoctrineAdapter; 18 | use Symfony\Contracts\Service\ResetInterface; 19 | 20 | use function rawurlencode; 21 | 22 | /** 23 | * This class was copied from the Symfony Framework, see the original copyright 24 | * notice above. The code is distributed subject to the license terms in 25 | * https://github.com/symfony/symfony/blob/ff0cf61278982539c49e467db9ab13cbd342f76d/LICENSE 26 | */ 27 | final class DoctrineProvider extends CacheProvider 28 | { 29 | /** @var CacheItemPoolInterface */ 30 | private $pool; 31 | 32 | public static function wrap(CacheItemPoolInterface $pool): Cache 33 | { 34 | if ($pool instanceof CacheAdapter) { 35 | return $pool->getCache(); 36 | } 37 | 38 | if ($pool instanceof SymfonyDoctrineAdapter) { 39 | $getCache = function () { 40 | // phpcs:ignore Squiz.Scope.StaticThisUsage.Found 41 | return $this->provider; 42 | }; 43 | 44 | return $getCache->bindTo($pool, SymfonyDoctrineAdapter::class)(); 45 | } 46 | 47 | return new self($pool); 48 | } 49 | 50 | private function __construct(CacheItemPoolInterface $pool) 51 | { 52 | $this->pool = $pool; 53 | } 54 | 55 | /** @internal */ 56 | public function getPool(): CacheItemPoolInterface 57 | { 58 | return $this->pool; 59 | } 60 | 61 | public function reset(): void 62 | { 63 | if ($this->pool instanceof ResetInterface) { 64 | $this->pool->reset(); 65 | } 66 | 67 | $this->setNamespace($this->getNamespace()); 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | protected function doFetch($id) 74 | { 75 | $item = $this->pool->getItem(rawurlencode($id)); 76 | 77 | return $item->isHit() ? $item->get() : false; 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | * 83 | * @return bool 84 | */ 85 | protected function doContains($id) 86 | { 87 | return $this->pool->hasItem(rawurlencode($id)); 88 | } 89 | 90 | /** 91 | * {@inheritdoc} 92 | * 93 | * @return bool 94 | */ 95 | protected function doSave($id, $data, $lifeTime = 0) 96 | { 97 | $item = $this->pool->getItem(rawurlencode($id)); 98 | 99 | if (0 < $lifeTime) { 100 | $item->expiresAfter($lifeTime); 101 | } 102 | 103 | return $this->pool->save($item->set($data)); 104 | } 105 | 106 | /** 107 | * {@inheritdoc} 108 | * 109 | * @return bool 110 | */ 111 | protected function doDelete($id) 112 | { 113 | return $this->pool->deleteItem(rawurlencode($id)); 114 | } 115 | 116 | /** 117 | * {@inheritdoc} 118 | * 119 | * @return bool 120 | */ 121 | protected function doFlush() 122 | { 123 | return $this->pool->clear(); 124 | } 125 | 126 | /** 127 | * {@inheritdoc} 128 | * 129 | * @return array|null 130 | */ 131 | protected function doGetStats() 132 | { 133 | return null; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /lib/Doctrine/Common/Cache/Psr6/InvalidArgument.php: -------------------------------------------------------------------------------- 1 | key; 33 | } 34 | 35 | public function get(): mixed 36 | { 37 | return $this->value; 38 | } 39 | 40 | public function isHit(): bool 41 | { 42 | return $this->isHit; 43 | } 44 | 45 | public function set(mixed $value): static 46 | { 47 | $this->value = $value; 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | public function expiresAt($expiration): static 56 | { 57 | if ($expiration === null) { 58 | $this->expiry = null; 59 | } elseif ($expiration instanceof DateTimeInterface) { 60 | $this->expiry = (float) $expiration->format('U.u'); 61 | } else { 62 | throw new TypeError(sprintf( 63 | 'Expected $expiration to be an instance of DateTimeInterface or null, got %s', 64 | get_debug_type($expiration) 65 | )); 66 | } 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | public function expiresAfter($time): static 75 | { 76 | if ($time === null) { 77 | $this->expiry = null; 78 | } elseif ($time instanceof DateInterval) { 79 | $this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); 80 | } elseif (is_int($time)) { 81 | $this->expiry = $time + microtime(true); 82 | } else { 83 | throw new TypeError(sprintf( 84 | 'Expected $time to be either an integer, an instance of DateInterval or null, got %s', 85 | get_debug_type($time) 86 | )); 87 | } 88 | 89 | return $this; 90 | } 91 | 92 | /** 93 | * @internal 94 | */ 95 | public function getExpiry(): ?float 96 | { 97 | return $this->expiry; 98 | } 99 | } 100 | --------------------------------------------------------------------------------