Add appropriate parameter types for updated psr/cache interface
Gitea - aviat/banker/pipeline/head This commit looks good Details

This commit is contained in:
Timothy Warren 2021-02-18 19:23:20 -05:00
parent 94f40e6cd0
commit 18e61abd37
15 changed files with 97 additions and 73 deletions

View File

@ -1,5 +1,9 @@
# Changelog # Changelog
## 4.0.0
* Updated Cache implementation to latest version
* Increased required PHP version to 8
## 3.2.0 ## 3.2.0
* Improved validation of cache keys * Improved validation of cache keys
* Updated dependencies * Updated dependencies

View File

@ -12,7 +12,7 @@
"psr-16" "psr-16"
], ],
"provide": { "provide": {
"psr/cache-implementation": "^1.0.0", "psr/cache-implementation": "^3.0.0",
"psr/simple-cache-implementation": "^1.0.0" "psr/simple-cache-implementation": "^1.0.0"
}, },
"autoload": { "autoload": {
@ -26,11 +26,11 @@
} }
}, },
"require": { "require": {
"php": ">=7.4", "php": ">= 8",
"ext-json": "*", "ext-json": "*",
"predis/predis": "^1.1", "predis/predis": "^1.1",
"psr/log": "^1.0", "psr/log": "^1.0",
"psr/cache": "^1.0.1", "psr/cache": "^3.0.0",
"psr/simple-cache": "^1.0.1" "psr/simple-cache": "^1.0.1"
}, },
"require-dev": { "require-dev": {

View File

@ -36,11 +36,8 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
/** /**
* Common constructor interface for driver classes * 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 * Retrieve a set of values by their cache key

View File

@ -17,6 +17,7 @@ namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException; use Aviat\Banker\Exception\CacheException;
use DateInterval;
use function apcu_clear_cache; use function apcu_clear_cache;
use function apcu_delete; use function apcu_delete;
use function apcu_exists; use function apcu_exists;
@ -31,12 +32,10 @@ class ApcuDriver extends AbstractDriver {
/** /**
* Constructor * Constructor
* *
* @param array $config - Not used by this driver
* @param array $options - Not used by this driver
* @throws CacheException * @throws CacheException
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function __construct(array $config = [], array $options = []) public function __construct()
{ {
if ( ! extension_loaded('apcu')) if ( ! extension_loaded('apcu'))
{ {
@ -61,7 +60,7 @@ class ApcuDriver extends AbstractDriver {
* @param string $key * @param string $key
* @return mixed * @return mixed
*/ */
public function get(string $key) public function get(string $key): mixed
{ {
return apcu_fetch($key); return apcu_fetch($key);
} }
@ -85,10 +84,10 @@ class ApcuDriver extends AbstractDriver {
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int|DateInterval|null $expires
* @return bool * @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); $ttl = $this->getTTLFromExpiration($expires);
@ -174,10 +173,10 @@ class ApcuDriver extends AbstractDriver {
/** /**
* Convert expiration date argument into TTL argument * Convert expiration date argument into TTL argument
* *
* @param int $expires * @param int|null $expires
* @return int * @return int
*/ */
protected function getTTLFromExpiration($expires): int protected function getTTLFromExpiration(?int $expires): int
{ {
$ttl = (int)$expires - time(); $ttl = (int)$expires - time();

View File

@ -15,6 +15,8 @@
*/ */
namespace Aviat\Banker\Driver; namespace Aviat\Banker\Driver;
use DateInterval;
/** /**
* Interface for different cache backends * Interface for different cache backends
*/ */
@ -33,10 +35,10 @@ interface DriverInterface {
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param DateInterval|int|null $expires
* @return bool * @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 * Get the value for the selected cache key
@ -44,7 +46,7 @@ interface DriverInterface {
* @param string $key * @param string $key
* @return mixed * @return mixed
*/ */
public function get(string $key); public function get(string $key): mixed;
/** /**
* Retrieve a set of values by their cache key * Retrieve a set of values by their cache key

View File

@ -17,6 +17,8 @@ namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException; use Aviat\Banker\Exception\CacheException;
use Aviat\Banker\Exception\InvalidArgumentException;
use DateInterval;
use Memcached; use Memcached;
use MemcachedException; use MemcachedException;
@ -28,7 +30,7 @@ class MemcachedDriver extends AbstractDriver {
/** /**
* @var Memcached * @var Memcached
*/ */
private ?Memcached $conn; private Memcached $conn;
/** /**
* Driver for PHP Memcache extension * Driver for PHP Memcache extension
@ -96,7 +98,7 @@ class MemcachedDriver extends AbstractDriver {
* @param string $key * @param string $key
* @return mixed * @return mixed
*/ */
public function get(string $key) public function get(string $key): mixed
{ {
return $this->conn->get($key); return $this->conn->get($key);
} }
@ -120,10 +122,11 @@ class MemcachedDriver extends AbstractDriver {
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int|DateInterval|null $expires
* @return bool * @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); $this->validateKey($key);
@ -171,15 +174,20 @@ class MemcachedDriver extends AbstractDriver {
$deleted = $this->conn->deleteMulti($keys); $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;
} }
/** /**

View File

@ -15,6 +15,7 @@
*/ */
namespace Aviat\Banker\Driver; namespace Aviat\Banker\Driver;
use DateInterval;
/** /**
* Cache backend for use without a cache server. Only does transient * Cache backend for use without a cache server. Only does transient
@ -30,12 +31,9 @@ class NullDriver extends AbstractDriver {
protected array $store = []; protected array $store = [];
/** /**
* NullDriver constructor. * NullDriver constructor
*
* @param array $config
* @param array $options
*/ */
public function __construct(array $config = [], array $options = []) public function __construct()
{ {
$this->store = []; $this->store = [];
} }
@ -57,7 +55,7 @@ class NullDriver extends AbstractDriver {
* @param string $key * @param string $key
* @return mixed * @return mixed
*/ */
public function get(string $key) public function get(string $key): mixed
{ {
return $this->exists($key) return $this->exists($key)
? $this->store[$key] ? $this->store[$key]
@ -69,10 +67,10 @@ class NullDriver extends AbstractDriver {
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param DateInterval|int|null $expires
* @return bool * @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; $this->store[$key] = $value;
return $this->store[$key] === $value; return $this->store[$key] === $value;

View File

@ -18,6 +18,8 @@ namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException; use Aviat\Banker\Exception\CacheException;
use Predis\Client; use Predis\Client;
use DateInterval;
/** /**
* Redis cache backend * Redis cache backend
*/ */
@ -28,7 +30,7 @@ class RedisDriver extends AbstractDriver {
* *
* @var Client * @var Client
*/ */
protected ?Client $conn; protected Client $conn;
/** /**
* RedisDriver constructor. * RedisDriver constructor.
@ -74,7 +76,7 @@ class RedisDriver extends AbstractDriver {
* @param string $key * @param string $key
* @return mixed * @return mixed
*/ */
public function get(string $key) public function get(string $key): mixed
{ {
$raw = $this->conn->get($key); $raw = $this->conn->get($key);
return unserialize($raw); return unserialize($raw);
@ -85,10 +87,10 @@ class RedisDriver extends AbstractDriver {
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int|null $expires
* @return bool * @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); $value = serialize($value);

View File

@ -102,7 +102,7 @@ class Item implements CacheItemInterface {
* @return mixed * @return mixed
* The value corresponding to this cache item's key, or null if not found. * The value corresponding to this cache item's key, or null if not found.
*/ */
public function get() public function get(): mixed
{ {
if ($this->isHit()) if ($this->isHit())
{ {
@ -136,10 +136,10 @@ class Item implements CacheItemInterface {
* @param mixed $value * @param mixed $value
* The serializable value to be stored. * The serializable value to be stored.
* *
* @return Item * @return static
* The invoked object. * The invoked object.
*/ */
public function set($value): Item public function set(mixed $value): static
{ {
$this->value = $value; $this->value = $value;
return $this; return $this;
@ -154,10 +154,10 @@ class Item implements CacheItemInterface {
* the value should be stored permanently or for as long as the * the value should be stored permanently or for as long as the
* implementation allows. * implementation allows.
* *
* @return Item * @return static
* The called object. * The called object.
*/ */
public function expiresAt($expiration = NULL): Item public function expiresAt($expiration = NULL): static
{ {
if ($expiration instanceof DateTimeInterface) 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 * If none is set, the value should be stored permanently or for as long as the
* implementation allows. * implementation allows.
* *
* @return Item * @return static
* The called object. * The called object.
*/ */
public function expiresAfter($time = NULL): Item public function expiresAfter($time = NULL): static
{ {
if ($time instanceof DateInterval) if ($time instanceof DateInterval)
{ {

View File

@ -19,29 +19,22 @@ use Aviat\Banker\Exception\InvalidArgumentException;
trait KeyValidateTrait { trait KeyValidateTrait {
/** /**
* @param $keys * @param iterable $keys
* @param bool $hash * @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; $keys = ($hash) ? array_keys((array)$keys) : (array)$keys;
// Check each key // Check each key
array_walk($keys, fn($key) => $this->validateKey($key)); array_walk($keys, [$this, 'validateKey']);
} }
/** /**
* @param string $key * @param mixed $key
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
protected function validateKey($key): void protected function validateKey(mixed $key): void
{ {
if ( ! is_string($key)) if ( ! is_string($key))
{ {

View File

@ -39,7 +39,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* Set up the cache backend * Set up the cache backend
* *
* @param array $config * @param array $config
* @param LoggerInterface $logger * @param LoggerInterface|null $logger
*/ */
public function __construct(array $config, ?LoggerInterface $logger = NULL) public function __construct(array $config, ?LoggerInterface $logger = NULL)
{ {
@ -67,7 +67,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @return CacheItemInterface * @return CacheItemInterface
* The corresponding Cache Item. * The corresponding Cache Item.
*/ */
public function getItem($key): CacheItemInterface public function getItem(string $key): CacheItemInterface
{ {
$this->validateKey($key); $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 * If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
* MUST be thrown. * MUST be thrown.
* *
* @return array|\Traversable * @return iterable
* A traversable collection of Cache Items keyed by the cache keys of * 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 * 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 * key is not found. However, if no keys are specified then an empty
* traversable MUST be returned instead. * traversable MUST be returned instead.
*/ */
public function getItems(array $keys = []) public function getItems(array $keys = []): iterable
{ {
$this->validateKeys($keys); $this->validateKeys($keys);
@ -134,7 +134,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @return bool * @return bool
* True if item exists in the cache, false otherwise. * True if item exists in the cache, false otherwise.
*/ */
public function hasItem($key): bool public function hasItem(string $key): bool
{ {
$this->validateKey($key); $this->validateKey($key);
@ -171,7 +171,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @return bool * @return bool
* True if the item was successfully removed. False if there was an error. * 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); $this->validateKey($key);

View File

@ -15,6 +15,7 @@
*/ */
namespace Aviat\Banker; namespace Aviat\Banker;
use Aviat\Banker\Exception\InvalidArgumentException;
use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareInterface;
use Psr\SimpleCache; use Psr\SimpleCache;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -30,7 +31,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* Set up the cache backend * Set up the cache backend
* *
* @param array $config * @param array $config
* @param LoggerInterface $logger * @param LoggerInterface|null $logger
*/ */
public function __construct(array $config, ?LoggerInterface $logger = NULL) public function __construct(array $config, ?LoggerInterface $logger = NULL)
{ {
@ -53,7 +54,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* @throws SimpleCache\InvalidArgumentException * @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value. * 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); $this->validateKey($key);
@ -74,7 +75,7 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
* @throws SimpleCache\InvalidArgumentException * @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value. * 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); $this->validateKey($key);
@ -122,6 +123,12 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
*/ */
public function getMultiple($keys, $default = null) 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); $this->validateKeys($keys);
return $this->driver->getMultiple((array)$keys); return $this->driver->getMultiple((array)$keys);
@ -143,6 +150,12 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
*/ */
public function setMultiple($values, $ttl = null): bool 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); $this->validateKeys($values, TRUE);
return ($ttl === NULL) return ($ttl === NULL)
@ -163,6 +176,12 @@ class Teller implements SimpleCache\CacheInterface, LoggerAwareInterface {
*/ */
public function deleteMultiple($keys): bool 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); $this->validateKeys($keys);
return $this->driver->deleteMultiple((array)$keys); return $this->driver->deleteMultiple((array)$keys);

View File

@ -18,6 +18,7 @@ namespace Aviat\Banker\Tests\Driver;
use Aviat\Banker\Driver\DriverInterface; use Aviat\Banker\Driver\DriverInterface;
use Aviat\Banker\Exception\InvalidArgumentException; use Aviat\Banker\Exception\InvalidArgumentException;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use TypeError;
class DriverTestBase extends TestCase { class DriverTestBase extends TestCase {

View File

@ -21,6 +21,7 @@ use Monolog\Logger;
use Monolog\Handler\SyslogHandler; use Monolog\Handler\SyslogHandler;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\{LoggerInterface, NullLogger}; use Psr\Log\{LoggerInterface, NullLogger};
use TypeError;
class PoolTest extends TestCase { class PoolTest extends TestCase {
@ -97,8 +98,7 @@ class PoolTest extends TestCase {
public function testItemBadKey(): void public function testItemBadKey(): void
{ {
$this->expectException(InvalidArgumentException::class); $this->expectException(TypeError::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->pool->getItem([]); $this->pool->getItem([]);
} }
@ -173,8 +173,7 @@ class PoolTest extends TestCase {
{ {
$this->pool->clear(); $this->pool->clear();
$this->expectException(InvalidArgumentException::class); $this->expectException(TypeError::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->pool->hasItem(34); $this->pool->hasItem(34);
} }
@ -213,8 +212,8 @@ class PoolTest extends TestCase {
public function testDeleteItemBadKey(): void public function testDeleteItemBadKey(): void
{ {
$this->expectException(InvalidArgumentException::class); $this->expectException(TypeError::class);
$this->expectExceptionMessage('Cache key must be a string.'); // $this->expectExceptionMessage('Cache key must be a string.');
$this->pool->deleteItem(34); $this->pool->deleteItem(34);
} }

View File

@ -201,8 +201,10 @@ class TellerTest extends TestCase {
/** /**
* @dataProvider keyValidationTests * @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->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid characters in cache key'); $this->expectExceptionMessage('Invalid characters in cache key');