From 9e5f0062c199ffd678d87762aba8987ef0d2e345 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maximilian=20B=C3=B6sing?=
<2189546+boesing@users.noreply.github.com>
Date: Thu, 13 Jun 2024 17:30:51 +0200
Subject: [PATCH] refactor: provide `Capabilities` as a read-only class
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This also removes `capability` event and the `marker` object. Capabilities are meant to be read-only and thus won't change after retrieval via `StorageInterface#getCapabilties`.
By having the event deleted, there is no need to have the adapter injected, though we also removed `Capabilities#getAdapter` and the `StorageInterface` constructor argument.
By refactoring the `Serializer` plugin, which already replaced the initial instance of `Capabilities`, we were able to drop the `base capabilities` feature as well.
Final result is that we now provide all capabilities as public `read-only` properties which reflect their defaults which were previously handled via internal `$default` magic in `Capabilties#getCapability`.
Along all the refactoring, some capabilities have changed or were removed while respecting ideas of #8 which was around since 2016:
- `staticTtl` got removed without a replacement. It outlined if the cache backend is handling cache expiry or if the implementation is taking care of it. Though it might be interesting for picking a specific backend, that is rather not of interest at runtime for upstream projects.
- `lockOnExpire` got removed without a replacement. Was only used in zend-server adapter which is already abandoned since 2022
- `minTtl` got renamed to `ttlSupported` and its type changed from `int` to `bool`
- `maxTtl` got removed without a replacement. Every cache backend which is supported by laminas right now does allow TTLs being an infinite amount of seconds (where maximum `int` range is the limit, depending on the CPU architecture). There was a backend `XCache` where a limit existed but that backend was abandoned in 2021.
- `useRequestTime` was renamed to `usesRequestTime`
- `namespaceSeparator` got removed without a replacement. It was reflecting the option value and this the storage options can be used instead.
Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com>
---
docs/book/v4/storage/adapter.md | 95 ++--
docs/book/v4/storage/capabilities.md | 197 +-------
psalm-baseline.xml | 75 ---
.../CacheItemPool/CacheItemPoolDecorator.php | 11 +-
src/Psr/MaximumKeyLengthTrait.php | 2 +-
src/Psr/SerializationTrait.php | 2 +-
src/Psr/SimpleCache/SimpleCacheDecorator.php | 2 +-
src/Storage/Adapter/AbstractAdapter.php | 15 +-
src/Storage/Capabilities.php | 430 ++----------------
src/Storage/Plugin/Serializer.php | 52 +--
.../CacheItemPoolDecoratorTest.php | 72 ++-
.../SimpleCache/SimpleCacheDecoratorTest.php | 100 ++--
test/Storage/Adapter/AbstractAdapterTest.php | 3 +-
test/Storage/CapabilitiesTest.php | 99 ----
.../EventsCapableStorageInterface.php | 12 -
15 files changed, 198 insertions(+), 969 deletions(-)
delete mode 100644 test/Storage/CapabilitiesTest.php
delete mode 100644 test/Storage/TestAsset/EventsCapableStorageInterface.php
diff --git a/docs/book/v4/storage/adapter.md b/docs/book/v4/storage/adapter.md
index 8ec7de20..3359fdb6 100644
--- a/docs/book/v4/storage/adapter.md
+++ b/docs/book/v4/storage/adapter.md
@@ -515,15 +515,11 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|---------------------------------------------------------------------------------------|
| `supportedDatatypes` | `null`, `bool`, `int`, `float`, `string`, `array` (serialized), `object` (serialized) |
-| `minTtl` | 1 |
-| `maxTtl` | 0 |
-| `staticTtl` | `true` |
-| `ttlPrecision` | 1 |
-| `useRequestTime` | value of `apc.use_request_time` from `php.ini` |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | 5182 |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `1` |
+| `usesRequestTime` | value of `apc.use_request_time` INI value, disabled by default. |
+| `maxKeyLength` | `5182` |
| `namespaceIsPrefix` | `true` |
-| `namespaceSeparator` | Option value of `namespace_separator` |
### Metadata
@@ -570,15 +566,11 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|-------------------------------------------------------------|
| `supportedDatatypes` | `null`, `bool`, `int`, `float`, `string`, `array`, `object` |
-| `minTtl` | 1 |
-| `maxTtl` | 0 |
-| `staticTtl` | `false` or `true`, depending on `psr` option |
-| `ttlPrecision` | 1 |
-| `useRequestTime` | false |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | -1 |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `1` |
+| `usesRequestTime` | `false` |
+| `maxKeyLength` | unlimited as nothing will be cached anyways |
| `namespaceIsPrefix` | `true` |
-| `namespaceSeparator` | none |
## Filesystem Adapter
@@ -602,15 +594,11 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|--------------------------------------------------------------------------------------------------|
| `supportedDatatypes` | `string`, `null` => `string`, `boolean` => `string`, `integer` => `string`, `double` => `string` |
-| `minTtl` | 1 |
-| `maxTtl` | 0 |
-| `staticTtl` | `false` |
-| `ttlPrecision` | 1 |
-| `useRequestTime` | `false` |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | 251 |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `1` |
+| `usesRequestTime` | `false` |
+| `maxKeyLength` | `251` |
| `namespaceIsPrefix` | `true` |
-| `namespaceSeparator` | Option value of `namespace_separator` |
### Metadata
@@ -661,15 +649,11 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|-----------------------------------------------------------------------------------------------|
| `supportedDatatypes` | `null`, `boolean`, `integer`, `double`, `string`, `array` (serialized), `object` (serialized) |
-| `minTtl` | 1 |
-| `maxTtl` | 0 |
-| `staticTtl` | `true` |
-| `ttlPrecision` | 1 |
-| `useRequestTime` | `false` |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | 255 |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `1` |
+| `usesRequestTime` | `false` |
+| `maxKeyLength` | `255` |
| `namespaceIsPrefix` | `true` |
-| `namespaceSeparator` | none |
### Adapter Specific Options
@@ -695,15 +679,11 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|-------------------------------------------------------|
| `supportedDatatypes` | `string`, `array` (serialized), `object` (serialized) |
-| `minTtl` | 1 |
-| `maxTtl` | 0 |
-| `staticTtl` | `true` |
-| `ttlPrecision` | 1 |
-| `useRequestTime` | `false` |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | 512000000 (in Redis v3+, 255 otherwise) |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `1` |
+| `usesRequestTime` | `false` |
+| `maxKeyLength` | `512000000` (in Redis v3+, `255` in older versions) |
| `namespaceIsPrefix` | `true` |
-| `namespaceSeparator` | none |
### Metadata
@@ -745,15 +725,11 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|-------------------------------------------------------|
| `supportedDatatypes` | `string`, `array` (serialized), `object` (serialized) |
-| `minTtl` | 1 |
-| `maxTtl` | 0 |
-| `staticTtl` | `true` |
-| `ttlPrecision` | 1 |
-| `useRequestTime` | `false` |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | 512000000 (in Redis v3+, 255 otherwise) |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `1` |
+| `usesRequestTime` | `false` |
+| `maxKeyLength` | `512000000` (in Redis v3+, `255` in older versions) |
| `namespaceIsPrefix` | `true` |
-| `namespaceSeparator` | none |
### Metadata
@@ -796,13 +772,10 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|---------------------------------------------------------------------------------|
| `supportedDatatypes` | `string`, `null`, `boolean`, `integer`, `double`, `array`, `object`, `resource` |
-| `minTtl` | 1 |
-| `maxTtl` | Value of `PHP_INT_MAX` |
-| `staticTtl` | `false` |
-| `ttlPrecision` | 0.05 |
-| `useRequestTime` | `false` |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | 0 |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `0.05` |
+| `usesRequestTime` | `false` |
+| `maxKeyLength` | `0` |
| `namespaceIsPrefix` | `false` |
### Metadata
@@ -851,15 +824,11 @@ This adapter implements the following interfaces:
| Capability | Value |
|----------------------|-----------------------------------------------------------|
| `supportedDatatypes` | `string`, `null`, `boolean`, `integer`, `double`, `array` |
-| `minTtl` | 0 |
-| `maxTtl` | 0 |
-| `staticTtl` | `true` |
-| `ttlPrecision` | 1 |
-| `useRequestTime` | `false` |
-| `lockOnExpire` | 0 |
-| `maxKeyLength` | 255 |
+| `ttlSupported` | `true` |
+| `ttlPrecision` | `1` |
+| `usesRequestTime` | `false` |
+| `maxKeyLength` | `255` |
| `namespaceIsPrefix` | `true` |
-| `namespaceSeparator` | *Option value of `namespace_separator`* |
### Metadata
diff --git a/docs/book/v4/storage/capabilities.md b/docs/book/v4/storage/capabilities.md
index 6d1c8e92..0db2a237 100644
--- a/docs/book/v4/storage/capabilities.md
+++ b/docs/book/v4/storage/capabilities.md
@@ -24,156 +24,32 @@ use stdClass;
use Laminas\Cache\Exception;
use Laminas\EventManager\EventsCapableInterface;
-class Capabilities
+final class Capabilities
{
/**
- * Constructor
- *
+ * @param int<-1,max> $maxKeyLength
+ * @param SupportedDataTypesArrayShape $supportedDataTypes
*/
public function __construct(
- StorageInterface $storage,
- stdClass $marker,
- array $capabilities = [],
- Capabilities|null $baseCapabilities = null
- );
-
- /**
- * Get the storage adapter
- */
- public function getAdapter(): StorageInterface;
-
- /**
- * Get supported datatypes
- */
- public function getSupportedDatatypes(): array;
-
- /**
- * Set supported datatypes
- *
- * @param stdClass $marker
- * @param array $datatypes
- * @throws Exception\InvalidArgumentException
- * @return Capabilities Fluent interface
- */
- public function setSupportedDatatypes(stdClass $marker, array $datatypes);
-
- /**
- * Get minimum supported time-to-live
- *
- * @return int 0 means items never expire
- */
- public function getMinTtl(): int;
-
- /**
- * Set minimum supported time-to-live
- *
- * @param stdClass $marker
- * @param int $minTtl
- * @throws Exception\InvalidArgumentException
- */
- public function setMinTtl(stdClass $marker, int $minTtl): self;
-
- /**
- * Get maximum supported time-to-live
- *
- * @return int 0 means infinite
- */
- public function getMaxTtl(): int;
-
- /**
- * Set maximum supported time-to-live
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setMaxTtl(stdClass $marker, int $maxTtl): self;
-
- /**
- * Is the time-to-live handled static (on write)
- * or dynamic (on read)
- */
- public function getStaticTtl(): bool;
-
- /**
- * Set if the time-to-live handled static (on write) or dynamic (on read)
- */
- public function setStaticTtl(stdClass $marker, bool $flag): self;
-
- /**
- * Get time-to-live precision
- */
- public function getTtlPrecision(): float;
-
- /**
- * Set time-to-live precision
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setTtlPrecision(stdClass $marker, float $ttlPrecision): self;
-
- /**
- * Get use request time
- */
- public function getUseRequestTime(): bool;
-
- /**
- * Set use request time
- */
- public function setUseRequestTime(stdClass $marker, bool $flag): self;
-
-
- /**
- * Get "lock-on-expire" support in seconds.
- *
- * @return int 0 = Expired items will never be retrieved
- * >0 = Time in seconds an expired item could be retrieved
- * -1 = Expired items could be retrieved forever
- */
- public function getLockOnExpire(): int
- {
- return $this->getCapability('lockOnExpire', 0);
- }
-
- /**
- * Set "lock-on-expire" support in seconds.
- */
- public function setLockOnExpire(stdClass $marker, int $timeout): self
- {
- return $this->setCapability($marker, 'lockOnExpire', (int) $timeout);
+ /**
+ * Maximum supported key length for the cache backend
+ */
+ public readonly int $maxKeyLength,
+ /**
+ * Whether the cache backend supports TTL
+ */
+ public readonly bool $ttlSupported,
+ public readonly bool $namespaceIsPrefix,
+ /**
+ * Contains the supported data types.
+ * Depending on the cache backend in use, the type remains as is, is converted to a different type or is not
+ * supported at all.
+ */
+ public readonly array $supportedDataTypes,
+ public readonly int|float $ttlPrecision,
+ public readonly bool $usesRequestTime,
+ ) {
}
-
- /**
- * Get maximum key length
- *
- * @return int -1 means unknown, 0 means infinite
- */
- public function getMaxKeyLength(): int;
-
- /**
- * Set maximum key length
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setMaxKeyLength(stdClass $marker, int $maxKeyLength): self;
-
- /**
- * Get if namespace support is implemented as prefix
- */
- public function getNamespaceIsPrefix(): bool;
-
- /**
- * Set if namespace support is implemented as prefix
- */
- public function setNamespaceIsPrefix(stdClass $marker, bool $flag): self;
-
- /**
- * Get namespace separator if namespace is implemented as prefix
- */
- public function getNamespaceSeparator(): string;
-
- /**
- * Set the namespace separator if namespace is implemented as prefix
- */
- public function setNamespaceSeparator(stdClass $marker, string $separator): self;
}
```
@@ -192,37 +68,12 @@ $container = null; // can be any configured PSR-11 container
$storageFactory = $container->get(StorageAdapterFactoryInterface::class);
$cache = $storageFactory->create('filesystem');
-$supportedDatatypes = $cache->getCapabilities()->getSupportedDatatypes();
+$supportedDataTypes = $cache->getCapabilities()->supportedDataTypes;
// now you can run specific stuff in base of supported feature
-if ($supportedDatatypes['object']) {
+if ($supportedDataTypes['object']) {
$cache->set($key, $object);
} else {
$cache->set($key, serialize($object));
}
-```
-
-### Listen to the change Event
-
-```php
-use Laminas\Cache\Service\StorageAdapterFactoryInterface;
-use Psr\Container\ContainerInterface;
-
-/** @var ContainerInterface $container */
-$container = null; // can be any configured PSR-11 container
-
-/** @var StorageAdapterFactoryInterface $storageFactory */
-$storageFactory = $container->get(StorageAdapterFactoryInterface::class);
-
-$cache = $storageFactory->create('filesystem', [
- 'no_atime' => false,
-]);
-
-// Catching capability changes
-$cache->getEventManager()->attach('capability', function($event) {
- echo count($event->getParams()) . ' capabilities changed';
-});
-
-// change option which changes capabilities
-$cache->getOptions()->setNoATime(true);
-```
+```
\ No newline at end of file
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 22806fa1..cf1ddf8f 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -265,73 +265,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- getCapability('lockOnExpire', 0)]]>
- getCapability('maxKeyLength', self::UNKNOWN_KEY_LENGTH)]]>
- getCapability('maxTtl', 0)]]>
- getCapability('minTtl', 0)]]>
- getCapability('namespaceIsPrefix', true)]]>
- getCapability('namespaceSeparator', '')]]>
- getCapability('staticTtl', false)]]>
- getCapability('supportedDatatypes', [
- 'NULL' => false,
- 'boolean' => false,
- 'integer' => false,
- 'double' => false,
- 'string' => true,
- 'array' => false,
- 'object' => false,
- 'resource' => false,
- ])]]>
- getCapability('ttlPrecision', 1)]]>
- getCapability('useRequestTime', false)]]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -383,9 +316,6 @@
-
-
- getAdapter()]]>
@@ -397,9 +327,6 @@
-
-
-
@@ -547,11 +474,9 @@
-
-
diff --git a/src/Psr/CacheItemPool/CacheItemPoolDecorator.php b/src/Psr/CacheItemPool/CacheItemPoolDecorator.php
index de48d1ca..768bd518 100644
--- a/src/Psr/CacheItemPool/CacheItemPoolDecorator.php
+++ b/src/Psr/CacheItemPool/CacheItemPoolDecorator.php
@@ -307,26 +307,19 @@ private function validateStorage(StorageInterface $storage): void
// we've got to be able to set per-item TTL on write
$capabilities = $storage->getCapabilities();
- if (! ($capabilities->getStaticTtl() && $capabilities->getMinTtl())) {
+ if (! $capabilities->ttlSupported) {
throw new CacheException(sprintf(
'Storage %s does not support static TTL',
$storage::class
));
}
- if ($capabilities->getUseRequestTime()) {
+ if ($capabilities->usesRequestTime) {
throw new CacheException(sprintf(
'The capability "use-request-time" of storage %s violates PSR-6',
$storage::class
));
}
-
- if ($capabilities->getLockOnExpire()) {
- throw new CacheException(sprintf(
- 'The capability "lock-on-expire" of storage %s violates PSR-6',
- $storage::class
- ));
- }
}
/**
diff --git a/src/Psr/MaximumKeyLengthTrait.php b/src/Psr/MaximumKeyLengthTrait.php
index 37371e10..18058dc4 100644
--- a/src/Psr/MaximumKeyLengthTrait.php
+++ b/src/Psr/MaximumKeyLengthTrait.php
@@ -37,7 +37,7 @@ trait MaximumKeyLengthTrait
private function memoizeMaximumKeyLengthCapability(StorageInterface $storage, Capabilities $capabilities): void
{
- $maximumKeyLength = $capabilities->getMaxKeyLength();
+ $maximumKeyLength = $capabilities->maxKeyLength;
if ($maximumKeyLength === Capabilities::UNLIMITED_KEY_LENGTH) {
$this->maximumKeyLength = Capabilities::UNLIMITED_KEY_LENGTH;
diff --git a/src/Psr/SerializationTrait.php b/src/Psr/SerializationTrait.php
index c6541bb8..150f4627 100644
--- a/src/Psr/SerializationTrait.php
+++ b/src/Psr/SerializationTrait.php
@@ -21,7 +21,7 @@ private function isSerializationRequired(StorageInterface $storage): bool
{
$capabilities = $storage->getCapabilities();
$requiredTypes = ['string', 'integer', 'double', 'boolean', 'NULL', 'array', 'object'];
- $types = $capabilities->getSupportedDatatypes();
+ $types = $capabilities->supportedDataTypes;
foreach ($requiredTypes as $type) {
// 'object' => 'object' is OK
diff --git a/src/Psr/SimpleCache/SimpleCacheDecorator.php b/src/Psr/SimpleCache/SimpleCacheDecorator.php
index 1f206edb..3751b531 100644
--- a/src/Psr/SimpleCache/SimpleCacheDecorator.php
+++ b/src/Psr/SimpleCache/SimpleCacheDecorator.php
@@ -361,7 +361,7 @@ private function assertValidKey(string|int $key): void
*/
private function memoizeTtlCapabilities(Capabilities $capabilities): void
{
- $this->providesPerItemTtl = $capabilities->getStaticTtl() && (0 < $capabilities->getMinTtl());
+ $this->providesPerItemTtl = 0 < $capabilities->ttlSupported;
}
/**
diff --git a/src/Storage/Adapter/AbstractAdapter.php b/src/Storage/Adapter/AbstractAdapter.php
index f073c0dc..8daa1488 100644
--- a/src/Storage/Adapter/AbstractAdapter.php
+++ b/src/Storage/Adapter/AbstractAdapter.php
@@ -16,7 +16,6 @@
use Laminas\EventManager\EventManagerInterface;
use Laminas\EventManager\ResponseCollection;
use SplObjectStorage;
-use stdClass;
use Throwable;
use Webmozart\Assert\Assert;
@@ -56,11 +55,6 @@ abstract class AbstractAdapter implements StorageInterface, PluginAwareInterface
*/
protected ?Capabilities $capabilities = null;
- /**
- * Marker to change capabilities
- */
- protected ?object $capabilityMarker = null;
-
/**
* options
*
@@ -1180,7 +1174,7 @@ public function getCapabilities(): Capabilities
Assert::isInstanceOf($result, Capabilities::class);
return $result;
} catch (Throwable $throwable) {
- $result = $this->triggerThrowable(__FUNCTION__, $args, new Capabilities($this, new stdClass()), $throwable);
+ $result = $this->triggerThrowable(__FUNCTION__, $args, new Capabilities(), $throwable);
Assert::isInstanceOf($result, Capabilities::class);
return $result;
@@ -1192,12 +1186,7 @@ public function getCapabilities(): Capabilities
*/
protected function internalGetCapabilities(): Capabilities
{
- if ($this->capabilities === null) {
- $this->capabilityMarker = new stdClass();
- $this->capabilities = new Capabilities($this, $this->capabilityMarker);
- }
-
- return $this->capabilities;
+ return $this->capabilities ??= new Capabilities();
}
/* internal */
diff --git a/src/Storage/Capabilities.php b/src/Storage/Capabilities.php
index ce2d1b27..ba7e5bc7 100644
--- a/src/Storage/Capabilities.php
+++ b/src/Storage/Capabilities.php
@@ -2,404 +2,56 @@
namespace Laminas\Cache\Storage;
-use ArrayObject;
-use Laminas\Cache\Exception;
-use Laminas\EventManager\EventsCapableInterface;
-use stdClass;
-
-use function array_diff;
-use function array_keys;
-use function in_array;
-use function is_string;
-use function strtolower;
-
-class Capabilities
+/**
+ * @psalm-type DataTypeConversionType = 'null'|'boolean'|'integer'|'double'|'string'|'array'|'object'|'resource'
+ * @psalm-type SupportedDataTypesArrayShape = array{
+ * 'NULL'?: bool|DataTypeConversionType,
+ * 'boolean'?: bool|DataTypeConversionType,
+ * 'integer'?: bool|DataTypeConversionType,
+ * 'double'?: bool|DataTypeConversionType,
+ * 'string'?: bool|DataTypeConversionType,
+ * 'array'?: bool|DataTypeConversionType,
+ * 'object'?: bool|DataTypeConversionType,
+ * 'resource'?: bool|DataTypeConversionType,
+ * }
+ */
+final class Capabilities
{
public const UNKNOWN_KEY_LENGTH = -1;
public const UNLIMITED_KEY_LENGTH = 0;
+ private const DEFAULT_DATA_TYPES = [
+ 'NULL' => false,
+ 'boolean' => false,
+ 'integer' => false,
+ 'double' => false,
+ 'string' => true,
+ 'array' => false,
+ 'object' => false,
+ 'resource' => false,
+ ];
/**
- * "lock-on-expire" support in seconds.
- *
- * 0 = Expired items will never be retrieved
- * >0 = Time in seconds an expired item could be retrieved
- * -1 = Expired items could be retrieved forever
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?bool $lockOnExpire = null;
-
- /**
- * Max. key length
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?int $maxKeyLength = null;
-
- /**
- * Min. TTL (0 means items never expire)
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?int $minTtl = null;
-
- /**
- * Max. TTL (0 means infinite)
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?int $maxTtl = null;
-
- /**
- * Namespace is prefix
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?bool $namespaceIsPrefix = null;
-
- /**
- * Namespace separator
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
+ * @param int<-1,max> $maxKeyLength
+ * @param SupportedDataTypesArrayShape $supportedDataTypes
*/
- protected ?string $namespaceSeparator = null;
-
- /**
- * Static ttl
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?bool $staticTtl = null;
-
- /**
- * Supported datatypes
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|array
- */
- protected ?array $supportedDatatypes = null;
-
- /**
- * TTL precision
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?int $ttlPrecision = null;
-
- /**
- * Use request time
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- */
- protected ?bool $useRequestTime = null;
-
public function __construct(
- protected StorageInterface $storage,
/**
- * A marker to set/change capabilities
+ * Maximum supported key length for the cache backend
+ */
+ public readonly int $maxKeyLength = self::UNKNOWN_KEY_LENGTH,
+ /**
+ * Whether the cache backend supports TTL
+ */
+ public readonly bool $ttlSupported = false,
+ public readonly bool $namespaceIsPrefix = true,
+ /**
+ * Contains the supported data types.
+ * Depending on the cache backend in use, the type remains as is, is converted to a different type or is not
+ * supported at all.
*/
- protected stdClass $marker,
- array $capabilities = [],
- protected ?Capabilities $baseCapabilities = null
+ public readonly array $supportedDataTypes = self::DEFAULT_DATA_TYPES,
+ public readonly int|float $ttlPrecision = 1,
+ public readonly bool $usesRequestTime = false,
) {
- foreach ($capabilities as $name => $value) {
- $this->setCapability($marker, $name, $value);
- }
- }
-
- /**
- * Get the storage adapter
- */
- public function getAdapter(): StorageInterface
- {
- return $this->storage;
- }
-
- /**
- * Get supported datatypes
- */
- public function getSupportedDatatypes(): array
- {
- return $this->getCapability('supportedDatatypes', [
- 'NULL' => false,
- 'boolean' => false,
- 'integer' => false,
- 'double' => false,
- 'string' => true,
- 'array' => false,
- 'object' => false,
- 'resource' => false,
- ]);
- }
-
- /**
- * Set supported datatypes
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setSupportedDatatypes(stdClass $marker, array $datatypes): self
- {
- $allTypes = [
- 'array',
- 'boolean',
- 'double',
- 'integer',
- 'NULL',
- 'object',
- 'resource',
- 'string',
- ];
-
- // check/normalize datatype values
- $normalized = [];
- foreach ($datatypes as $type => $toType) {
- if (! in_array($type, $allTypes)) {
- throw new Exception\InvalidArgumentException("Unknown datatype '{$type}'");
- }
-
- if (is_string($toType)) {
- $toType = strtolower($toType);
- if (! in_array($toType, $allTypes)) {
- throw new Exception\InvalidArgumentException("Unknown datatype '{$toType}'");
- }
- } else {
- $toType = (bool) $toType;
- }
-
- $normalized[$type] = $toType;
- }
-
- // add missing datatypes as not supported
- $missingTypes = array_diff($allTypes, array_keys($normalized));
- foreach ($missingTypes as $type) {
- $normalized[$type] = false;
- }
-
- return $this->setCapability($marker, 'supportedDatatypes', $normalized);
- }
-
- /**
- * Get minimum supported time-to-live
- *
- * @return int 0 means items never expire
- */
- public function getMinTtl(): int
- {
- return $this->getCapability('minTtl', 0);
- }
-
- /**
- * Set minimum supported time-to-live
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setMinTtl(stdClass $marker, int $minTtl): self
- {
- if ($minTtl < 0) {
- throw new Exception\InvalidArgumentException('$minTtl must be greater or equal 0');
- }
- return $this->setCapability($marker, 'minTtl', $minTtl);
- }
-
- /**
- * Get maximum supported time-to-live
- *
- * @return int 0 means infinite
- */
- public function getMaxTtl(): int
- {
- return $this->getCapability('maxTtl', 0);
- }
-
- /**
- * Set maximum supported time-to-live
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setMaxTtl(stdClass $marker, int $maxTtl): self
- {
- if ($maxTtl < 0) {
- throw new Exception\InvalidArgumentException('$maxTtl must be greater or equal 0');
- }
- return $this->setCapability($marker, 'maxTtl', $maxTtl);
- }
-
- /**
- * Is the time-to-live handled static (on write)
- * or dynamic (on read)
- */
- public function getStaticTtl(): bool
- {
- return $this->getCapability('staticTtl', false);
- }
-
- /**
- * Set if the time-to-live handled static (on write) or dynamic (on read)
- */
- public function setStaticTtl(stdClass $marker, bool $flag): self
- {
- return $this->setCapability($marker, 'staticTtl', $flag);
- }
-
- /**
- * Get time-to-live precision
- */
- public function getTtlPrecision(): float
- {
- return $this->getCapability('ttlPrecision', 1);
- }
-
- /**
- * Set time-to-live precision
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setTtlPrecision(stdClass $marker, float $ttlPrecision): self
- {
- if ($ttlPrecision <= 0) {
- throw new Exception\InvalidArgumentException('$ttlPrecision must be greater than 0');
- }
- return $this->setCapability($marker, 'ttlPrecision', $ttlPrecision);
- }
-
- /**
- * Get use request time
- */
- public function getUseRequestTime(): bool
- {
- return $this->getCapability('useRequestTime', false);
- }
-
- /**
- * Set use request time
- */
- public function setUseRequestTime(stdClass $marker, bool $flag): self
- {
- return $this->setCapability($marker, 'useRequestTime', $flag);
- }
-
- /**
- * Get "lock-on-expire" support in seconds.
- *
- * @return int 0 = Expired items will never be retrieved
- * >0 = Time in seconds an expired item could be retrieved
- * -1 = Expired items could be retrieved forever
- */
- public function getLockOnExpire(): int
- {
- return $this->getCapability('lockOnExpire', 0);
- }
-
- /**
- * Set "lock-on-expire" support in seconds.
- */
- public function setLockOnExpire(stdClass $marker, int $timeout): self
- {
- return $this->setCapability($marker, 'lockOnExpire', $timeout);
- }
-
- /**
- * Get maximum key length
- *
- * @return int -1 means unknown, 0 means infinite
- */
- public function getMaxKeyLength(): int
- {
- return $this->getCapability('maxKeyLength', self::UNKNOWN_KEY_LENGTH);
- }
-
- /**
- * Set maximum key length
- *
- * @throws Exception\InvalidArgumentException
- */
- public function setMaxKeyLength(stdClass $marker, int $maxKeyLength): self
- {
- if ($maxKeyLength < -1) {
- throw new Exception\InvalidArgumentException('$maxKeyLength must be greater or equal than -1');
- }
- return $this->setCapability($marker, 'maxKeyLength', $maxKeyLength);
- }
-
- /**
- * Get if namespace support is implemented as prefix
- */
- public function getNamespaceIsPrefix(): bool
- {
- return $this->getCapability('namespaceIsPrefix', true);
- }
-
- /**
- * Set if namespace support is implemented as prefix
- */
- public function setNamespaceIsPrefix(stdClass $marker, bool $flag): self
- {
- return $this->setCapability($marker, 'namespaceIsPrefix', $flag);
- }
-
- /**
- * Get namespace separator if namespace is implemented as prefix
- */
- public function getNamespaceSeparator(): string
- {
- return $this->getCapability('namespaceSeparator', '');
- }
-
- /**
- * Set the namespace separator if namespace is implemented as prefix
- */
- public function setNamespaceSeparator(stdClass $marker, string $separator): self
- {
- return $this->setCapability($marker, 'namespaceSeparator', $separator);
- }
-
- /**
- * Get a capability
- */
- protected function getCapability(string $property, mixed $default = null): mixed
- {
- if ($this->$property !== null) {
- return $this->$property;
- } elseif ($this->baseCapabilities) {
- $getMethod = 'get' . $property;
- return $this->baseCapabilities->$getMethod();
- }
- return $default;
- }
-
- /**
- * Change a capability
- *
- * @throws Exception\InvalidArgumentException
- */
- protected function setCapability(stdClass $marker, string $property, mixed $value): self
- {
- if ($this->marker !== $marker) {
- throw new Exception\InvalidArgumentException('Invalid marker');
- }
-
- if ($this->$property !== $value) {
- $this->$property = $value;
-
- // trigger event
- if ($this->storage instanceof EventsCapableInterface) {
- $this->storage->getEventManager()->trigger('capability', $this->storage, new ArrayObject([
- $property => $value,
- ]));
- }
- }
-
- return $this;
}
}
diff --git a/src/Storage/Plugin/Serializer.php b/src/Storage/Plugin/Serializer.php
index 2cecd1f4..0ef6a6cb 100644
--- a/src/Storage/Plugin/Serializer.php
+++ b/src/Storage/Plugin/Serializer.php
@@ -8,15 +8,11 @@
use Laminas\EventManager\EventManagerInterface;
use Laminas\Serializer\Adapter\AdapterInterface;
use Laminas\ServiceManager\PluginManagerInterface;
-use stdClass;
use function assert;
-use function spl_object_hash;
final class Serializer extends AbstractPlugin
{
- protected array $capabilities = [];
-
private ?AdapterInterface $serializer = null;
/**
@@ -111,34 +107,32 @@ public function onWriteItemsPre(Event $event): void
}
/**
- * On get capabilities
+ * Update data types when using serializer plugin.
*/
public function onGetCapabilitiesPost(PostEvent $event): void
{
- $baseCapabilities = $event->getResult();
- $index = spl_object_hash($baseCapabilities);
-
- if (! isset($this->capabilities[$index])) {
- $this->capabilities[$index] = new Capabilities(
- $baseCapabilities->getAdapter(),
- new stdClass(), // marker
- [
- 'supportedDatatypes' => [
- 'NULL' => true,
- 'boolean' => true,
- 'integer' => true,
- 'double' => true,
- 'string' => true,
- 'array' => true,
- 'object' => 'object',
- 'resource' => false,
- ],
- ],
- $baseCapabilities
- );
- }
-
- $event->setResult($this->capabilities[$index]);
+ $capabilities = $event->getResult();
+ assert($capabilities instanceof Capabilities);
+
+ $capabilitiesWithUpdatedDataTypes = new Capabilities(
+ $capabilities->maxKeyLength,
+ $capabilities->ttlSupported,
+ $capabilities->namespaceIsPrefix,
+ [
+ 'NULL' => true,
+ 'boolean' => true,
+ 'integer' => true,
+ 'double' => true,
+ 'string' => true,
+ 'array' => true,
+ 'object' => 'object',
+ 'resource' => false,
+ ],
+ $capabilities->ttlPrecision,
+ $capabilities->usesRequestTime,
+ );
+
+ $event->setResult($capabilitiesWithUpdatedDataTypes);
}
public function getSerializer(): AdapterInterface
diff --git a/test/Psr/CacheItemPool/CacheItemPoolDecoratorTest.php b/test/Psr/CacheItemPool/CacheItemPoolDecoratorTest.php
index 4cdb710b..73c56915 100644
--- a/test/Psr/CacheItemPool/CacheItemPoolDecoratorTest.php
+++ b/test/Psr/CacheItemPool/CacheItemPoolDecoratorTest.php
@@ -16,14 +16,12 @@
use Laminas\Cache\Storage\ClearByNamespaceInterface;
use Laminas\Cache\Storage\FlushableInterface;
use Laminas\Cache\Storage\StorageInterface;
-use Laminas\EventManager\EventManager;
use LaminasTest\Cache\Psr\CacheItemPool\TestAsset\FlushableStorageAdapterInterface;
use LaminasTest\Cache\Psr\TestAsset\FlushableNamespaceStorageInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemInterface;
use Psr\Clock\ClockInterface;
-use stdClass;
use Throwable;
use function array_keys;
@@ -34,15 +32,17 @@
use function str_repeat;
use function time;
+/**
+ * @psalm-import-type SupportedDataTypesArrayShape from Capabilities
+ */
final class CacheItemPoolDecoratorTest extends TestCase
{
/** @var StorageInterface&FlushableInterface&MockObject */
- private $storage;
+ private StorageInterface&FlushableInterface&MockObject $storage;
private ?CacheItemPoolDecorator $adapter;
- /** @var array */
- private array $requiredTypes = [
+ private const REQUIRED_TYPES = [
'NULL' => true,
'boolean' => true,
'integer' => true,
@@ -53,8 +53,7 @@ final class CacheItemPoolDecoratorTest extends TestCase
'resource' => false,
];
- /** @var AdapterOptions&MockObject */
- private $options;
+ private AdapterOptions&MockObject $options;
protected function setUp(): void
{
@@ -65,31 +64,24 @@ protected function setUp(): void
}
/**
+ * @param SupportedDataTypesArrayShape|null $supportedDataTypes
+ * @param int<-1,max> $maxKeyLength
* @return StorageInterface&FlushableInterface&ClearByNamespaceInterface&MockObject
*/
private function createMockedStorage(
?AdapterOptions $options = null,
?array $supportedDataTypes = null,
- bool $staticTtl = true,
- int $minTtl = 1,
+ bool $ttlSupported = true,
int $maxKeyLength = -1,
bool $useRequestTime = false,
- bool $lockOnExpire = false
): StorageInterface {
$storage = $this->createMock(FlushableNamespaceStorageInterface::class);
- $storage
- ->method('getEventManager')
- ->willReturn(new EventManager());
-
$capabilities = $this->createCapabilities(
- $storage,
$supportedDataTypes,
- $staticTtl,
- $minTtl,
+ $ttlSupported,
$maxKeyLength,
$useRequestTime,
- $lockOnExpire
);
$storage
@@ -108,7 +100,7 @@ public function testStorageNeedsSerializerWillThrowException(): void
$this->expectException(CacheException::class);
$storage = $this->createMock(FlushableStorageAdapterInterface::class);
- $capabilities = $this->createCapabilities($storage, [
+ $capabilities = $this->createCapabilities(supportedDataTypes: [
'NULL' => true,
'boolean' => true,
'integer' => true,
@@ -127,17 +119,10 @@ public function testStorageNeedsSerializerWillThrowException(): void
$this->getAdapter($storage);
}
- public function testStorageFalseStaticTtlThrowsException(): void
+ public function testBackendDoesNotSupportTtlThrowsException(): void
{
$this->expectException(CacheException::class);
- $storage = $this->createMockedStorage(null, null, false);
- $this->getAdapter($storage);
- }
-
- public function testStorageZeroMinTtlThrowsException(): void
- {
- $this->expectException(CacheException::class);
- $storage = $this->createMockedStorage(null, null, true, 0);
+ $storage = $this->createMockedStorage(null, null, ttlSupported: false);
$this->getAdapter($storage);
}
@@ -930,7 +915,7 @@ public function testWontSaveAlreadyExpiredCacheItemAsDeferredItem(): void
$adapter
->expects(self::atLeast(3))
->method('getCapabilities')
- ->willReturn($this->createCapabilities($adapter));
+ ->willReturn($this->createCapabilities());
$adapter
->expects(self::never())
@@ -973,11 +958,7 @@ public function testWillUsePcreMaximumQuantifierLengthIfAdapterAllowsMoreThanTha
{
$storage = $this->createMock(FlushableStorageAdapterInterface::class);
$capabilities = $this->createCapabilities(
- $storage,
- null,
- true,
- 60,
- SimpleCacheDecorator::$pcreMaximumQuantifierLength
+ maxKeyLength: SimpleCacheDecorator::$pcreMaximumQuantifierLength
);
$storage
@@ -1008,23 +989,22 @@ public function testPcreMaximumQuantifierLengthWontResultInCompilationError(): v
);
}
+ /**
+ * @param SupportedDataTypesArrayShape|null $supportedDataTypes
+ * @param int<-1,max> $maxKeyLength
+ */
private function createCapabilities(
- StorageInterface $storage,
?array $supportedDataTypes = null,
- bool $staticTtl = true,
- int $minTtl = 1,
+ bool $ttlSupported = true,
int $maxKeyLength = -1,
bool $useRequestTime = false,
- bool $lockOnExpire = false
): Capabilities {
- return new Capabilities($storage, new stdClass(), [
- 'supportedDatatypes' => $supportedDataTypes ?? $this->requiredTypes,
- 'staticTtl' => $staticTtl,
- 'minTtl' => $minTtl,
- 'maxKeyLength' => $maxKeyLength,
- 'useRequestTime' => $useRequestTime,
- 'lockOnExpire' => $lockOnExpire,
- ]);
+ return new Capabilities(
+ maxKeyLength: $maxKeyLength,
+ ttlSupported: $ttlSupported,
+ supportedDataTypes: $supportedDataTypes ?? self::REQUIRED_TYPES,
+ usesRequestTime: $useRequestTime,
+ );
}
public function testKeepsDeferredItemsWhenCommitFails(): void
diff --git a/test/Psr/SimpleCache/SimpleCacheDecoratorTest.php b/test/Psr/SimpleCache/SimpleCacheDecoratorTest.php
index 05d831f8..c4c0698e 100644
--- a/test/Psr/SimpleCache/SimpleCacheDecoratorTest.php
+++ b/test/Psr/SimpleCache/SimpleCacheDecoratorTest.php
@@ -39,11 +39,11 @@
* try/catch blocks and assert identity against the result of getPrevious().
*
* phpcs:disable Generic.Files.LineLength.TooLong
+ * @psalm-import-type SupportedDataTypesArrayShape from Capabilities
*/
-class SimpleCacheDecoratorTest extends TestCase
+final class SimpleCacheDecoratorTest extends TestCase
{
- /** @var array */
- private array $requiredTypes = [
+ private const SIMPLE_CACHE_REQUIRED_TYPES = [
'NULL' => true,
'boolean' => true,
'integer' => true,
@@ -68,7 +68,7 @@ class SimpleCacheDecoratorTest extends TestCase
public function unsupportedCapabilities(): Generator
{
yield 'minimum key length <64 characters' => [
- $this->getMockCapabilities(null, true, 60, 63),
+ $this->createCapabilities(null, true, 63),
];
}
@@ -80,43 +80,36 @@ protected function setUp(): void
$this->cache = new SimpleCacheDecorator($this->storage);
}
- private function getMockCapabilities(
+ /**
+ * @param SupportedDataTypesArrayShape|null $supportedDataTypes
+ * @param int<-1,max> $maxKeyLength
+ */
+ private function createCapabilities(
?array $supportedDataTypes = null,
- bool $staticTtl = true,
- int $minTtl = 60,
+ bool $ttlSupported = true,
int $maxKeyLength = -1
): Capabilities {
- $supportedDataTypes = $supportedDataTypes ?? $this->requiredTypes;
- $capabilities = $this->createMock(Capabilities::class);
- $capabilities
- ->method('getSupportedDatatypes')
- ->willReturn($supportedDataTypes);
-
- $capabilities
- ->method('getStaticTtl')
- ->willReturn($staticTtl);
- $capabilities
- ->method('getMinTtl')
- ->willReturn($minTtl);
-
- $capabilities
- ->method('getMaxKeyLength')
- ->willReturn($maxKeyLength);
-
- return $capabilities;
+ $supportedDataTypes = $supportedDataTypes ?? self::SIMPLE_CACHE_REQUIRED_TYPES;
+ return new Capabilities(
+ maxKeyLength: $maxKeyLength,
+ ttlSupported: $ttlSupported,
+ supportedDataTypes: $supportedDataTypes,
+ );
}
+ /**
+ * @param SupportedDataTypesArrayShape|null $supportedDataTypes
+ * @param int<-1,max> $maxKeyLength
+ */
private function mockCapabilities(
- MockObject $storage,
+ MockObject&StorageInterface $storage,
?array $supportedDataTypes = null,
- bool $staticTtl = true,
- int $minTtl = 60,
+ bool $ttlSupported = true,
int $maxKeyLength = -1
): void {
- $capabilities = $this->getMockCapabilities(
+ $capabilities = $this->createCapabilities(
$supportedDataTypes,
- $staticTtl,
- $minTtl,
+ $ttlSupported,
$maxKeyLength
);
@@ -168,16 +161,14 @@ public function invalidatingTtls()
public function testStorageNeedsSerializerWillThrowException(): void
{
- $dataTypes = [
- 'staticTtl' => true,
- 'minTtl' => 1,
- 'supportedDatatypes' => [
+ $storage = $this->createMock(StorageInterface::class);
+ $this->mockCapabilities(
+ $storage,
+ supportedDataTypes: [
'double' => false,
],
- ];
+ );
- $storage = $this->createMock(StorageInterface::class);
- $this->mockCapabilities($storage, $dataTypes, false);
$storage
->expects(self::never())
->method('getOptions');
@@ -320,10 +311,10 @@ public function testSetShouldRemoveItemFromCacheIfTtlIsBelow1($ttl)
self::assertTrue($this->cache->set('key', 'value', $ttl));
}
- public function testSetShouldReturnFalseWhenProvidedWithPositiveTtlAndStorageDoesNotSupportPerItemTtl(): void
+ public function testSetShouldReturnFalseWhenProvidedWithPositiveTtlAndStorageDoesNotSupportTtl(): void
{
$storage = $this->createMock(StorageInterface::class);
- $this->mockCapabilities($storage, null, false);
+ $this->mockCapabilities($storage, null, ttlSupported: false);
$storage
->expects(self::never())
->method('getOptions');
@@ -339,12 +330,11 @@ public function testSetShouldReturnFalseWhenProvidedWithPositiveTtlAndStorageDoe
/**
* @dataProvider invalidatingTtls
- * @param int $ttl
*/
- public function testSetShouldRemoveItemFromCacheIfTtlIsBelow1AndStorageDoesNotSupportPerItemTtl($ttl)
+ public function testSetShouldRemoveItemFromCacheIfTtlIsBelow1AndStorageDoesNotSupportTtl(int $ttl): void
{
$storage = $this->createMock(StorageInterface::class);
- $this->mockCapabilities($storage, null, false);
+ $this->mockCapabilities($storage, null, ttlSupported: false);
$storage
->expects(self::never())
->method('getOptions');
@@ -390,7 +380,7 @@ public function testSetShouldAcknowledgeStorageAdapterMaxKeyLengthWithPsrDecorat
->method('getOptions')
->willReturn($this->options);
- $this->mockCapabilities($storage, null, false, 60, 251);
+ $this->mockCapabilities($storage, null, true, 251);
$storage
->expects(self::once())
->method('setItem')
@@ -747,7 +737,7 @@ public function testSetMultipleShouldRemoveItemsFromCacheIfTtlIsBelow1($ttl)
self::assertTrue($this->cache->setMultiple($values, $ttl));
}
- public function testSetMultipleShouldReturnFalseWhenProvidedWithPositiveTtlAndStorageDoesNotSupportPerItemTtl(): void
+ public function testSetMultipleShouldReturnFalseWhenProvidedWithPositiveTtlAndStorageDoesNotSupportTtl(): void
{
$values = [
'one' => 1,
@@ -756,7 +746,7 @@ public function testSetMultipleShouldReturnFalseWhenProvidedWithPositiveTtlAndSt
];
$storage = $this->createMock(StorageInterface::class);
- $this->mockCapabilities($storage, null, false);
+ $this->mockCapabilities($storage, null, ttlSupported: false);
$storage
->expects(self::never())
->method('getOptions');
@@ -772,9 +762,8 @@ public function testSetMultipleShouldReturnFalseWhenProvidedWithPositiveTtlAndSt
/**
* @dataProvider invalidatingTtls
- * @param int $ttl
*/
- public function testSetMultipleShouldRemoveItemsFromCacheIfTtlIsBelow1AndStorageDoesNotSupportPerItemTtl($ttl)
+ public function testSetMultipleShouldRemoveItemsFromCacheIfTtlIsBelow1AndStorageDoesNotSupportTtl(int $ttl): void
{
$values = [
'one' => 1,
@@ -783,7 +772,7 @@ public function testSetMultipleShouldRemoveItemsFromCacheIfTtlIsBelow1AndStorage
];
$storage = $this->createMock(StorageInterface::class);
- $this->mockCapabilities($storage, null, false);
+ $this->mockCapabilities($storage, ttlSupported: false);
$storage
->expects(self::never())
->method('getOptions');
@@ -986,7 +975,7 @@ public function testHasReRaisesExceptionThrownByStorage(): void
public function testUseTtlFromOptionsWhenNotProvidedOnSet(): void
{
- $capabilities = $this->getMockCapabilities();
+ $capabilities = $this->createCapabilities();
$storage = new TestAsset\TtlStorage(['ttl' => 20]);
$storage->setCapabilities($capabilities);
@@ -999,7 +988,7 @@ public function testUseTtlFromOptionsWhenNotProvidedOnSet(): void
public function testUseTtlFromOptionsWhenNotProvidedOnSetMultiple(): void
{
- $capabilities = $this->getMockCapabilities();
+ $capabilities = $this->createCapabilities();
$storage = new TestAsset\TtlStorage(['ttl' => 20]);
$storage->setCapabilities($capabilities);
@@ -1082,11 +1071,10 @@ public function testWillThrowExceptionWhenStorageDoesNotFulfillMinimumRequiremen
public function testWillUsePcreMaximumQuantifierLengthIfAdapterAllowsMoreThanThat(): void
{
$storage = $this->createMock(StorageInterface::class);
- $capabilities = $this->getMockCapabilities(
+ $capabilities = $this->createCapabilities(
null,
- true,
- 60,
- SimpleCacheDecorator::$pcreMaximumQuantifierLength
+ ttlSupported: true,
+ maxKeyLength: SimpleCacheDecorator::$pcreMaximumQuantifierLength
);
$storage
@@ -1121,7 +1109,7 @@ public function testGeneratorFloatKeyIsDetectedAsInvalidKey(): void
{
$storage = $this->createMock(StorageInterface::class);
- $capabilities = $this->getMockCapabilities();
+ $capabilities = $this->createCapabilities();
$storage
->method('getCapabilities')
diff --git a/test/Storage/Adapter/AbstractAdapterTest.php b/test/Storage/Adapter/AbstractAdapterTest.php
index beb911ca..81c87f62 100644
--- a/test/Storage/Adapter/AbstractAdapterTest.php
+++ b/test/Storage/Adapter/AbstractAdapterTest.php
@@ -24,7 +24,6 @@
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionMethod;
-use stdClass;
use function array_keys;
use function array_merge;
@@ -371,7 +370,7 @@ public function testGetItemReturnsNullIfFailed(): void
public function simpleEventHandlingMethodDefinitions(): array
{
- $capabilities = new Capabilities($this->getMockForAbstractAdapter(), new stdClass());
+ $capabilities = new Capabilities();
return [
// name, internalName, args, returnValue
diff --git a/test/Storage/CapabilitiesTest.php b/test/Storage/CapabilitiesTest.php
deleted file mode 100644
index f1bcec8f..00000000
--- a/test/Storage/CapabilitiesTest.php
+++ /dev/null
@@ -1,99 +0,0 @@
-marker = new stdClass();
- $this->adapter = $this->createMock(StorageInterface::class);
-
- $this->baseCapabilities = new Capabilities($this->adapter, $this->marker);
- $this->capabilities = new Capabilities($this->adapter, $this->marker, [], $this->baseCapabilities);
- }
-
- public function testGetAdapter(): void
- {
- self::assertSame($this->adapter, $this->capabilities->getAdapter());
- self::assertSame($this->adapter, $this->baseCapabilities->getAdapter());
- }
-
- public function testSetAndGetCapability(): void
- {
- $this->capabilities->setMaxTtl($this->marker, 100);
- self::assertEquals(100, $this->capabilities->getMaxTtl());
- }
-
- public function testGetCapabilityByBaseCapabilities(): void
- {
- $this->baseCapabilities->setMaxTtl($this->marker, 100);
- self::assertEquals(100, $this->capabilities->getMaxTtl());
- }
-
- public function testTriggerCapabilityEvent(): void
- {
- $eventManager = $this->createMock(EventManagerInterface::class);
-
- $adapter = $this->createMock(EventsCapableStorageInterface::class);
- $adapter
- ->expects(self::once())
- ->method('getEventManager')
- ->willReturn($eventManager);
-
- $eventManager
- ->expects(self::once())
- ->method('trigger')
- ->with('capability', $adapter, self::callback(static function ($params): bool {
- self::assertInstanceOf(ArrayObject::class, $params);
- self::assertTrue(isset($params['maxTtl']));
- self::assertEquals(100, $params['maxTtl']);
- return true;
- }));
-
- $capabilities = new Capabilities($adapter, $this->marker);
- $capabilities->setMaxTtl($this->marker, 100);
- }
-}
diff --git a/test/Storage/TestAsset/EventsCapableStorageInterface.php b/test/Storage/TestAsset/EventsCapableStorageInterface.php
deleted file mode 100644
index b2b7a459..00000000
--- a/test/Storage/TestAsset/EventsCapableStorageInterface.php
+++ /dev/null
@@ -1,12 +0,0 @@
-