From 18e61abd3775221c8ecc657fd3fb81dc049de28f Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Thu, 18 Feb 2021 19:23:20 -0500 Subject: [PATCH] Add appropriate parameter types for updated psr/cache interface --- CHANGELOG.md | 4 ++++ composer.json | 6 +++--- src/Driver/AbstractDriver.php | 5 +---- src/Driver/ApcuDriver.php | 15 +++++++-------- src/Driver/DriverInterface.php | 8 +++++--- src/Driver/MemcachedDriver.php | 24 ++++++++++++++++-------- src/Driver/NullDriver.php | 14 ++++++-------- src/Driver/RedisDriver.php | 10 ++++++---- src/Item.php | 14 +++++++------- src/KeyValidateTrait.php | 17 +++++------------ src/Pool.php | 12 ++++++------ src/Teller.php | 25 ++++++++++++++++++++++--- tests/Driver/DriverTestBase.php | 1 + tests/PoolTest.php | 11 +++++------ tests/TellerTest.php | 4 +++- 15 files changed, 97 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95df514..2b05858 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 4.0.0 +* Updated Cache implementation to latest version +* Increased required PHP version to 8 + ## 3.2.0 * Improved validation of cache keys * Updated dependencies diff --git a/composer.json b/composer.json index aa7d3a3..ebde058 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "psr-16" ], "provide": { - "psr/cache-implementation": "^1.0.0", + "psr/cache-implementation": "^3.0.0", "psr/simple-cache-implementation": "^1.0.0" }, "autoload": { @@ -26,11 +26,11 @@ } }, "require": { - "php": ">=7.4", + "php": ">= 8", "ext-json": "*", "predis/predis": "^1.1", "psr/log": "^1.0", - "psr/cache": "^1.0.1", + "psr/cache": "^3.0.0", "psr/simple-cache": "^1.0.1" }, "require-dev": { diff --git a/src/Driver/AbstractDriver.php b/src/Driver/AbstractDriver.php index ea575ad..054230b 100644 --- a/src/Driver/AbstractDriver.php +++ b/src/Driver/AbstractDriver.php @@ -36,11 +36,8 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface { /** * Common constructor interface for driver classes - * - * @param array $config - Connection parameters for the specified backend - * @param array $options - Special connection options for the specified backend */ - abstract public function __construct(array $config = [], array $options = []); + abstract public function __construct(); /** * Retrieve a set of values by their cache key diff --git a/src/Driver/ApcuDriver.php b/src/Driver/ApcuDriver.php index 5e2bd12..6af251a 100644 --- a/src/Driver/ApcuDriver.php +++ b/src/Driver/ApcuDriver.php @@ -17,6 +17,7 @@ namespace Aviat\Banker\Driver; use Aviat\Banker\Exception\CacheException; +use DateInterval; use function apcu_clear_cache; use function apcu_delete; use function apcu_exists; @@ -31,12 +32,10 @@ class ApcuDriver extends AbstractDriver { /** * Constructor * - * @param array $config - Not used by this driver - * @param array $options - Not used by this driver * @throws CacheException * @codeCoverageIgnore */ - public function __construct(array $config = [], array $options = []) + public function __construct() { if ( ! extension_loaded('apcu')) { @@ -61,7 +60,7 @@ class ApcuDriver extends AbstractDriver { * @param string $key * @return mixed */ - public function get(string $key) + public function get(string $key): mixed { return apcu_fetch($key); } @@ -85,10 +84,10 @@ class ApcuDriver extends AbstractDriver { * * @param string $key * @param mixed $value - * @param int $expires + * @param int|DateInterval|null $expires * @return bool */ - public function set(string $key, $value, ?int $expires = NULL): bool + public function set(string $key, mixed $value, int|DateInterval|null $expires = NULL): bool { $ttl = $this->getTTLFromExpiration($expires); @@ -174,10 +173,10 @@ class ApcuDriver extends AbstractDriver { /** * Convert expiration date argument into TTL argument * - * @param int $expires + * @param int|null $expires * @return int */ - protected function getTTLFromExpiration($expires): int + protected function getTTLFromExpiration(?int $expires): int { $ttl = (int)$expires - time(); diff --git a/src/Driver/DriverInterface.php b/src/Driver/DriverInterface.php index 6bf9dd5..535ae75 100644 --- a/src/Driver/DriverInterface.php +++ b/src/Driver/DriverInterface.php @@ -15,6 +15,8 @@ */ namespace Aviat\Banker\Driver; +use DateInterval; + /** * Interface for different cache backends */ @@ -33,10 +35,10 @@ interface DriverInterface { * * @param string $key * @param mixed $value - * @param int $expires + * @param DateInterval|int|null $expires * @return bool */ - public function set(string $key, $value, ?int $expires = NULL): bool; + public function set(string $key, mixed $value, DateInterval|int|null $expires = NULL): bool; /** * Get the value for the selected cache key @@ -44,7 +46,7 @@ interface DriverInterface { * @param string $key * @return mixed */ - public function get(string $key); + public function get(string $key): mixed; /** * Retrieve a set of values by their cache key diff --git a/src/Driver/MemcachedDriver.php b/src/Driver/MemcachedDriver.php index e69cc7a..f3f7e96 100644 --- a/src/Driver/MemcachedDriver.php +++ b/src/Driver/MemcachedDriver.php @@ -17,6 +17,8 @@ namespace Aviat\Banker\Driver; use Aviat\Banker\Exception\CacheException; +use Aviat\Banker\Exception\InvalidArgumentException; +use DateInterval; use Memcached; use MemcachedException; @@ -28,7 +30,7 @@ class MemcachedDriver extends AbstractDriver { /** * @var Memcached */ - private ?Memcached $conn; + private Memcached $conn; /** * Driver for PHP Memcache extension @@ -96,7 +98,7 @@ class MemcachedDriver extends AbstractDriver { * @param string $key * @return mixed */ - public function get(string $key) + public function get(string $key): mixed { return $this->conn->get($key); } @@ -120,10 +122,11 @@ class MemcachedDriver extends AbstractDriver { * * @param string $key * @param mixed $value - * @param int $expires + * @param int|DateInterval|null $expires * @return bool + * @throws InvalidArgumentException */ - public function set(string $key, $value, ?int $expires = NULL): bool + public function set(string $key, mixed $value, int|DateInterval|null $expires = NULL): bool { $this->validateKey($key); @@ -171,15 +174,20 @@ class MemcachedDriver extends AbstractDriver { $deleted = $this->conn->deleteMulti($keys); - foreach ($deleted as $key => $status) + if (is_array($deleted)) { - if ($status !== TRUE) + foreach ($deleted as $key => $status) { - return FALSE; + if ($status !== TRUE) + { + return FALSE; + } } + + return TRUE; } - return TRUE; + return FALSE; } /** diff --git a/src/Driver/NullDriver.php b/src/Driver/NullDriver.php index 5f41498..5117684 100644 --- a/src/Driver/NullDriver.php +++ b/src/Driver/NullDriver.php @@ -15,6 +15,7 @@ */ namespace Aviat\Banker\Driver; +use DateInterval; /** * Cache backend for use without a cache server. Only does transient @@ -30,12 +31,9 @@ class NullDriver extends AbstractDriver { protected array $store = []; /** - * NullDriver constructor. - * - * @param array $config - * @param array $options + * NullDriver constructor */ - public function __construct(array $config = [], array $options = []) + public function __construct() { $this->store = []; } @@ -57,7 +55,7 @@ class NullDriver extends AbstractDriver { * @param string $key * @return mixed */ - public function get(string $key) + public function get(string $key): mixed { return $this->exists($key) ? $this->store[$key] @@ -69,10 +67,10 @@ class NullDriver extends AbstractDriver { * * @param string $key * @param mixed $value - * @param int $expires + * @param DateInterval|int|null $expires * @return bool */ - public function set(string $key, $value, ?int $expires = NULL): bool + public function set(string $key, mixed $value, DateInterval|int|null $expires = NULL): bool { $this->store[$key] = $value; return $this->store[$key] === $value; diff --git a/src/Driver/RedisDriver.php b/src/Driver/RedisDriver.php index 7856613..571a4ed 100644 --- a/src/Driver/RedisDriver.php +++ b/src/Driver/RedisDriver.php @@ -18,6 +18,8 @@ namespace Aviat\Banker\Driver; use Aviat\Banker\Exception\CacheException; use Predis\Client; +use DateInterval; + /** * Redis cache backend */ @@ -28,7 +30,7 @@ class RedisDriver extends AbstractDriver { * * @var Client */ - protected ?Client $conn; + protected Client $conn; /** * RedisDriver constructor. @@ -74,7 +76,7 @@ class RedisDriver extends AbstractDriver { * @param string $key * @return mixed */ - public function get(string $key) + public function get(string $key): mixed { $raw = $this->conn->get($key); return unserialize($raw); @@ -85,10 +87,10 @@ class RedisDriver extends AbstractDriver { * * @param string $key * @param mixed $value - * @param int $expires + * @param int|null $expires * @return bool */ - public function set(string $key, $value, ?int $expires = NULL): bool + public function set(string $key, mixed $value, DateInterval|int|null $expires = NULL): bool { $value = serialize($value); diff --git a/src/Item.php b/src/Item.php index 93fc519..e965904 100644 --- a/src/Item.php +++ b/src/Item.php @@ -102,7 +102,7 @@ class Item implements CacheItemInterface { * @return mixed * The value corresponding to this cache item's key, or null if not found. */ - public function get() + public function get(): mixed { if ($this->isHit()) { @@ -136,10 +136,10 @@ class Item implements CacheItemInterface { * @param mixed $value * The serializable value to be stored. * - * @return Item + * @return static * The invoked object. */ - public function set($value): Item + public function set(mixed $value): static { $this->value = $value; return $this; @@ -154,10 +154,10 @@ class Item implements CacheItemInterface { * the value should be stored permanently or for as long as the * implementation allows. * - * @return Item + * @return static * The called object. */ - public function expiresAt($expiration = NULL): Item + public function expiresAt($expiration = NULL): static { if ($expiration instanceof DateTimeInterface) { @@ -179,10 +179,10 @@ class Item implements CacheItemInterface { * If none is set, the value should be stored permanently or for as long as the * implementation allows. * - * @return Item + * @return static * The called object. */ - public function expiresAfter($time = NULL): Item + public function expiresAfter($time = NULL): static { if ($time instanceof DateInterval) { diff --git a/src/KeyValidateTrait.php b/src/KeyValidateTrait.php index 5a2a21a..418d442 100644 --- a/src/KeyValidateTrait.php +++ b/src/KeyValidateTrait.php @@ -19,29 +19,22 @@ use Aviat\Banker\Exception\InvalidArgumentException; trait KeyValidateTrait { /** - * @param $keys + * @param iterable $keys * @param bool $hash - * @throws InvalidArgumentException */ - protected function validateKeys($keys, bool $hash = FALSE): void + protected function validateKeys(iterable $keys, bool $hash = FALSE): void { - // Check type of keys - if ( ! is_iterable($keys)) - { - throw new InvalidArgumentException('Keys must be an array or a traversable object'); - } - $keys = ($hash) ? array_keys((array)$keys) : (array)$keys; // Check each key - array_walk($keys, fn($key) => $this->validateKey($key)); + array_walk($keys, [$this, 'validateKey']); } /** - * @param string $key + * @param mixed $key * @throws InvalidArgumentException */ - protected function validateKey($key): void + protected function validateKey(mixed $key): void { if ( ! is_string($key)) { diff --git a/src/Pool.php b/src/Pool.php index a53cc02..b814311 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -39,7 +39,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * Set up the cache backend * * @param array $config - * @param LoggerInterface $logger + * @param LoggerInterface|null $logger */ public function __construct(array $config, ?LoggerInterface $logger = NULL) { @@ -67,7 +67,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * @return CacheItemInterface * The corresponding Cache Item. */ - public function getItem($key): CacheItemInterface + public function getItem(string $key): CacheItemInterface { $this->validateKey($key); @@ -90,13 +90,13 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException * MUST be thrown. * - * @return array|\Traversable + * @return iterable * A traversable collection of Cache Items keyed by the cache keys of * each item. A Cache item will be returned for each key, even if that * key is not found. However, if no keys are specified then an empty * traversable MUST be returned instead. */ - public function getItems(array $keys = []) + public function getItems(array $keys = []): iterable { $this->validateKeys($keys); @@ -134,7 +134,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * @return bool * True if item exists in the cache, false otherwise. */ - public function hasItem($key): bool + public function hasItem(string $key): bool { $this->validateKey($key); @@ -171,7 +171,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * @return bool * True if the item was successfully removed. False if there was an error. */ - public function deleteItem($key): bool + public function deleteItem(string $key): bool { $this->validateKey($key); diff --git a/src/Teller.php b/src/Teller.php index 0bf6eb2..ad6b164 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -15,6 +15,7 @@ */ namespace Aviat\Banker; +use Aviat\Banker\Exception\InvalidArgumentException; use Psr\Log\LoggerAwareInterface; use Psr\SimpleCache; use Psr\Log\LoggerInterface; @@ -30,7 +31,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface { * Set up the cache backend * * @param array $config - * @param LoggerInterface $logger + * @param LoggerInterface|null $logger */ public function __construct(array $config, ?LoggerInterface $logger = NULL) { @@ -53,7 +54,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface { * @throws SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ - public function get($key, $default = null) + public function get($key, $default = null):mixed { $this->validateKey($key); @@ -74,7 +75,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface { * @throws SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ - public function set($key, $value, $ttl = null): bool + public function set($key, mixed $value, $ttl = null): bool { $this->validateKey($key); @@ -122,6 +123,12 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface { */ public function getMultiple($keys, $default = null) { + // Check type of keys + if ( ! is_iterable($keys)) + { + throw new InvalidArgumentException('Keys must be an array or a traversable object'); + } + $this->validateKeys($keys); return $this->driver->getMultiple((array)$keys); @@ -143,6 +150,12 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface { */ public function setMultiple($values, $ttl = null): bool { + // Check type of keys + if ( ! is_iterable($values)) + { + throw new InvalidArgumentException('Values must be an array or a traversable object'); + } + $this->validateKeys($values, TRUE); return ($ttl === NULL) @@ -163,6 +176,12 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface { */ public function deleteMultiple($keys): bool { + // Check type of keys + if ( ! is_iterable($keys)) + { + throw new InvalidArgumentException('Keys must be an array or a traversable object'); + } + $this->validateKeys($keys); return $this->driver->deleteMultiple((array)$keys); diff --git a/tests/Driver/DriverTestBase.php b/tests/Driver/DriverTestBase.php index 194f562..1ae3549 100644 --- a/tests/Driver/DriverTestBase.php +++ b/tests/Driver/DriverTestBase.php @@ -18,6 +18,7 @@ namespace Aviat\Banker\Tests\Driver; use Aviat\Banker\Driver\DriverInterface; use Aviat\Banker\Exception\InvalidArgumentException; use PHPUnit\Framework\TestCase; +use TypeError; class DriverTestBase extends TestCase { diff --git a/tests/PoolTest.php b/tests/PoolTest.php index 9fd517a..e0ed383 100644 --- a/tests/PoolTest.php +++ b/tests/PoolTest.php @@ -21,6 +21,7 @@ use Monolog\Logger; use Monolog\Handler\SyslogHandler; use PHPUnit\Framework\TestCase; use Psr\Log\{LoggerInterface, NullLogger}; +use TypeError; class PoolTest extends TestCase { @@ -97,8 +98,7 @@ class PoolTest extends TestCase { public function testItemBadKey(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Cache key must be a string.'); + $this->expectException(TypeError::class); $this->pool->getItem([]); } @@ -173,8 +173,7 @@ class PoolTest extends TestCase { { $this->pool->clear(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Cache key must be a string.'); + $this->expectException(TypeError::class); $this->pool->hasItem(34); } @@ -213,8 +212,8 @@ class PoolTest extends TestCase { public function testDeleteItemBadKey(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Cache key must be a string.'); + $this->expectException(TypeError::class); + // $this->expectExceptionMessage('Cache key must be a string.'); $this->pool->deleteItem(34); } diff --git a/tests/TellerTest.php b/tests/TellerTest.php index e4978c6..6c0c7b3 100644 --- a/tests/TellerTest.php +++ b/tests/TellerTest.php @@ -201,8 +201,10 @@ class TellerTest extends TestCase { /** * @dataProvider keyValidationTests + * @param string $key + * @throws \Psr\SimpleCache\InvalidArgumentException */ - public function testKeyValidation($key): void + public function testKeyValidation(string $key): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid characters in cache key');