diff options
Diffstat (limited to 'vendor/symfony/cache')
74 files changed, 2128 insertions, 683 deletions
diff --git a/vendor/symfony/cache/Adapter/AbstractAdapter.php b/vendor/symfony/cache/Adapter/AbstractAdapter.php index 6897fbceee..883a94ba9b 100644 --- a/vendor/symfony/cache/Adapter/AbstractAdapter.php +++ b/vendor/symfony/cache/Adapter/AbstractAdapter.php @@ -11,14 +11,13 @@ namespace Symfony\Component\Cache\Adapter; -use Psr\Cache\CacheItemInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\ResettableInterface; -use Symfony\Component\Cache\Traits\AbstractTrait; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Contracts\Cache\CacheInterface; @@ -27,15 +26,12 @@ use Symfony\Contracts\Cache\CacheInterface; */ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface { - use AbstractTrait; + use AbstractAdapterTrait; use ContractsTrait; private static $apcuSupported; private static $phpFilesSupported; - private $createCacheItem; - private $mergeByLifetime; - protected function __construct(string $namespace = '', int $defaultLifetime = 0) { $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; @@ -132,7 +128,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg if (!\is_string($dsn)) { throw new InvalidArgumentException(sprintf('The %s() method expect argument #1 to be string, %s given.', __METHOD__, \gettype($dsn))); } - if (0 === strpos($dsn, 'redis:')) { + if (0 === strpos($dsn, 'redis:') || 0 === strpos($dsn, 'rediss:')) { return RedisAdapter::createConnection($dsn, $options); } if (0 === strpos($dsn, 'memcached:')) { @@ -145,81 +141,6 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg /** * {@inheritdoc} */ - public function getItem($key) - { - if ($this->deferred) { - $this->commit(); - } - $id = $this->getId($key); - - $f = $this->createCacheItem; - $isHit = false; - $value = null; - - try { - foreach ($this->doFetch([$id]) as $value) { - $isHit = true; - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]); - } - - return $f($key, $value, $isHit); - } - - /** - * {@inheritdoc} - */ - public function getItems(array $keys = []) - { - if ($this->deferred) { - $this->commit(); - } - $ids = []; - - foreach ($keys as $key) { - $ids[] = $this->getId($key); - } - try { - $items = $this->doFetch($ids); - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => $keys, 'exception' => $e]); - $items = []; - } - $ids = array_combine($ids, $keys); - - return $this->generateItems($items, $ids); - } - - /** - * {@inheritdoc} - */ - public function save(CacheItemInterface $item) - { - if (!$item instanceof CacheItem) { - return false; - } - $this->deferred[$item->getKey()] = $item; - - return $this->commit(); - } - - /** - * {@inheritdoc} - */ - public function saveDeferred(CacheItemInterface $item) - { - if (!$item instanceof CacheItem) { - return false; - } - $this->deferred[$item->getKey()] = $item; - - return true; - } - - /** - * {@inheritdoc} - */ public function commit() { $ok = true; @@ -243,7 +164,8 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg $ok = false; $v = $values[$id]; $type = \is_object($v) ? \get_class($v) : \gettype($v); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); } } else { foreach ($values as $id => $v) { @@ -265,39 +187,11 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg } $ok = false; $type = \is_object($v) ? \get_class($v) : \gettype($v); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); } } return $ok; } - - public function __destruct() - { - if ($this->deferred) { - $this->commit(); - } - } - - private function generateItems($items, &$keys) - { - $f = $this->createCacheItem; - - try { - foreach ($items as $id => $value) { - if (!isset($keys[$id])) { - $id = key($keys); - } - $key = $keys[$id]; - unset($keys[$id]); - yield $key => $f($key, $value, true); - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]); - } - - foreach ($keys as $key) { - yield $key => $f($key, null, false); - } - } } diff --git a/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php new file mode 100644 index 0000000000..2eb5ce8c6e --- /dev/null +++ b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php @@ -0,0 +1,305 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Log\LoggerAwareInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +/** + * Abstract for native TagAware adapters. + * + * To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids + * to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate(). + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @internal + * @experimental in 4.3 + */ +abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface +{ + use AbstractAdapterTrait; + use ContractsTrait; + + private const TAGS_PREFIX = "\0tags\0"; + + protected function __construct(string $namespace = '', int $defaultLifetime = 0) + { + $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; + if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { + throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + } + $this->createCacheItem = \Closure::bind( + static function ($key, $value, $isHit) use ($defaultLifetime) { + $item = new CacheItem(); + $item->key = $key; + $item->defaultLifetime = $defaultLifetime; + $item->isTaggable = true; + // If structure does not match what we expect return item as is (no value and not a hit) + if (!\is_array($value) || !\array_key_exists('value', $value)) { + return $item; + } + $item->isHit = $isHit; + // Extract value, tags and meta data from the cache value + $item->value = $value['value']; + $item->metadata[CacheItem::METADATA_TAGS] = $value['tags'] ?? []; + if (isset($value['meta'])) { + // For compactness these values are packed, & expiry is offset to reduce size + $v = \unpack('Ve/Nc', $value['meta']); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } + + return $item; + }, + null, + CacheItem::class + ); + $getId = \Closure::fromCallable([$this, 'getId']); + $tagPrefix = self::TAGS_PREFIX; + $this->mergeByLifetime = \Closure::bind( + static function ($deferred, &$expiredIds) use ($getId, $tagPrefix) { + $byLifetime = []; + $now = microtime(true); + $expiredIds = []; + + foreach ($deferred as $key => $item) { + $key = (string) $key; + if (null === $item->expiry) { + $ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0; + } elseif (0 >= $ttl = (int) ($item->expiry - $now)) { + $expiredIds[] = $getId($key); + continue; + } + // Store Value and Tags on the cache value + if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) { + $value = ['value' => $item->value, 'tags' => $metadata[CacheItem::METADATA_TAGS]]; + unset($metadata[CacheItem::METADATA_TAGS]); + } else { + $value = ['value' => $item->value, 'tags' => []]; + } + + if ($metadata) { + // For compactness, expiry and creation duration are packed, using magic numbers as separators + $value['meta'] = \pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME]); + } + + // Extract tag changes, these should be removed from values in doSave() + $value['tag-operations'] = ['add' => [], 'remove' => []]; + $oldTags = $item->metadata[CacheItem::METADATA_TAGS] ?? []; + foreach (\array_diff($value['tags'], $oldTags) as $addedTag) { + $value['tag-operations']['add'][] = $getId($tagPrefix.$addedTag); + } + foreach (\array_diff($oldTags, $value['tags']) as $removedTag) { + $value['tag-operations']['remove'][] = $getId($tagPrefix.$removedTag); + } + + $byLifetime[$ttl][$getId($key)] = $value; + } + + return $byLifetime; + }, + null, + CacheItem::class + ); + } + + /** + * Persists several cache items immediately. + * + * @param array $values The values to cache, indexed by their cache identifier + * @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning + * @param array[] $addTagData Hash where key is tag id, and array value is list of cache id's to add to tag + * @param array[] $removeTagData Hash where key is tag id, and array value is list of cache id's to remove to tag + * + * @return array The identifiers that failed to be cached or a boolean stating if caching succeeded or not + */ + abstract protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $removeTagData = []): array; + + /** + * Removes multiple items from the pool and their corresponding tags. + * + * @param array $ids An array of identifiers that should be removed from the pool + * @param array $tagData Optional array of tag identifiers => key identifiers that should be removed from the pool + * + * @return bool True if the items were successfully removed, false otherwise + */ + abstract protected function doDelete(array $ids, array $tagData = []): bool; + + /** + * Invalidates cached items using tags. + * + * @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id + * + * @return bool True on success + */ + abstract protected function doInvalidate(array $tagIds): bool; + + /** + * {@inheritdoc} + */ + public function commit() + { + $ok = true; + $byLifetime = $this->mergeByLifetime; + $byLifetime = $byLifetime($this->deferred, $expiredIds); + $retry = $this->deferred = []; + + if ($expiredIds) { + // Tags are not cleaned up in this case, however that is done on invalidateTags(). + $this->doDelete($expiredIds); + } + foreach ($byLifetime as $lifetime => $values) { + try { + $values = $this->extractTagData($values, $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + if (\is_array($e) || 1 === \count($values)) { + foreach (\is_array($e) ? $e : array_keys($values) as $id) { + $ok = false; + $v = $values[$id]; + $type = \is_object($v) ? \get_class($v) : \gettype($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); + } + } else { + foreach ($values as $id => $v) { + $retry[$lifetime][] = $id; + } + } + } + + // When bulk-save failed, retry each item individually + foreach ($retry as $lifetime => $ids) { + foreach ($ids as $id) { + try { + $v = $byLifetime[$lifetime][$id]; + $values = $this->extractTagData([$id => $v], $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + $ok = false; + $type = \is_object($v) ? \get_class($v) : \gettype($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); + } + } + + return $ok; + } + + /** + * {@inheritdoc} + * + * Overloaded in order to deal with tags for adjusted doDelete() signature. + */ + public function deleteItems(array $keys) + { + if (!$keys) { + return true; + } + + $ids = []; + $tagData = []; + + foreach ($keys as $key) { + $ids[$key] = $this->getId($key); + unset($this->deferred[$key]); + } + + foreach ($this->doFetch($ids) as $id => $value) { + foreach ($value['tags'] ?? [] as $tag) { + $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id; + } + } + + try { + if ($this->doDelete(\array_values($ids), $tagData)) { + return true; + } + } catch (\Exception $e) { + } + + $ok = true; + + // When bulk-delete failed, retry each item individually + foreach ($ids as $key => $id) { + try { + $e = null; + if ($this->doDelete([$id])) { + continue; + } + } catch (\Exception $e) { + } + $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]); + $ok = false; + } + + return $ok; + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) + { + if (empty($tags)) { + return false; + } + + $tagIds = []; + foreach (\array_unique($tags) as $tag) { + $tagIds[] = $this->getId(self::TAGS_PREFIX.$tag); + } + + if ($this->doInvalidate($tagIds)) { + return true; + } + + return false; + } + + /** + * Extracts tags operation data from $values set in mergeByLifetime, and returns values without it. + */ + private function extractTagData(array $values, ?array &$addTagData, ?array &$removeTagData): array + { + $addTagData = $removeTagData = []; + foreach ($values as $id => $value) { + foreach ($value['tag-operations']['add'] as $tag => $tagId) { + $addTagData[$tagId][] = $id; + } + + foreach ($value['tag-operations']['remove'] as $tag => $tagId) { + $removeTagData[$tagId][] = $id; + } + + unset($values[$id]['tag-operations']); + } + + return $values; + } +} diff --git a/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php new file mode 100644 index 0000000000..f96c670ae9 --- /dev/null +++ b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php @@ -0,0 +1,149 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Traits\FilesystemTrait; +use Symfony\Component\Filesystem\Filesystem; + +/** + * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls. + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @experimental in 4.3 + */ +class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface +{ + use FilesystemTrait { + doSave as doSaveCache; + doDelete as doDeleteCache; + } + + /** + * Folder used for tag symlinks. + */ + private const TAG_FOLDER = 'tags'; + + /** + * @var Filesystem|null + */ + private $fs; + + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) + { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $removeTagData = []): array + { + $failed = $this->doSaveCache($values, $lifetime); + + $fs = $this->getFilesystem(); + // Add Tags as symlinks + foreach ($addTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + $file = $this->getFile($id); + $fs->symlink($file, $this->getFile($id, true, $tagFolder)); + } + } + + // Unlink removed Tags + $files = []; + foreach ($removeTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + $files[] = $this->getFile($id, false, $tagFolder); + } + } + $fs->remove($files); + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids, array $tagData = []): bool + { + $ok = $this->doDeleteCache($ids); + + // Remove tags + $files = []; + $fs = $this->getFilesystem(); + foreach ($tagData as $tagId => $idMap) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($idMap as $id) { + $files[] = $this->getFile($id, false, $tagFolder); + } + } + $fs->remove($files); + + return $ok; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + foreach ($tagIds as $tagId) { + $tagsFolder = $this->getTagFolder($tagId); + if (!file_exists($tagsFolder)) { + continue; + } + + foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS)) as $itemLink) { + if (!$itemLink->isLink()) { + throw new LogicException('Expected a (sym)link when iterating over tag folder, non link found: '.$itemLink); + } + + $valueFile = $itemLink->getRealPath(); + if ($valueFile && \file_exists($valueFile)) { + @unlink($valueFile); + } + + @unlink((string) $itemLink); + } + } + + return true; + } + + private function getFilesystem(): Filesystem + { + return $this->fs ?? $this->fs = new Filesystem(); + } + + private function getTagFolder(string $tagId): string + { + return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR; + } +} diff --git a/vendor/symfony/cache/Adapter/Psr16Adapter.php b/vendor/symfony/cache/Adapter/Psr16Adapter.php new file mode 100644 index 0000000000..a14ee082be --- /dev/null +++ b/vendor/symfony/cache/Adapter/Psr16Adapter.php @@ -0,0 +1,81 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ProxyTrait; + +/** + * Turns a PSR-16 cache into a PSR-6 one. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface +{ + use ProxyTrait; + + private $miss; + + public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0) + { + parent::__construct($namespace, $defaultLifetime); + + $this->pool = $pool; + $this->miss = new \stdClass(); + } + + /** + * {@inheritdoc} + */ + protected function doFetch(array $ids) + { + foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) { + if ($this->miss !== $value) { + yield $key => $value; + } + } + } + + /** + * {@inheritdoc} + */ + protected function doHave($id) + { + return $this->pool->has($id); + } + + /** + * {@inheritdoc} + */ + protected function doClear($namespace) + { + return $this->pool->clear(); + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids) + { + return $this->pool->deleteMultiple($ids); + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, $lifetime) + { + return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime); + } +} diff --git a/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php new file mode 100644 index 0000000000..4e09387213 --- /dev/null +++ b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php @@ -0,0 +1,209 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Predis; +use Predis\Connection\Aggregate\ClusterInterface; +use Predis\Response\Status; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Traits\RedisTrait; + +/** + * Stores tag id <> cache id relationship as a Redis Set, lookup on invalidation using sPOP. + * + * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even + * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache + * relationship survives eviction (cache cleanup when Redis runs out of memory). + * + * Requirements: + * - Server: Redis 3.2+ + * - Client: PHP Redis 3.1.3+ OR Predis + * - Redis Server(s) configured with any `volatile-*` eviction policy, OR `noeviction` if it will NEVER fill up memory + * + * Design limitations: + * - Max 2 billion cache keys per cache tag + * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 2 billion cache items as well + * + * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies. + * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype. + * @see https://redis.io/commands/spop Documentation for sPOP operation, capable of retriving AND emptying a Set at once. + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @experimental in 4.3 + */ +class RedisTagAwareAdapter extends AbstractTagAwareAdapter +{ + use RedisTrait; + + /** + * Redis "Set" can hold more than 4 billion members, here we limit ourselves to PHP's > 2 billion max int (32Bit). + */ + private const POP_MAX_LIMIT = 2147483647 - 1; + + /** + * Limits for how many keys are deleted in batch. + */ + private const BULK_DELETE_LIMIT = 10000; + + /** + * On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are + * preferred to be evicted over tag Sets, if eviction policy is configured according to requirements. + */ + private const DEFAULT_CACHE_TTL = 8640000; + + /** + * @var bool|null + */ + private $redisServerSupportSPOP = null; + + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient The redis client + * @param string $namespace The default namespace + * @param int $defaultLifetime The default lifetime + * @param MarshallerInterface|null $marshaller + * + * @throws \Symfony\Component\Cache\Exception\LogicException If phpredis with version lower than 3.1.3. + */ + public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) + { + $this->init($redisClient, $namespace, $defaultLifetime, $marshaller); + + // Make sure php-redis is 3.1.3 or higher configured for Redis classes + if (!$this->redis instanceof Predis\Client && \version_compare(\phpversion('redis'), '3.1.3', '<')) { + throw new LogicException('RedisTagAwareAdapter requires php-redis 3.1.3 or higher, alternatively use predis/predis'); + } + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $delTagData = []): array + { + // serialize values + if (!$serialized = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + // While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op + $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData) { + // Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one + foreach ($serialized as $id => $value) { + yield 'setEx' => [ + $id, + 0 >= $lifetime ? self::DEFAULT_CACHE_TTL : $lifetime, + $value, + ]; + } + + // Add and Remove Tags + foreach ($addTagData as $tagId => $ids) { + yield 'sAdd' => array_merge([$tagId], $ids); + } + + foreach ($delTagData as $tagId => $ids) { + yield 'sRem' => array_merge([$tagId], $ids); + } + }); + + foreach ($results as $id => $result) { + // Skip results of SADD/SREM operations, they'll be 1 or 0 depending on if set value already existed or not + if (\is_numeric($result)) { + continue; + } + // setEx results + if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) { + $failed[] = $id; + } + } + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids, array $tagData = []): bool + { + if (!$ids) { + return true; + } + + $predisCluster = $this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface; + $this->pipeline(static function () use ($ids, $tagData, $predisCluster) { + if ($predisCluster) { + foreach ($ids as $id) { + yield 'del' => [$id]; + } + } else { + yield 'del' => $ids; + } + + foreach ($tagData as $tagId => $idList) { + yield 'sRem' => \array_merge([$tagId], $idList); + } + })->rewind(); + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + if (!$this->redisServerSupportSPOP()) { + return false; + } + + // Pop all tag info at once to avoid race conditions + $tagIdSets = $this->pipeline(static function () use ($tagIds) { + foreach ($tagIds as $tagId) { + // Client: Predis or PHP Redis 3.1.3+ (https://github.com/phpredis/phpredis/commit/d2e203a6) + // Server: Redis 3.2 or higher (https://redis.io/commands/spop) + yield 'sPop' => [$tagId, self::POP_MAX_LIMIT]; + } + }); + + // Flatten generator result from pipeline, ignore keys (tag ids) + $ids = \array_unique(\array_merge(...\iterator_to_array($tagIdSets, false))); + + // Delete cache in chunks to avoid overloading the connection + foreach (\array_chunk($ids, self::BULK_DELETE_LIMIT) as $chunkIds) { + $this->doDelete($chunkIds); + } + + return true; + } + + private function redisServerSupportSPOP(): bool + { + if (null !== $this->redisServerSupportSPOP) { + return $this->redisServerSupportSPOP; + } + + foreach ($this->getHosts() as $host) { + $info = $host->info('Server'); + $info = isset($info['Server']) ? $info['Server'] : $info; + if (version_compare($info['redis_version'], '3.2', '<')) { + CacheItem::log($this->logger, 'Redis server needs to be version 3.2 or higher, your Redis server was detected as '.$info['redis_version']); + + return $this->redisServerSupportSPOP = false; + } + } + + return $this->redisServerSupportSPOP = true; + } +} diff --git a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php index 5a836a3dbf..d0d42e57f0 100644 --- a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php +++ b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php @@ -11,68 +11,11 @@ namespace Symfony\Component\Cache\Adapter; -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\Traits\ProxyTrait; +@trigger_error(sprintf('The "%s" class is @deprecated since Symfony 4.3, use "Psr16Adapter" instead.', SimpleCacheAdapter::class), E_USER_DEPRECATED); /** - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use Psr16Adapter instead. */ -class SimpleCacheAdapter extends AbstractAdapter implements PruneableInterface +class SimpleCacheAdapter extends Psr16Adapter { - use ProxyTrait; - - private $miss; - - public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0) - { - parent::__construct($namespace, $defaultLifetime); - - $this->pool = $pool; - $this->miss = new \stdClass(); - } - - /** - * {@inheritdoc} - */ - protected function doFetch(array $ids) - { - foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) { - if ($this->miss !== $value) { - yield $key => $value; - } - } - } - - /** - * {@inheritdoc} - */ - protected function doHave($id) - { - return $this->pool->has($id); - } - - /** - * {@inheritdoc} - */ - protected function doClear($namespace) - { - return $this->pool->clear(); - } - - /** - * {@inheritdoc} - */ - protected function doDelete(array $ids) - { - return $this->pool->deleteMultiple($ids); - } - - /** - * {@inheritdoc} - */ - protected function doSave(array $values, $lifetime) - { - return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime); - } } diff --git a/vendor/symfony/cache/CHANGELOG.md b/vendor/symfony/cache/CHANGELOG.md index 9016bc5dbf..37dd2e11a0 100644 --- a/vendor/symfony/cache/CHANGELOG.md +++ b/vendor/symfony/cache/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +4.3.0 +----- + + * removed `psr/simple-cache` dependency, run `composer require psr/simple-cache` if you need it + * deprecated all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead + * deprecated `SimpleCacheAdapter`, use `Psr16Adapter` instead + 4.2.0 ----- diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php index b1af39755e..5d7a2369c2 100644 --- a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php @@ -68,14 +68,20 @@ class CachePoolPass implements CompilerPassInterface if ($pool->isAbstract()) { continue; } + $class = $adapter->getClass(); while ($adapter instanceof ChildDefinition) { $adapter = $container->findDefinition($adapter->getParent()); + $class = $class ?: $adapter->getClass(); if ($t = $adapter->getTag($this->cachePoolTag)) { $tags[0] += $t[0]; } } $name = $tags[0]['name'] ?? $id; if (!isset($tags[0]['namespace'])) { + if (null !== $class) { + $seed .= '.'.$class; + } + $tags[0]['namespace'] = $this->getNamespace($seed, $name); } if (isset($tags[0]['clearer'])) { @@ -136,6 +142,10 @@ class CachePoolPass implements CompilerPassInterface $clearer->addTag($this->cacheSystemClearerTag); } } + + if ($container->hasDefinition('console.command.cache_pool_list')) { + $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($pools)); + } } private function getNamespace($seed, $id) diff --git a/vendor/symfony/cache/Exception/CacheException.php b/vendor/symfony/cache/Exception/CacheException.php index e87b2db8fe..d2e975b2bc 100644 --- a/vendor/symfony/cache/Exception/CacheException.php +++ b/vendor/symfony/cache/Exception/CacheException.php @@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception; use Psr\Cache\CacheException as Psr6CacheInterface; use Psr\SimpleCache\CacheException as SimpleCacheInterface; -class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface -{ +if (interface_exists(SimpleCacheInterface::class)) { + class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class CacheException extends \Exception implements Psr6CacheInterface + { + } } diff --git a/vendor/symfony/cache/Exception/InvalidArgumentException.php b/vendor/symfony/cache/Exception/InvalidArgumentException.php index 828bf3ed77..7f9584a264 100644 --- a/vendor/symfony/cache/Exception/InvalidArgumentException.php +++ b/vendor/symfony/cache/Exception/InvalidArgumentException.php @@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception; use Psr\Cache\InvalidArgumentException as Psr6CacheInterface; use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface; -class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface -{ +if (interface_exists(SimpleCacheInterface::class)) { + class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface + { + } } diff --git a/vendor/symfony/cache/Exception/LogicException.php b/vendor/symfony/cache/Exception/LogicException.php index d299673eb2..9ffa7ed695 100644 --- a/vendor/symfony/cache/Exception/LogicException.php +++ b/vendor/symfony/cache/Exception/LogicException.php @@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception; use Psr\Cache\CacheException as Psr6CacheInterface; use Psr\SimpleCache\CacheException as SimpleCacheInterface; -class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface -{ +if (interface_exists(SimpleCacheInterface::class)) { + class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class LogicException extends \LogicException implements Psr6CacheInterface + { + } } diff --git a/vendor/symfony/cache/LockRegistry.php b/vendor/symfony/cache/LockRegistry.php index ef49805ea0..676fba5dca 100644 --- a/vendor/symfony/cache/LockRegistry.php +++ b/vendor/symfony/cache/LockRegistry.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache; +use Psr\Log\LoggerInterface; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; @@ -33,19 +34,23 @@ final class LockRegistry */ private static $files = [ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractTagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AdapterInterface.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ApcuAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ArrayAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ChainAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpArrayAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpFilesAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ProxyAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'Psr16Adapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisTagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'SimpleCacheAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php', @@ -74,7 +79,7 @@ final class LockRegistry return $previousFiles; } - public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null) + public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null) { $key = self::$files ? crc32($item->getKey()) % \count(self::$files) : -1; @@ -86,6 +91,7 @@ final class LockRegistry try { // race to get the lock in non-blocking mode if (flock($lock, LOCK_EX | LOCK_NB)) { + $logger && $logger->info('Lock acquired, now computing item "{key}"', ['key' => $item->getKey()]); self::$lockedFiles[$key] = true; $value = $callback($item, $save); @@ -102,6 +108,7 @@ final class LockRegistry return $value; } // if we failed the race, retry locking in blocking mode to wait for the winner + $logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]); flock($lock, LOCK_SH); } finally { flock($lock, LOCK_UN); @@ -113,6 +120,7 @@ final class LockRegistry try { $value = $pool->get($item->getKey(), $signalingCallback, 0); + $logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]); $save = false; return $value; @@ -120,6 +128,7 @@ final class LockRegistry if ($signalingException !== $e) { throw $e; } + $logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]); } } } diff --git a/vendor/symfony/cache/Psr16Cache.php b/vendor/symfony/cache/Psr16Cache.php new file mode 100644 index 0000000000..589ffa0d8b --- /dev/null +++ b/vendor/symfony/cache/Psr16Cache.php @@ -0,0 +1,263 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +use Psr\Cache\CacheException as Psr6CacheException; +use Psr\Cache\CacheItemPoolInterface; +use Psr\SimpleCache\CacheException as SimpleCacheException; +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Traits\ProxyTrait; + +/** + * Turns a PSR-6 cache into a PSR-16 one. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterface +{ + use ProxyTrait; + + private const METADATA_EXPIRY_OFFSET = 1527506807; + + private $createCacheItem; + private $cacheItemPrototype; + + public function __construct(CacheItemPoolInterface $pool) + { + $this->pool = $pool; + + if (!$pool instanceof AdapterInterface) { + return; + } + $cacheItemPrototype = &$this->cacheItemPrototype; + $createCacheItem = \Closure::bind( + function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) { + $item = clone $cacheItemPrototype; + $item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key); + $item->value = $value; + $item->isHit = false; + + return $item; + }, + null, + CacheItem::class + ); + $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) { + if (null === $this->cacheItemPrototype) { + $this->get($allowInt && \is_int($key) ? (string) $key : $key); + } + $this->createCacheItem = $createCacheItem; + + return $createCacheItem($key, null, $allowInt)->set($value); + }; + } + + /** + * {@inheritdoc} + */ + public function get($key, $default = null) + { + try { + $item = $this->pool->getItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + if (null === $this->cacheItemPrototype) { + $this->cacheItemPrototype = clone $item; + $this->cacheItemPrototype->set(null); + } + + return $item->isHit() ? $item->get() : $default; + } + + /** + * {@inheritdoc} + */ + public function set($key, $value, $ttl = null) + { + try { + if (null !== $f = $this->createCacheItem) { + $item = $f($key, $value); + } else { + $item = $this->pool->getItem($key)->set($value); + } + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + if (null !== $ttl) { + $item->expiresAfter($ttl); + } + + return $this->pool->save($item); + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + try { + return $this->pool->deleteItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + */ + public function clear() + { + return $this->pool->clear(); + } + + /** + * {@inheritdoc} + */ + public function getMultiple($keys, $default = null) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!\is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys))); + } + + try { + $items = $this->pool->getItems($keys); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + $values = []; + + if (!$this->pool instanceof AdapterInterface) { + foreach ($items as $key => $item) { + $values[$key] = $item->isHit() ? $item->get() : $default; + } + + return $values; + } + + foreach ($items as $key => $item) { + if (!$item->isHit()) { + $values[$key] = $default; + continue; + } + $values[$key] = $item->get(); + + if (!$metadata = $item->getMetadata()) { + continue; + } + unset($metadata[CacheItem::METADATA_TAGS]); + + if ($metadata) { + $values[$key] = ["\x9D".pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]]; + } + } + + return $values; + } + + /** + * {@inheritdoc} + */ + public function setMultiple($values, $ttl = null) + { + $valuesIsArray = \is_array($values); + if (!$valuesIsArray && !$values instanceof \Traversable) { + throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values))); + } + $items = []; + + try { + if (null !== $f = $this->createCacheItem) { + $valuesIsArray = false; + foreach ($values as $key => $value) { + $items[$key] = $f($key, $value, true); + } + } elseif ($valuesIsArray) { + $items = []; + foreach ($values as $key => $value) { + $items[] = (string) $key; + } + $items = $this->pool->getItems($items); + } else { + foreach ($values as $key => $value) { + if (\is_int($key)) { + $key = (string) $key; + } + $items[$key] = $this->pool->getItem($key)->set($value); + } + } + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + $ok = true; + + foreach ($items as $key => $item) { + if ($valuesIsArray) { + $item->set($values[$key]); + } + if (null !== $ttl) { + $item->expiresAfter($ttl); + } + $ok = $this->pool->saveDeferred($item) && $ok; + } + + return $this->pool->commit() && $ok; + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple($keys) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!\is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys))); + } + + try { + return $this->pool->deleteItems($keys); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + */ + public function has($key) + { + try { + return $this->pool->hasItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/vendor/symfony/cache/Simple/AbstractCache.php b/vendor/symfony/cache/Simple/AbstractCache.php index 7a2a3cb36e..312a7dbfd0 100644 --- a/vendor/symfony/cache/Simple/AbstractCache.php +++ b/vendor/symfony/cache/Simple/AbstractCache.php @@ -12,16 +12,20 @@ namespace Symfony\Component\Cache\Simple; use Psr\Log\LoggerAwareInterface; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\AbstractTrait; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', AbstractCache::class, AbstractAdapter::class, CacheInterface::class), E_USER_DEPRECATED); /** - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use AbstractAdapter and type-hint for CacheInterface instead. */ -abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, ResettableInterface +abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface { use AbstractTrait { deleteItems as private; @@ -52,7 +56,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re return $value; } } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]); } return $default; @@ -86,7 +90,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re try { $values = $this->doFetch($ids); } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => $keys, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]); $values = []; } $ids = array_combine($ids, $keys); @@ -125,7 +129,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re foreach (\is_array($e) ? $e : array_keys($valuesById) as $id) { $keys[] = substr($id, \strlen($this->namespace)); } - CacheItem::log($this->logger, 'Failed to save values', ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]); + $message = 'Failed to save values'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]); return false; } @@ -171,7 +176,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re yield $key => $value; } } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => array_values($keys), 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]); } foreach ($keys as $key) { diff --git a/vendor/symfony/cache/Simple/ApcuCache.php b/vendor/symfony/cache/Simple/ApcuCache.php index 0877c394bb..c22771e822 100644 --- a/vendor/symfony/cache/Simple/ApcuCache.php +++ b/vendor/symfony/cache/Simple/ApcuCache.php @@ -13,6 +13,11 @@ namespace Symfony\Component\Cache\Simple; use Symfony\Component\Cache\Traits\ApcuTrait; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ApcuCache::class, ApcuAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use ApcuAdapter and type-hint for CacheInterface instead. + */ class ApcuCache extends AbstractCache { use ApcuTrait; diff --git a/vendor/symfony/cache/Simple/ArrayCache.php b/vendor/symfony/cache/Simple/ArrayCache.php index e36dacb829..3df5b4990c 100644 --- a/vendor/symfony/cache/Simple/ArrayCache.php +++ b/vendor/symfony/cache/Simple/ArrayCache.php @@ -12,16 +12,20 @@ namespace Symfony\Component\Cache\Simple; use Psr\Log\LoggerAwareInterface; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\ArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ArrayCache::class, ArrayAdapter::class, CacheInterface::class), E_USER_DEPRECATED); /** - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use ArrayAdapter and type-hint for CacheInterface instead. */ -class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInterface +class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface { use ArrayTrait { ArrayTrait::deleteItem as delete; diff --git a/vendor/symfony/cache/Simple/ChainCache.php b/vendor/symfony/cache/Simple/ChainCache.php index 18e9462ba0..a0122fdee9 100644 --- a/vendor/symfony/cache/Simple/ChainCache.php +++ b/vendor/symfony/cache/Simple/ChainCache.php @@ -11,21 +11,25 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\ChainAdapter; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Service\ResetInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ChainCache::class, ChainAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + /** * Chains several caches together. * * Cached items are fetched from the first cache having them in its data store. * They are saved and deleted in all caches at once. * - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use ChainAdapter and type-hint for CacheInterface instead. */ -class ChainCache implements CacheInterface, PruneableInterface, ResettableInterface +class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface { private $miss; private $caches = []; @@ -33,8 +37,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf private $cacheCount; /** - * @param CacheInterface[] $caches The ordered list of caches used to fetch cached items - * @param int $defaultLifetime The lifetime of items propagated from lower caches to upper ones + * @param Psr16CacheInterface[] $caches The ordered list of caches used to fetch cached items + * @param int $defaultLifetime The lifetime of items propagated from lower caches to upper ones */ public function __construct(array $caches, int $defaultLifetime = 0) { @@ -43,8 +47,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf } foreach ($caches as $cache) { - if (!$cache instanceof CacheInterface) { - throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), CacheInterface::class)); + if (!$cache instanceof Psr16CacheInterface) { + throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), Psr16CacheInterface::class)); } } diff --git a/vendor/symfony/cache/Simple/DoctrineCache.php b/vendor/symfony/cache/Simple/DoctrineCache.php index 0ba701d7cd..6a6d003153 100644 --- a/vendor/symfony/cache/Simple/DoctrineCache.php +++ b/vendor/symfony/cache/Simple/DoctrineCache.php @@ -12,8 +12,15 @@ namespace Symfony\Component\Cache\Simple; use Doctrine\Common\Cache\CacheProvider; +use Symfony\Component\Cache\Adapter\DoctrineAdapter; use Symfony\Component\Cache\Traits\DoctrineTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', DoctrineCache::class, DoctrineAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use DoctrineAdapter and type-hint for CacheInterface instead. + */ class DoctrineCache extends AbstractCache { use DoctrineTrait; diff --git a/vendor/symfony/cache/Simple/FilesystemCache.php b/vendor/symfony/cache/Simple/FilesystemCache.php index 8e04d53355..8891abd94c 100644 --- a/vendor/symfony/cache/Simple/FilesystemCache.php +++ b/vendor/symfony/cache/Simple/FilesystemCache.php @@ -11,11 +11,18 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Marshaller\DefaultMarshaller; use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\FilesystemTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', FilesystemCache::class, FilesystemAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use FilesystemAdapter and type-hint for CacheInterface instead. + */ class FilesystemCache extends AbstractCache implements PruneableInterface { use FilesystemTrait; diff --git a/vendor/symfony/cache/Simple/MemcachedCache.php b/vendor/symfony/cache/Simple/MemcachedCache.php index 8e418b071e..e1934119aa 100644 --- a/vendor/symfony/cache/Simple/MemcachedCache.php +++ b/vendor/symfony/cache/Simple/MemcachedCache.php @@ -11,9 +11,16 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\MemcachedAdapter; use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\MemcachedTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', MemcachedCache::class, MemcachedAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use MemcachedAdapter and type-hint for CacheInterface instead. + */ class MemcachedCache extends AbstractCache { use MemcachedTrait; diff --git a/vendor/symfony/cache/Simple/NullCache.php b/vendor/symfony/cache/Simple/NullCache.php index fa986aebd1..d1ca6f7187 100644 --- a/vendor/symfony/cache/Simple/NullCache.php +++ b/vendor/symfony/cache/Simple/NullCache.php @@ -11,12 +11,16 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Components\Cache\Adapter\NullAdapter; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', NullCache::class, NullAdapter::class, CacheInterface::class), E_USER_DEPRECATED); /** - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use NullAdapter and type-hint for CacheInterface instead. */ -class NullCache implements CacheInterface +class NullCache implements Psr16CacheInterface { /** * {@inheritdoc} diff --git a/vendor/symfony/cache/Simple/PdoCache.php b/vendor/symfony/cache/Simple/PdoCache.php index 521e9b8f2d..07849e93fe 100644 --- a/vendor/symfony/cache/Simple/PdoCache.php +++ b/vendor/symfony/cache/Simple/PdoCache.php @@ -11,10 +11,17 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\PdoAdapter; use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\PdoTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PdoCache::class, PdoAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use PdoAdapter and type-hint for CacheInterface instead. + */ class PdoCache extends AbstractCache implements PruneableInterface { use PdoTrait; diff --git a/vendor/symfony/cache/Simple/PhpArrayCache.php b/vendor/symfony/cache/Simple/PhpArrayCache.php index 6ba8527885..566609359d 100644 --- a/vendor/symfony/cache/Simple/PhpArrayCache.php +++ b/vendor/symfony/cache/Simple/PhpArrayCache.php @@ -11,28 +11,28 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\PhpArrayAdapter; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\PhpArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PhpArrayCache::class, PhpArrayAdapter::class, CacheInterface::class), E_USER_DEPRECATED); /** - * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0. - * Warmed up items are read-only and run-time discovered items are cached using a fallback adapter. - * - * @author Titouan Galopin <galopintitouan@gmail.com> - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use PhpArrayAdapter and type-hint for CacheInterface instead. */ -class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInterface +class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface { use PhpArrayTrait; /** - * @param string $file The PHP file were values are cached - * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit + * @param string $file The PHP file were values are cached + * @param Psr16CacheInterface $fallbackPool A pool to fallback on when an item is not hit */ - public function __construct(string $file, CacheInterface $fallbackPool) + public function __construct(string $file, Psr16CacheInterface $fallbackPool) { $this->file = $file; $this->pool = $fallbackPool; @@ -43,9 +43,9 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt * * @param string $file The PHP file were values are cached * - * @return CacheInterface + * @return Psr16CacheInterface */ - public static function create($file, CacheInterface $fallbackPool) + public static function create($file, Psr16CacheInterface $fallbackPool) { // Shared memory is available in PHP 7.0+ with OPCache enabled if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) { diff --git a/vendor/symfony/cache/Simple/PhpFilesCache.php b/vendor/symfony/cache/Simple/PhpFilesCache.php index 37432c5af8..060244a086 100644 --- a/vendor/symfony/cache/Simple/PhpFilesCache.php +++ b/vendor/symfony/cache/Simple/PhpFilesCache.php @@ -11,10 +11,17 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\PhpFilesAdapter; use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\PhpFilesTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PhpFilesCache::class, PhpFilesAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use PhpFilesAdapter and type-hint for CacheInterface instead. + */ class PhpFilesCache extends AbstractCache implements PruneableInterface { use PhpFilesTrait; diff --git a/vendor/symfony/cache/Simple/Psr6Cache.php b/vendor/symfony/cache/Simple/Psr6Cache.php index fceb9ba70f..090f48c172 100644 --- a/vendor/symfony/cache/Simple/Psr6Cache.php +++ b/vendor/symfony/cache/Simple/Psr6Cache.php @@ -11,254 +11,13 @@ namespace Symfony\Component\Cache\Simple; -use Psr\Cache\CacheException as Psr6CacheException; -use Psr\Cache\CacheItemPoolInterface; -use Psr\SimpleCache\CacheException as SimpleCacheException; -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\Adapter\AdapterInterface; -use Symfony\Component\Cache\CacheItem; -use Symfony\Component\Cache\Exception\InvalidArgumentException; -use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\ResettableInterface; -use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Component\Cache\Psr16Cache; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', Psr6Cache::class, Psr16Cache::class), E_USER_DEPRECATED); /** - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use Psr16Cache instead. */ -class Psr6Cache implements CacheInterface, PruneableInterface, ResettableInterface +class Psr6Cache extends Psr16Cache { - use ProxyTrait; - - private const METADATA_EXPIRY_OFFSET = 1527506807; - - private $createCacheItem; - private $cacheItemPrototype; - - public function __construct(CacheItemPoolInterface $pool) - { - $this->pool = $pool; - - if (!$pool instanceof AdapterInterface) { - return; - } - $cacheItemPrototype = &$this->cacheItemPrototype; - $createCacheItem = \Closure::bind( - function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) { - $item = clone $cacheItemPrototype; - $item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key); - $item->value = $value; - $item->isHit = false; - - return $item; - }, - null, - CacheItem::class - ); - $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) { - if (null === $this->cacheItemPrototype) { - $this->get($allowInt && \is_int($key) ? (string) $key : $key); - } - $this->createCacheItem = $createCacheItem; - - return $createCacheItem($key, null, $allowInt)->set($value); - }; - } - - /** - * {@inheritdoc} - */ - public function get($key, $default = null) - { - try { - $item = $this->pool->getItem($key); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - if (null === $this->cacheItemPrototype) { - $this->cacheItemPrototype = clone $item; - $this->cacheItemPrototype->set(null); - } - - return $item->isHit() ? $item->get() : $default; - } - - /** - * {@inheritdoc} - */ - public function set($key, $value, $ttl = null) - { - try { - if (null !== $f = $this->createCacheItem) { - $item = $f($key, $value); - } else { - $item = $this->pool->getItem($key)->set($value); - } - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - if (null !== $ttl) { - $item->expiresAfter($ttl); - } - - return $this->pool->save($item); - } - - /** - * {@inheritdoc} - */ - public function delete($key) - { - try { - return $this->pool->deleteItem($key); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function clear() - { - return $this->pool->clear(); - } - - /** - * {@inheritdoc} - */ - public function getMultiple($keys, $default = null) - { - if ($keys instanceof \Traversable) { - $keys = iterator_to_array($keys, false); - } elseif (!\is_array($keys)) { - throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys))); - } - - try { - $items = $this->pool->getItems($keys); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - $values = []; - - if (!$this->pool instanceof AdapterInterface) { - foreach ($items as $key => $item) { - $values[$key] = $item->isHit() ? $item->get() : $default; - } - - return $values; - } - - foreach ($items as $key => $item) { - if (!$item->isHit()) { - $values[$key] = $default; - continue; - } - $values[$key] = $item->get(); - - if (!$metadata = $item->getMetadata()) { - continue; - } - unset($metadata[CacheItem::METADATA_TAGS]); - - if ($metadata) { - $values[$key] = ["\x9D".pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]]; - } - } - - return $values; - } - - /** - * {@inheritdoc} - */ - public function setMultiple($values, $ttl = null) - { - $valuesIsArray = \is_array($values); - if (!$valuesIsArray && !$values instanceof \Traversable) { - throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values))); - } - $items = []; - - try { - if (null !== $f = $this->createCacheItem) { - $valuesIsArray = false; - foreach ($values as $key => $value) { - $items[$key] = $f($key, $value, true); - } - } elseif ($valuesIsArray) { - $items = []; - foreach ($values as $key => $value) { - $items[] = (string) $key; - } - $items = $this->pool->getItems($items); - } else { - foreach ($values as $key => $value) { - if (\is_int($key)) { - $key = (string) $key; - } - $items[$key] = $this->pool->getItem($key)->set($value); - } - } - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - $ok = true; - - foreach ($items as $key => $item) { - if ($valuesIsArray) { - $item->set($values[$key]); - } - if (null !== $ttl) { - $item->expiresAfter($ttl); - } - $ok = $this->pool->saveDeferred($item) && $ok; - } - - return $this->pool->commit() && $ok; - } - - /** - * {@inheritdoc} - */ - public function deleteMultiple($keys) - { - if ($keys instanceof \Traversable) { - $keys = iterator_to_array($keys, false); - } elseif (!\is_array($keys)) { - throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys))); - } - - try { - return $this->pool->deleteItems($keys); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function has($key) - { - try { - return $this->pool->hasItem($key); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - } } diff --git a/vendor/symfony/cache/Simple/RedisCache.php b/vendor/symfony/cache/Simple/RedisCache.php index df2a96e86b..2933bf15b3 100644 --- a/vendor/symfony/cache/Simple/RedisCache.php +++ b/vendor/symfony/cache/Simple/RedisCache.php @@ -11,9 +11,16 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\RedisTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', RedisCache::class, RedisAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use RedisAdapter and type-hint for CacheInterface instead. + */ class RedisCache extends AbstractCache { use RedisTrait; diff --git a/vendor/symfony/cache/Simple/TraceableCache.php b/vendor/symfony/cache/Simple/TraceableCache.php index 2db335ac96..ad9bfcf09c 100644 --- a/vendor/symfony/cache/Simple/TraceableCache.php +++ b/vendor/symfony/cache/Simple/TraceableCache.php @@ -11,23 +11,24 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Service\ResetInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', TraceableCache::class, TraceableAdapter::class, CacheInterface::class), E_USER_DEPRECATED); + /** - * An adapter that collects data about all cache calls. - * - * @author Nicolas Grekas <p@tchwork.com> + * @deprecated since Symfony 4.3, use TraceableAdapter and type-hint for CacheInterface instead. */ -class TraceableCache implements CacheInterface, PruneableInterface, ResettableInterface +class TraceableCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface { private $pool; private $miss; private $calls = []; - public function __construct(CacheInterface $pool) + public function __construct(Psr16CacheInterface $pool) { $this->pool = $pool; $this->miss = new \stdClass(); diff --git a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php b/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php index 0eceb6e572..2b66d2bea0 100644 --- a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php +++ b/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php @@ -59,6 +59,26 @@ abstract class AdapterTestCase extends CachePoolTest $this->assertFalse($isHit); } + public function testRecursiveGet() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createCachePool(0, __FUNCTION__); + + $v = $cache->get('k1', function () use (&$counter, $cache) { + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + + return $v; + }); + + $this->assertSame(1, $counter); + $this->assertSame(1, $v); + $this->assertSame(1, $cache->get('k2', function () { return 2; })); + } + public function testGetMetadata() { if (isset($this->skippedTests[__FUNCTION__])) { @@ -215,14 +235,9 @@ abstract class AdapterTestCase extends CachePoolTest } } -class NotUnserializable implements \Serializable +class NotUnserializable { - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) + public function __wakeup() { throw new \Exception(__CLASS__); } diff --git a/vendor/symfony/cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php new file mode 100644 index 0000000000..83a7ea52dd --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php @@ -0,0 +1,28 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\FilesystemTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +/** + * @group time-sensitive + */ +class FilesystemTagAwareAdapterTest extends FilesystemAdapterTest +{ + use TagAwareTestTrait; + + public function createCachePool($defaultLifetime = 0) + { + return new FilesystemTagAwareAdapter('', $defaultLifetime); + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php index cee80ac196..3a5904b107 100644 --- a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -23,6 +23,7 @@ class PhpArrayAdapterTest extends AdapterTestCase { protected $skippedTests = [ 'testGet' => 'PhpArrayAdapter is read-only.', + 'testRecursiveGet' => 'PhpArrayAdapter is read-only.', 'testBasicUsage' => 'PhpArrayAdapter is read-only.', 'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.', 'testClear' => 'PhpArrayAdapter is read-only.', diff --git a/vendor/symfony/cache/Tests/Adapter/PredisTagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareAdapterTest.php new file mode 100644 index 0000000000..e321a1c9b8 --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareAdapterTest extends PredisAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php new file mode 100644 index 0000000000..a8a72e1de4 --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareClusterAdapterTest extends PredisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php new file mode 100644 index 0000000000..5b82a80ecb --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareRedisClusterAdapterTest extends PredisRedisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/Psr16AdapterTest.php b/vendor/symfony/cache/Tests/Adapter/Psr16AdapterTest.php new file mode 100644 index 0000000000..19907ddf78 --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/Psr16AdapterTest.php @@ -0,0 +1,31 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\Adapter\Psr16Adapter; +use Symfony\Component\Cache\Psr16Cache; + +/** + * @group time-sensitive + */ +class Psr16AdapterTest extends AdapterTestCase +{ + protected $skippedTests = [ + 'testPrune' => 'Psr16adapter just proxies', + ]; + + public function createCachePool($defaultLifetime = 0) + { + return new Psr16Adapter(new Psr16Cache(new FilesystemAdapter()), '', $defaultLifetime); + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php index c83abaf91b..4d9bc319eb 100644 --- a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php @@ -31,30 +31,33 @@ class RedisAdapterTest extends AbstractRedisAdapterTest return $adapter; } - public function testCreateConnection() + /** + * @dataProvider provideValidSchemes + */ + public function testCreateConnection($dsnScheme) { - $redis = RedisAdapter::createConnection('redis:?host[h1]&host[h2]&host[/foo:]'); + $redis = RedisAdapter::createConnection($dsnScheme.':?host[h1]&host[h2]&host[/foo:]'); $this->assertInstanceOf(\RedisArray::class, $redis); $this->assertSame(['h1:6379', 'h2:6379', '/foo'], $redis->_hosts()); @$redis = null; // some versions of phpredis connect on destruct, let's silence the warning $redisHost = getenv('REDIS_HOST'); - $redis = RedisAdapter::createConnection('redis://'.$redisHost); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost); $this->assertInstanceOf(\Redis::class, $redis); $this->assertTrue($redis->isConnected()); $this->assertSame(0, $redis->getDbNum()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'/2'); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost.'/2'); $this->assertSame(2, $redis->getDbNum()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['timeout' => 3]); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost, ['timeout' => 3]); $this->assertEquals(3, $redis->getTimeout()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'?timeout=4'); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost.'?timeout=4'); $this->assertEquals(4, $redis->getTimeout()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['read_timeout' => 5]); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost, ['read_timeout' => 5]); $this->assertEquals(5, $redis->getReadTimeout()); } @@ -87,6 +90,14 @@ class RedisAdapterTest extends AbstractRedisAdapterTest RedisAdapter::createConnection($dsn); } + public function provideValidSchemes() + { + return [ + ['redis'], + ['rediss'], + ]; + } + public function provideInvalidCreateConnection() { return [ diff --git a/vendor/symfony/cache/Tests/Adapter/RedisTagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareAdapterTest.php new file mode 100644 index 0000000000..95e5fe7e3a --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareAdapterTest.php @@ -0,0 +1,35 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; +use Symfony\Component\Cache\Traits\RedisProxy; + +class RedisTagAwareAdapterTest extends RedisAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(RedisProxy::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php new file mode 100644 index 0000000000..5855cc3adf --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class RedisTagAwareArrayAdapterTest extends RedisArrayAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\RedisArray::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php new file mode 100644 index 0000000000..ef17c1d69e --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php @@ -0,0 +1,35 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; +use Symfony\Component\Cache\Traits\RedisClusterProxy; + +class RedisTagAwareClusterAdapterTest extends RedisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(RedisClusterProxy::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php index 3028af47c6..b11f72d5a3 100644 --- a/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Cache\Tests\Adapter; -use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\SimpleCacheAdapter; -use Symfony\Component\Cache\Simple\Psr6Cache; +use Symfony\Component\Cache\Simple\FilesystemCache; /** * @group time-sensitive + * @group legacy */ class SimpleCacheAdapterTest extends AdapterTestCase { @@ -26,6 +26,6 @@ class SimpleCacheAdapterTest extends AdapterTestCase public function createCachePool($defaultLifetime = 0) { - return new SimpleCacheAdapter(new Psr6Cache(new FilesystemAdapter()), '', $defaultLifetime); + return new SimpleCacheAdapter(new FilesystemCache(), '', $defaultLifetime); } } diff --git a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php index 7b8895b700..a339790862 100644 --- a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php @@ -14,13 +14,15 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\TagAwareAdapter; -use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; /** * @group time-sensitive */ class TagAwareAdapterTest extends AdapterTestCase { + use TagAwareTestTrait; + public function createCachePool($defaultLifetime = 0) { return new TagAwareAdapter(new FilesystemAdapter('', $defaultLifetime)); @@ -32,53 +34,9 @@ class TagAwareAdapterTest extends AdapterTestCase } /** - * @expectedException \Psr\Cache\InvalidArgumentException + * Test feature specific to TagAwareAdapter as it implicit needs to save deferred when also saving expiry info. */ - public function testInvalidTag() - { - $pool = $this->createCachePool(); - $item = $pool->getItem('foo'); - $item->tag(':'); - } - - public function testInvalidateTags() - { - $pool = $this->createCachePool(); - - $i0 = $pool->getItem('i0'); - $i1 = $pool->getItem('i1'); - $i2 = $pool->getItem('i2'); - $i3 = $pool->getItem('i3'); - $foo = $pool->getItem('foo'); - - $pool->save($i0->tag('bar')); - $pool->save($i1->tag('foo')); - $pool->save($i2->tag('foo')->tag('bar')); - $pool->save($i3->tag('foo')->tag('baz')); - $pool->save($foo); - - $pool->invalidateTags(['bar']); - - $this->assertFalse($pool->getItem('i0')->isHit()); - $this->assertTrue($pool->getItem('i1')->isHit()); - $this->assertFalse($pool->getItem('i2')->isHit()); - $this->assertTrue($pool->getItem('i3')->isHit()); - $this->assertTrue($pool->getItem('foo')->isHit()); - - $pool->invalidateTags(['foo']); - - $this->assertFalse($pool->getItem('i1')->isHit()); - $this->assertFalse($pool->getItem('i3')->isHit()); - $this->assertTrue($pool->getItem('foo')->isHit()); - - $anotherPoolInstance = $this->createCachePool(); - - $this->assertFalse($anotherPoolInstance->getItem('i1')->isHit()); - $this->assertFalse($anotherPoolInstance->getItem('i3')->isHit()); - $this->assertTrue($anotherPoolInstance->getItem('foo')->isHit()); - } - - public function testInvalidateCommits() + public function testInvalidateCommitsSeperatePools() { $pool1 = $this->createCachePool(); @@ -94,76 +52,6 @@ class TagAwareAdapterTest extends AdapterTestCase $this->assertTrue($foo->isHit()); } - public function testTagsAreCleanedOnSave() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $pool->save($i->tag('bar')); - - $pool->invalidateTags(['foo']); - $this->assertTrue($pool->getItem('k')->isHit()); - } - - public function testTagsAreCleanedOnDelete() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - $pool->deleteItem('k'); - - $pool->save($pool->getItem('k')); - $pool->invalidateTags(['foo']); - - $this->assertTrue($pool->getItem('k')->isHit()); - } - - public function testTagItemExpiry() - { - $pool = $this->createCachePool(10); - - $item = $pool->getItem('foo'); - $item->tag(['baz']); - $item->expiresAfter(100); - - $pool->save($item); - $pool->invalidateTags(['baz']); - $this->assertFalse($pool->getItem('foo')->isHit()); - - sleep(20); - - $this->assertFalse($pool->getItem('foo')->isHit()); - } - - /** - * @group legacy - */ - public function testGetPreviousTags() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $this->assertSame(['foo' => 'foo'], $i->getPreviousTags()); - } - - public function testGetMetadata() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $this->assertSame(['foo' => 'foo'], $i->getMetadata()[CacheItem::METADATA_TAGS]); - } - public function testPrune() { $cache = new TagAwareAdapter($this->getPruneableMock()); diff --git a/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php index f307aa5386..4681b3dc81 100644 --- a/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php +++ b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\DependencyInjection\CachePoolPass; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -48,6 +49,27 @@ class CachePoolPassTest extends TestCase $this->assertSame('z3X945Jbf5', $cachePool->getArgument(0)); } + public function testNamespaceArgumentIsSeededWithAdapterClassName() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('kernel.project_dir', 'foo'); + $adapter = new Definition(); + $adapter->setAbstract(true); + $adapter->addTag('cache.pool'); + $adapter->setClass(RedisAdapter::class); + $container->setDefinition('app.cache_adapter', $adapter); + $container->setAlias('app.cache_adapter_alias', 'app.cache_adapter'); + $cachePool = new ChildDefinition('app.cache_adapter_alias'); + $cachePool->addArgument(null); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + + $this->assertSame('xmOJ8gqF-Y', $cachePool->getArgument(0)); + } + public function testNamespaceArgumentIsNotReplacedIfArrayAdapterIsUsed() { $container = new ContainerBuilder(); diff --git a/vendor/symfony/cache/Tests/Psr16CacheTest.php b/vendor/symfony/cache/Tests/Psr16CacheTest.php new file mode 100644 index 0000000000..e56d99e441 --- /dev/null +++ b/vendor/symfony/cache/Tests/Psr16CacheTest.php @@ -0,0 +1,168 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests; + +use Cache\IntegrationTests\SimpleCacheTest; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Psr16Cache; + +/** + * @group time-sensitive + */ +class Psr16CacheTest extends SimpleCacheTest +{ + protected function setUp() + { + parent::setUp(); + + if (\array_key_exists('testPrune', $this->skippedTests)) { + return; + } + + $pool = $this->createSimpleCache(); + if ($pool instanceof Psr16Cache) { + $pool = ((array) $pool)[sprintf("\0%s\0pool", Psr16Cache::class)]; + } + + if (!$pool instanceof PruneableInterface) { + $this->skippedTests['testPrune'] = 'Not a pruneable cache pool.'; + } + } + + public function createSimpleCache($defaultLifetime = 0) + { + return new Psr16Cache(new FilesystemAdapter('', $defaultLifetime)); + } + + public static function validKeys() + { + return array_merge(parent::validKeys(), [["a\0b"]]); + } + + public function testDefaultLifeTime() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createSimpleCache(2); + $cache->clear(); + + $cache->set('key.dlt', 'value'); + sleep(1); + + $this->assertSame('value', $cache->get('key.dlt')); + + sleep(2); + $this->assertNull($cache->get('key.dlt')); + + $cache->clear(); + } + + public function testNotUnserializable() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createSimpleCache(); + $cache->clear(); + + $cache->set('foo', new NotUnserializable()); + + $this->assertNull($cache->get('foo')); + + $cache->setMultiple(['foo' => new NotUnserializable()]); + + foreach ($cache->getMultiple(['foo']) as $value) { + } + $this->assertNull($value); + + $cache->clear(); + } + + public function testPrune() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + /** @var PruneableInterface|CacheInterface $cache */ + $cache = $this->createSimpleCache(); + $cache->clear(); + + $cache->set('foo', 'foo-val', new \DateInterval('PT05S')); + $cache->set('bar', 'bar-val', new \DateInterval('PT10S')); + $cache->set('baz', 'baz-val', new \DateInterval('PT15S')); + $cache->set('qux', 'qux-val', new \DateInterval('PT20S')); + + sleep(30); + $cache->prune(); + $this->assertTrue($this->isPruned($cache, 'foo')); + $this->assertTrue($this->isPruned($cache, 'bar')); + $this->assertTrue($this->isPruned($cache, 'baz')); + $this->assertTrue($this->isPruned($cache, 'qux')); + + $cache->set('foo', 'foo-val'); + $cache->set('bar', 'bar-val', new \DateInterval('PT20S')); + $cache->set('baz', 'baz-val', new \DateInterval('PT40S')); + $cache->set('qux', 'qux-val', new \DateInterval('PT80S')); + + $cache->prune(); + $this->assertFalse($this->isPruned($cache, 'foo')); + $this->assertFalse($this->isPruned($cache, 'bar')); + $this->assertFalse($this->isPruned($cache, 'baz')); + $this->assertFalse($this->isPruned($cache, 'qux')); + + sleep(30); + $cache->prune(); + $this->assertFalse($this->isPruned($cache, 'foo')); + $this->assertTrue($this->isPruned($cache, 'bar')); + $this->assertFalse($this->isPruned($cache, 'baz')); + $this->assertFalse($this->isPruned($cache, 'qux')); + + sleep(30); + $cache->prune(); + $this->assertFalse($this->isPruned($cache, 'foo')); + $this->assertTrue($this->isPruned($cache, 'baz')); + $this->assertFalse($this->isPruned($cache, 'qux')); + + sleep(30); + $cache->prune(); + $this->assertFalse($this->isPruned($cache, 'foo')); + $this->assertTrue($this->isPruned($cache, 'qux')); + + $cache->clear(); + } + + protected function isPruned($cache, $name) + { + if (Psr16Cache::class !== \get_class($cache)) { + $this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.'); + } + + $pool = ((array) $cache)[sprintf("\0%s\0pool", Psr16Cache::class)]; + $getFileMethod = (new \ReflectionObject($pool))->getMethod('getFile'); + $getFileMethod->setAccessible(true); + + return !file_exists($getFileMethod->invoke($pool, $name)); + } +} + +class NotUnserializable +{ + public function __wakeup() + { + throw new \Exception(__CLASS__); + } +} diff --git a/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php b/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php index dd5e1509c1..a9f5d98b92 100644 --- a/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\RedisCache; +/** + * @group legacy + */ abstract class AbstractRedisCacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php b/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php index f37b95a093..b322094603 100644 --- a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\ApcuCache; +/** + * @group legacy + */ class ApcuCacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php index 26c3e14d09..587304a5db 100644 --- a/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Cache\Simple\ArrayCache; /** * @group time-sensitive + * @group legacy */ class ArrayCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php b/vendor/symfony/cache/Tests/Simple/CacheTestCase.php index 3c8824869b..d4b3d07f62 100644 --- a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php +++ b/vendor/symfony/cache/Tests/Simple/CacheTestCase.php @@ -132,14 +132,9 @@ abstract class CacheTestCase extends SimpleCacheTest } } -class NotUnserializable implements \Serializable +class NotUnserializable { - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) + public function __wakeup() { throw new \Exception(__CLASS__); } diff --git a/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php b/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php index e6f7c7cc63..806bb7633b 100644 --- a/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Cache\Simple\FilesystemCache; /** * @group time-sensitive + * @group legacy */ class ChainCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php b/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php index af4331d69b..5d78c00cac 100644 --- a/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Tests\Fixtures\ArrayCache; /** * @group time-sensitive + * @group legacy */ class DoctrineCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php b/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php index 620305a58a..9f423ba641 100644 --- a/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\FilesystemCache; /** * @group time-sensitive + * @group legacy */ class FilesystemCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php index f83f0a2e34..692259296f 100644 --- a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php @@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Simple\MemcachedCache; +/** + * @group legacy + */ class MemcachedCacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php index 13865a6098..d68131a1db 100644 --- a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php +++ b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php @@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Simple\MemcachedCache; +/** + * @group legacy + */ class MemcachedCacheTextModeTest extends MemcachedCacheTest { public function createSimpleCache($defaultLifetime = 0) diff --git a/vendor/symfony/cache/Tests/Simple/NullCacheTest.php b/vendor/symfony/cache/Tests/Simple/NullCacheTest.php index 31f42c32b6..cf0dde92b3 100644 --- a/vendor/symfony/cache/Tests/Simple/NullCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/NullCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\NullCache; /** * @group time-sensitive + * @group legacy */ class NullCacheTest extends TestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php b/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php index 665db09f67..fbdf03be7e 100644 --- a/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; /** * @group time-sensitive + * @group legacy */ class PdoCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php b/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php index ce1a9ae4f8..af5c42340b 100644 --- a/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; /** * @group time-sensitive + * @group legacy */ class PdoDbalCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php index ba4bde3139..5272604dc3 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest; /** * @group time-sensitive + * @group legacy */ class PhpArrayCacheTest extends CacheTestCase { @@ -127,35 +128,3 @@ class PhpArrayCacheTest extends CacheTestCase $this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory'); } } - -class PhpArrayCacheWrapper extends PhpArrayCache -{ - protected $data = []; - - public function set($key, $value, $ttl = null) - { - (\Closure::bind(function () use ($key, $value) { - $this->data[$key] = $value; - $this->warmUp($this->data); - list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayCache::class))(); - - return true; - } - - public function setMultiple($values, $ttl = null) - { - if (!\is_array($values) && !$values instanceof \Traversable) { - return parent::setMultiple($values, $ttl); - } - (\Closure::bind(function () use ($values) { - foreach ($values as $key => $value) { - $this->data[$key] = $value; - } - $this->warmUp($this->data); - list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayCache::class))(); - - return true; - } -} diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php index abee5e7872..90aa7bb6ef 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest; /** * @group time-sensitive + * @group legacy */ class PhpArrayCacheWithFallbackTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWrapper.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWrapper.php new file mode 100644 index 0000000000..1e102fe1ff --- /dev/null +++ b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWrapper.php @@ -0,0 +1,46 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Simple; + +use Symfony\Component\Cache\Simple\PhpArrayCache; + +class PhpArrayCacheWrapper extends PhpArrayCache +{ + protected $data = []; + + public function set($key, $value, $ttl = null) + { + (\Closure::bind(function () use ($key, $value) { + $this->data[$key] = $value; + $this->warmUp($this->data); + list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); + }, $this, PhpArrayCache::class))(); + + return true; + } + + public function setMultiple($values, $ttl = null) + { + if (!\is_array($values) && !$values instanceof \Traversable) { + return parent::setMultiple($values, $ttl); + } + (\Closure::bind(function () use ($values) { + foreach ($values as $key => $value) { + $this->data[$key] = $value; + } + $this->warmUp($this->data); + list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); + }, $this, PhpArrayCache::class))(); + + return true; + } +} diff --git a/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php b/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php index 3a68dd3984..7e40df7de5 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\PhpFilesCache; /** * @group time-sensitive + * @group legacy */ class PhpFilesCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php b/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php index 65d48a978c..9fff36e402 100644 --- a/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\Psr6Cache; +/** + * @group legacy + */ abstract class Psr6CacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php index 46da9354d6..e5c7a6a4c7 100644 --- a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php +++ b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Cache\Adapter\FilesystemAdapter; /** * @group time-sensitive + * @group legacy */ class Psr6CacheWithAdapterTest extends Psr6CacheTest { diff --git a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php index a8c4164dcb..f987d40539 100644 --- a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php +++ b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter; /** * @group time-sensitive + * @group legacy */ class Psr6CacheWithoutAdapterTest extends Psr6CacheTest { diff --git a/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php index bda39d990b..b52f5f9acd 100644 --- a/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Cache\Tests\Simple; +/** + * @group legacy + */ class RedisArrayCacheTest extends AbstractRedisCacheTest { public static function setupBeforeClass() diff --git a/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php index 407d916c73..ddb674b285 100644 --- a/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\RedisCache; +/** + * @group legacy + */ class RedisCacheTest extends AbstractRedisCacheTest { public static function setupBeforeClass() diff --git a/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php index 99d4e518fb..33c7acae0b 100644 --- a/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Cache\Tests\Simple; +/** + * @group legacy + */ class RedisClusterCacheTest extends AbstractRedisCacheTest { public static function setupBeforeClass() diff --git a/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php b/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php index e684caf36e..c2e8a477b4 100644 --- a/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\TraceableCache; /** * @group time-sensitive + * @group legacy */ class TraceableCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Traits/TagAwareTestTrait.php b/vendor/symfony/cache/Tests/Traits/TagAwareTestTrait.php new file mode 100644 index 0000000000..38cc4dc9cc --- /dev/null +++ b/vendor/symfony/cache/Tests/Traits/TagAwareTestTrait.php @@ -0,0 +1,160 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Traits; + +use Symfony\Component\Cache\CacheItem; + +/** + * Common assertions for TagAware adapters. + * + * @method \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface createCachePool() Must be implemented by TestCase + */ +trait TagAwareTestTrait +{ + /** + * @expectedException \Psr\Cache\InvalidArgumentException + */ + public function testInvalidTag() + { + $pool = $this->createCachePool(); + $item = $pool->getItem('foo'); + $item->tag(':'); + } + + public function testInvalidateTags() + { + $pool = $this->createCachePool(); + + $i0 = $pool->getItem('i0'); + $i1 = $pool->getItem('i1'); + $i2 = $pool->getItem('i2'); + $i3 = $pool->getItem('i3'); + $foo = $pool->getItem('foo'); + + $pool->save($i0->tag('bar')); + $pool->save($i1->tag('foo')); + $pool->save($i2->tag('foo')->tag('bar')); + $pool->save($i3->tag('foo')->tag('baz')); + $pool->save($foo); + + $pool->invalidateTags(['bar']); + + $this->assertFalse($pool->getItem('i0')->isHit()); + $this->assertTrue($pool->getItem('i1')->isHit()); + $this->assertFalse($pool->getItem('i2')->isHit()); + $this->assertTrue($pool->getItem('i3')->isHit()); + $this->assertTrue($pool->getItem('foo')->isHit()); + + $pool->invalidateTags(['foo']); + + $this->assertFalse($pool->getItem('i1')->isHit()); + $this->assertFalse($pool->getItem('i3')->isHit()); + $this->assertTrue($pool->getItem('foo')->isHit()); + + $anotherPoolInstance = $this->createCachePool(); + + $this->assertFalse($anotherPoolInstance->getItem('i1')->isHit()); + $this->assertFalse($anotherPoolInstance->getItem('i3')->isHit()); + $this->assertTrue($anotherPoolInstance->getItem('foo')->isHit()); + } + + public function testInvalidateCommits() + { + $pool = $this->createCachePool(); + + $foo = $pool->getItem('foo'); + $foo->tag('tag'); + + $pool->saveDeferred($foo->set('foo')); + $pool->invalidateTags(['tag']); + + // ??: This seems to contradict a bit logic in deleteItems, where it does unset($this->deferred[$key]); on key matches + + $foo = $pool->getItem('foo'); + + $this->assertTrue($foo->isHit()); + } + + public function testTagsAreCleanedOnSave() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + + $i = $pool->getItem('k'); + $pool->save($i->tag('bar')); + + $pool->invalidateTags(['foo']); + $this->assertTrue($pool->getItem('k')->isHit()); + } + + public function testTagsAreCleanedOnDelete() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + $pool->deleteItem('k'); + + $pool->save($pool->getItem('k')); + $pool->invalidateTags(['foo']); + + $this->assertTrue($pool->getItem('k')->isHit()); + } + + public function testTagItemExpiry() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $pool = $this->createCachePool(10); + + $item = $pool->getItem('foo'); + $item->tag(['baz']); + $item->expiresAfter(100); + + $pool->save($item); + $pool->invalidateTags(['baz']); + $this->assertFalse($pool->getItem('foo')->isHit()); + + sleep(20); + + $this->assertFalse($pool->getItem('foo')->isHit()); + } + + /** + * @group legacy + */ + public function testGetPreviousTags() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + + $i = $pool->getItem('k'); + $this->assertSame(['foo' => 'foo'], $i->getPreviousTags()); + } + + public function testGetMetadata() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + + $i = $pool->getItem('k'); + $this->assertSame(['foo' => 'foo'], $i->getMetadata()[CacheItem::METADATA_TAGS]); + } +} diff --git a/vendor/symfony/cache/Traits/AbstractAdapterTrait.php b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php new file mode 100644 index 0000000000..eb464c319e --- /dev/null +++ b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php @@ -0,0 +1,139 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\CacheItem; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +trait AbstractAdapterTrait +{ + use AbstractTrait; + + /** + * @var \Closure needs to be set by class, signature is function(string <key>, mixed <value>, bool <isHit>) + */ + private $createCacheItem; + + /** + * @var \Closure needs to be set by class, signature is function(array <deferred>, string <namespace>, array <&expiredIds>) + */ + private $mergeByLifetime; + + /** + * {@inheritdoc} + */ + public function getItem($key) + { + if ($this->deferred) { + $this->commit(); + } + $id = $this->getId($key); + + $f = $this->createCacheItem; + $isHit = false; + $value = null; + + try { + foreach ($this->doFetch([$id]) as $value) { + $isHit = true; + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]); + } + + return $f($key, $value, $isHit); + } + + /** + * {@inheritdoc} + */ + public function getItems(array $keys = []) + { + if ($this->deferred) { + $this->commit(); + } + $ids = []; + + foreach ($keys as $key) { + $ids[] = $this->getId($key); + } + try { + $items = $this->doFetch($ids); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]); + $items = []; + } + $ids = array_combine($ids, $keys); + + return $this->generateItems($items, $ids); + } + + /** + * {@inheritdoc} + */ + public function save(CacheItemInterface $item) + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return $this->commit(); + } + + /** + * {@inheritdoc} + */ + public function saveDeferred(CacheItemInterface $item) + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return true; + } + + public function __destruct() + { + if ($this->deferred) { + $this->commit(); + } + } + + private function generateItems($items, &$keys) + { + $f = $this->createCacheItem; + + try { + foreach ($items as $id => $value) { + if (!isset($keys[$id])) { + $id = key($keys); + } + $key = $keys[$id]; + unset($keys[$id]); + yield $key => $f($key, $value, true); + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]); + } + + foreach ($keys as $key) { + yield $key => $f($key, null, false); + } + } +} diff --git a/vendor/symfony/cache/Traits/AbstractTrait.php b/vendor/symfony/cache/Traits/AbstractTrait.php index 2553ea75cb..1d6c189c81 100644 --- a/vendor/symfony/cache/Traits/AbstractTrait.php +++ b/vendor/symfony/cache/Traits/AbstractTrait.php @@ -94,7 +94,7 @@ trait AbstractTrait try { return $this->doHave($id); } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', ['key' => $key, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached: '.$e->getMessage(), ['key' => $key, 'exception' => $e]); return false; } @@ -122,7 +122,7 @@ trait AbstractTrait try { return $this->doClear($this->namespace) || $cleared; } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to clear the cache', ['exception' => $e]); + CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]); return false; } @@ -166,7 +166,8 @@ trait AbstractTrait } } catch (\Exception $e) { } - CacheItem::log($this->logger, 'Failed to delete key "{key}"', ['key' => $key, 'exception' => $e]); + $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]); $ok = false; } diff --git a/vendor/symfony/cache/Traits/ArrayTrait.php b/vendor/symfony/cache/Traits/ArrayTrait.php index e585c3d48c..8ae9cad59b 100644 --- a/vendor/symfony/cache/Traits/ArrayTrait.php +++ b/vendor/symfony/cache/Traits/ArrayTrait.php @@ -128,7 +128,8 @@ trait ArrayTrait $serialized = serialize($value); } catch (\Exception $e) { $type = \is_object($value) ? \get_class($value) : \gettype($value); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => $key, 'type' => $type, 'exception' => $e]); + $message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage()); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e]); return; } @@ -150,7 +151,7 @@ trait ArrayTrait try { $value = unserialize($value); } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]); $value = false; } if (false === $value) { diff --git a/vendor/symfony/cache/Traits/ContractsTrait.php b/vendor/symfony/cache/Traits/ContractsTrait.php index bd7be08dd5..d9514d3965 100644 --- a/vendor/symfony/cache/Traits/ContractsTrait.php +++ b/vendor/symfony/cache/Traits/ContractsTrait.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Traits; +use Psr\Log\LoggerInterface; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; @@ -31,6 +32,7 @@ trait ContractsTrait } private $callbackWrapper = [LockRegistry::class, 'compute']; + private $computing = []; /** * Wraps the callback passed to ->get() in a callable. @@ -40,7 +42,7 @@ trait ContractsTrait public function setCallbackWrapper(?callable $callbackWrapper): callable { $previousWrapper = $this->callbackWrapper; - $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata) { + $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) { return $callback($item, $save); }; @@ -68,27 +70,28 @@ trait ContractsTrait CacheItem::class ); - return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata) { + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) { // don't wrap nor save recursive calls - if (null === $callbackWrapper = $this->callbackWrapper) { + if (isset($this->computing[$key])) { $value = $callback($item, $save); $save = false; return $value; } - $this->callbackWrapper = null; + + $this->computing[$key] = $key; $startTime = microtime(true); try { - $value = $callbackWrapper($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { + $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { $setMetadata($item, $startTime, $metadata); - }); + }, $this->logger ?? null); $setMetadata($item, $startTime, $metadata); return $value; } finally { - $this->callbackWrapper = $callbackWrapper; + unset($this->computing[$key]); } - }, $beta, $metadata); + }, $beta, $metadata, $this->logger ?? null); } } diff --git a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php index 3f684acd68..37e1fd1f06 100644 --- a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php +++ b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php @@ -101,11 +101,11 @@ trait FilesystemCommonTrait } } - private function getFile($id, $mkdir = false) + private function getFile($id, $mkdir = false, string $directory = null) { // Use MD5 to favor speed over security, which is not an issue here $hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true))); - $dir = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); + $dir = ($directory ?? $this->directory).strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); if ($mkdir && !file_exists($dir)) { @mkdir($dir, 0777, true); diff --git a/vendor/symfony/cache/Traits/RedisTrait.php b/vendor/symfony/cache/Traits/RedisTrait.php index 350a54360e..b2faca651d 100644 --- a/vendor/symfony/cache/Traits/RedisTrait.php +++ b/vendor/symfony/cache/Traits/RedisTrait.php @@ -80,15 +80,19 @@ trait RedisTrait */ public static function createConnection($dsn, array $options = []) { - if (0 !== strpos($dsn, 'redis:')) { - throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis:".', $dsn)); + if (0 === strpos($dsn, 'redis:')) { + $scheme = 'redis'; + } elseif (0 === strpos($dsn, 'rediss:')) { + $scheme = 'rediss'; + } else { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis:" or "rediss".', $dsn)); } if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { throw new CacheException(sprintf('Cannot find the "redis" extension nor the "predis/predis" package: %s', $dsn)); } - $params = preg_replace_callback('#^redis:(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { + $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { if (isset($m[2])) { $auth = $m[2]; } @@ -317,33 +321,13 @@ trait RedisTrait protected function doClear($namespace) { $cleared = true; - $hosts = [$this->redis]; - $evalArgs = [[$namespace], 0]; - if ($this->redis instanceof \Predis\Client) { $evalArgs = [0, $namespace]; - - $connection = $this->redis->getConnection(); - if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) { - $hosts = []; - foreach ($connection as $c) { - $hosts[] = new \Predis\Client($c); - } - } - } elseif ($this->redis instanceof \RedisArray) { - $hosts = []; - foreach ($this->redis->_hosts() as $host) { - $hosts[] = $this->redis->_instance($host); - } - } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) { - $hosts = []; - foreach ($this->redis->_masters() as $host) { - $hosts[] = $h = new \Redis(); - $h->connect($host[0], $host[1]); - } + } else { + $evalArgs = [[$namespace], 0]; } - foreach ($hosts as $host) { + foreach ($this->getHosts() as $host) { if (!isset($namespace[0])) { $cleared = $host->flushDb() && $cleared; continue; @@ -475,4 +459,31 @@ trait RedisTrait yield $id => $results[$k]; } } + + private function getHosts(): array + { + $hosts = [$this->redis]; + if ($this->redis instanceof \Predis\Client) { + $connection = $this->redis->getConnection(); + if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) { + $hosts = []; + foreach ($connection as $c) { + $hosts[] = new \Predis\Client($c); + } + } + } elseif ($this->redis instanceof \RedisArray) { + $hosts = []; + foreach ($this->redis->_hosts() as $host) { + $hosts[] = $this->redis->_instance($host); + } + } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) { + $hosts = []; + foreach ($this->redis->_masters() as $host) { + $hosts[] = $h = new \Redis(); + $h->connect($host[0], $host[1]); + } + } + + return $hosts; + } } diff --git a/vendor/symfony/cache/composer.json b/vendor/symfony/cache/composer.json index 8f9e669a33..05bed1cf75 100644 --- a/vendor/symfony/cache/composer.json +++ b/vendor/symfony/cache/composer.json @@ -18,14 +18,14 @@ "provide": { "psr/cache-implementation": "1.0", "psr/simple-cache-implementation": "1.0", - "symfony/cache-contracts-implementation": "1.0" + "symfony/cache-implementation": "1.0" }, "require": { "php": "^7.1.3", "psr/cache": "~1.0", "psr/log": "~1.0", - "psr/simple-cache": "^1.0", - "symfony/contracts": "^1.0", + "symfony/cache-contracts": "^1.1", + "symfony/service-contracts": "^1.1", "symfony/var-exporter": "^4.2" }, "require-dev": { @@ -33,6 +33,7 @@ "doctrine/cache": "~1.6", "doctrine/dbal": "~2.5", "predis/predis": "~1.1", + "psr/simple-cache": "^1.0", "symfony/config": "~4.2", "symfony/dependency-injection": "~3.4|~4.1", "symfony/var-dumper": "^4.1.1" @@ -51,7 +52,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/cache/phpunit.xml.dist b/vendor/symfony/cache/phpunit.xml.dist index c35458ca44..591046cf1c 100644 --- a/vendor/symfony/cache/phpunit.xml.dist +++ b/vendor/symfony/cache/phpunit.xml.dist @@ -40,7 +40,8 @@ <element key="1"><string>Doctrine\Common\Cache</string></element> <element key="2"><string>Symfony\Component\Cache</string></element> <element key="3"><string>Symfony\Component\Cache\Tests\Fixtures</string></element> - <element key="4"><string>Symfony\Component\Cache\Traits</string></element> + <element key="4"><string>Symfony\Component\Cache\Tests\Traits</string></element> + <element key="5"><string>Symfony\Component\Cache\Traits</string></element> </array> </element> </array> |
