Implement PSR-16
Some checks failed
Gitea - aviat/banker/pipeline/head There was a failure building this commit

This commit is contained in:
Timothy Warren 2020-05-07 17:17:03 -04:00
parent ac22e0d647
commit f31fe826b0
26 changed files with 562 additions and 154 deletions

View File

@ -1,5 +1,10 @@
# Changelog # Changelog
## 3.0.0
* Updated dependencies
* Increased required PHP version to 7.4
* Added SimpleCache (PSR-16) implementation in `Teller` class
## 2.0.0 ## 2.0.0
* Removed `Memcache` integration, as the extension does not seem to be maintained * Removed `Memcache` integration, as the extension does not seem to be maintained
* Increased required PHP version to 7.1 * Increased required PHP version to 7.1

View File

@ -51,7 +51,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Do static analysis tasks * Do static analysis tasks
*/ */
public function analyze() public function analyze(): void
{ {
$this->prepare(); $this->prepare();
$this->lint(); $this->lint();
@ -64,7 +64,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Run all tests, generate coverage, generate docs, generate code statistics * Run all tests, generate coverage, generate docs, generate code statistics
*/ */
public function build() public function build(): void
{ {
$this->analyze(); $this->analyze();
$this->coverage(); $this->coverage();
@ -74,22 +74,22 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Cleanup temporary files * Cleanup temporary files
*/ */
public function clean() public function clean(): void
{ {
$cleanFiles = [ $cleanFiles = [
'build/humbug.json', 'build/humbug.json',
'build/humbug-log.txt', 'build/humbug-log.txt',
]; ];
array_map(function ($file) { array_map(static function ($file) {
@unlink($file); @unlink($file);
}, $cleanFiles); }, $cleanFiles);
// So the task doesn't complain, // So the task doesn't complain,
// make any 'missing' dirs to cleanup // make any 'missing' dirs to cleanup
array_map(function ($dir) { array_map(static function ($dir) {
if ( ! is_dir($dir)) if ( ! is_dir($dir))
{ {
`mkdir -p {$dir}`; shell_exec("mkdir -p {$dir}");
} }
}, $this->cleanDirs); }, $this->cleanDirs);
@ -100,18 +100,15 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Run unit tests and generate coverage reports * Run unit tests and generate coverage reports
*/ */
public function coverage() public function coverage(): void
{ {
$this->taskPhpUnit() $this->_run(['phpdbg -qrr -- vendor/bin/phpunit -c build']);
->configFile('build/phpunit.xml')
->printed(true)
->run();
} }
/** /**
* Generate documentation with phpdox * Generate documentation with phpdox
*/ */
public function docs() public function docs(): void
{ {
$cmd_parts = [ $cmd_parts = [
'cd build', 'cd build',
@ -124,7 +121,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Verify that source files are valid * Verify that source files are valid
*/ */
public function lint() public function lint(): void
{ {
$files = $this->getAllSourceFiles(); $files = $this->getAllSourceFiles();
@ -142,7 +139,7 @@ class RoboFile extends \Robo\Tasks {
* *
* @param bool $stats - if true, generates stats rather than running mutation tests * @param bool $stats - if true, generates stats rather than running mutation tests
*/ */
public function mutate($stats = FALSE) public function mutate($stats = FALSE): void
{ {
$test_parts = [ $test_parts = [
'vendor/bin/humbug' 'vendor/bin/humbug'
@ -164,7 +161,7 @@ class RoboFile extends \Robo\Tasks {
* *
* @param bool $report - if true, generates reports instead of direct output * @param bool $report - if true, generates reports instead of direct output
*/ */
public function phpcs($report = FALSE) public function phpcs($report = FALSE): void
{ {
$report_cmd_parts = [ $report_cmd_parts = [
'vendor/bin/phpcs', 'vendor/bin/phpcs',
@ -187,7 +184,7 @@ class RoboFile extends \Robo\Tasks {
* *
* @param bool $report - if true, generates reports instead of direct output * @param bool $report - if true, generates reports instead of direct output
*/ */
public function phploc($report = FALSE) public function phploc($report = FALSE): void
{ {
// Command for generating reports // Command for generating reports
$report_cmd_parts = [ $report_cmd_parts = [
@ -215,7 +212,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Create temporary directories * Create temporary directories
*/ */
public function prepare() public function prepare(): void
{ {
array_map([$this, '_mkdir'], $this->taskDirs); array_map([$this, '_mkdir'], $this->taskDirs);
} }
@ -223,7 +220,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Lint php files and run unit tests * Lint php files and run unit tests
*/ */
public function test() public function test(): void
{ {
$this->lint(); $this->lint();
$this->taskPHPUnit() $this->taskPHPUnit()
@ -235,7 +232,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Watches for file updates, and automatically runs appropriate actions * Watches for file updates, and automatically runs appropriate actions
*/ */
public function watch() public function watch(): void
{ {
$this->taskWatch() $this->taskWatch()
->monitor('composer.json', function() { ->monitor('composer.json', function() {
@ -253,7 +250,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Create pdepend reports * Create pdepend reports
*/ */
protected function dependencyReport() protected function dependencyReport(): void
{ {
$cmd_parts = [ $cmd_parts = [
'vendor/bin/pdepend', 'vendor/bin/pdepend',
@ -270,14 +267,14 @@ class RoboFile extends \Robo\Tasks {
* *
* @return array * @return array
*/ */
protected function getAllSourceFiles() protected function getAllSourceFiles(): array
{ {
$files = array_merge( $files = array_unique(array_merge(
glob_recursive('build/*.php'), glob_recursive('build/*.php'),
glob_recursive('src/*.php'), glob_recursive('src/*.php'),
glob_recursive('tests/*.php'), glob_recursive('tests/*.php'),
glob('*.php') glob('*.php')
); ));
sort($files); sort($files);
@ -289,7 +286,7 @@ class RoboFile extends \Robo\Tasks {
* *
* @param array $chunk * @param array $chunk
*/ */
protected function parallelLint(array $chunk) protected function parallelLint(array $chunk): void
{ {
$task = $this->taskParallelExec() $task = $this->taskParallelExec()
->timeout(5) ->timeout(5)
@ -306,7 +303,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Generate copy paste detector report * Generate copy paste detector report
*/ */
protected function phpcpdReport() protected function phpcpdReport(): void
{ {
$cmd_parts = [ $cmd_parts = [
'vendor/bin/phpcpd', 'vendor/bin/phpcpd',
@ -323,7 +320,7 @@ class RoboFile extends \Robo\Tasks {
* @param array $cmd_parts - command arguments * @param array $cmd_parts - command arguments
* @param string $join_on - what to join the command arguments with * @param string $join_on - what to join the command arguments with
*/ */
protected function _run(array $cmd_parts, $join_on = ' ') protected function _run(array $cmd_parts, $join_on = ' '): void
{ {
$this->taskExec(implode($join_on, $cmd_parts))->run(); $this->taskExec(implode($join_on, $cmd_parts))->run();
} }

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -30,7 +30,7 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
* *
* @var array * @var array
*/ */
protected $deferred = []; protected array $deferred = [];
/** /**
* Common constructor interface for driver classes * Common constructor interface for driver classes
@ -40,11 +40,6 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
*/ */
abstract public function __construct(array $config = [], array $options = []); abstract public function __construct(array $config = [], array $options = []);
/**
* Common destructor
*/
abstract public function __destruct();
/** /**
* Retrieve a set of values by their cache key * Retrieve a set of values by their cache key
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -17,6 +17,11 @@ namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException; use Aviat\Banker\Exception\CacheException;
use function apcu_clear_cache;
use function apcu_delete;
use function apcu_exists;
use function apcu_fetch;
use function apcu_store;
/** /**
* Memcached cache backend * Memcached cache backend
@ -29,6 +34,7 @@ class ApcuDriver extends AbstractDriver {
* @param array $config - Not used by this driver * @param array $config - Not used by this driver
* @param array $options - Not used by this driver * @param array $options - Not used by this driver
* @throws CacheException * @throws CacheException
* @codeCoverageIgnore
*/ */
public function __construct(array $config = [], array $options = []) public function __construct(array $config = [], array $options = [])
{ {
@ -38,14 +44,6 @@ class ApcuDriver extends AbstractDriver {
} }
} }
/**
* Destructor
*/
public function __destruct()
{
// noop
}
/** /**
* See if a key currently exists in the cache * See if a key currently exists in the cache
* *
@ -54,7 +52,7 @@ class ApcuDriver extends AbstractDriver {
*/ */
public function exists(string $key): bool public function exists(string $key): bool
{ {
return \apcu_exists($key) !== FALSE; return apcu_exists($key) !== FALSE;
} }
/** /**
@ -65,7 +63,7 @@ class ApcuDriver extends AbstractDriver {
*/ */
public function get(string $key) public function get(string $key)
{ {
return \apcu_fetch($key); return apcu_fetch($key);
} }
/** /**
@ -77,7 +75,7 @@ class ApcuDriver extends AbstractDriver {
public function getMultiple(array $keys = []): array public function getMultiple(array $keys = []): array
{ {
$status = FALSE; $status = FALSE;
return \apcu_fetch($keys, $status); return apcu_fetch($keys, $status);
} }
/** /**
@ -86,20 +84,13 @@ class ApcuDriver extends AbstractDriver {
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int $expires
* @return DriverInterface * @return bool
*/ */
public function set(string $key, $value, int $expires = 0): DriverInterface public function set(string $key, $value, int $expires = 0): bool
{ {
if ( ! \apcu_exists($key)) $ttl = $this->getTTLFromExpiration($expires);
{
\apcu_add($key, $value, $expires);
}
else
{
\apcu_store($key, $value, $expires);
}
return $this; return apcu_store($key, $value, $ttl);
} }
/** /**
@ -110,7 +101,7 @@ class ApcuDriver extends AbstractDriver {
*/ */
public function delete(string $key): bool public function delete(string $key): bool
{ {
return (bool) \apcu_delete($key); return apcu_delete($key);
} }
/** /**
@ -121,7 +112,8 @@ class ApcuDriver extends AbstractDriver {
*/ */
public function deleteMultiple(array $keys = []): bool public function deleteMultiple(array $keys = []): bool
{ {
return (bool) \apcu_delete($keys); $deleted = apcu_delete($keys);
return ($keys <=> $deleted) === 0;
} }
/** /**
@ -131,7 +123,7 @@ class ApcuDriver extends AbstractDriver {
*/ */
public function flush(): bool public function flush(): bool
{ {
return \apcu_clear_cache(); return apcu_clear_cache();
} }
/** /**
@ -146,11 +138,25 @@ class ApcuDriver extends AbstractDriver {
if ($this->exists($key)) if ($this->exists($key))
{ {
$value = $this->get($key); $value = $this->get($key);
return \apcu_store($key, $value, $expires); $ttl = $this->getTTLFromExpiration($expires);
return apcu_store($key, $value, $ttl);
} }
$this->getLogger()->log('warning', 'Tried to set expiration on a key that does not exist'); $this->getLogger()->log('warning', 'Tried to set expiration on a key that does not exist');
return FALSE; return FALSE;
} }
/**
* Convert expiration date argument into TTL argument
*
* @param int $expires
* @return int
*/
protected function getTTLFromExpiration(int $expires): int
{
$ttl = $expires - time();
return ($ttl < 0) ? 0 : $ttl;
}
} }

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -34,9 +34,9 @@ interface DriverInterface {
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int $expires
* @return DriverInterface * @return bool
*/ */
public function set(string $key, $value, int $expires = 0): DriverInterface; public function set(string $key, $value, int $expires = 0): bool;
/** /**
* Get the value for the selected cache key * Get the value for the selected cache key

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -17,15 +17,18 @@ namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException; use Aviat\Banker\Exception\CacheException;
use Memcached;
use MemcachedException;
/** /**
* Memcached cache backend * Memcached cache backend
*/ */
class MemcachedDriver extends AbstractDriver { class MemcachedDriver extends AbstractDriver {
/** /**
* @var \Memcached * @var Memcached
*/ */
private $conn; private ?Memcached $conn;
/** /**
* Driver for PHP Memcache extension * Driver for PHP Memcache extension
@ -47,8 +50,8 @@ class MemcachedDriver extends AbstractDriver {
try try
{ {
$this->conn = new \Memcached(); $this->conn = new Memcached();
$this->conn->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); $this->conn->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$this->conn->addServer($config['host'], (int) $config['port']); $this->conn->addServer($config['host'], (int) $config['port']);
if ( ! empty($options)) if ( ! empty($options))
@ -56,7 +59,7 @@ class MemcachedDriver extends AbstractDriver {
$this->conn->setOptions($options); $this->conn->setOptions($options);
} }
} }
catch (\MemcachedException $e) catch (MemcachedException $e)
{ {
// Rewrite MemcachedException as a CacheException to // Rewrite MemcachedException as a CacheException to
// match the requirements of the interface // match the requirements of the interface
@ -66,6 +69,7 @@ class MemcachedDriver extends AbstractDriver {
/** /**
* Disconnect from memcached server * Disconnect from memcached server
* @codeCoverageIgnore
*/ */
public function __destruct() public function __destruct()
{ {
@ -80,7 +84,10 @@ class MemcachedDriver extends AbstractDriver {
*/ */
public function exists(string $key): bool public function exists(string $key): bool
{ {
return $this->conn->get($key) !== FALSE; $this->conn->get($key);
$resultFlag = $this->conn->getResultCode();
return ($resultFlag !== Memcached::RES_NOTFOUND);
} }
/** /**
@ -102,8 +109,8 @@ class MemcachedDriver extends AbstractDriver {
*/ */
public function getMultiple(array $keys = []): array public function getMultiple(array $keys = []): array
{ {
$return = $this->conn->getMulti($keys); $response = $this->conn->getMulti($keys);
return ($return === FALSE) ? [] : $return; return (is_array($response)) ? $response : [];
} }
/** /**
@ -112,20 +119,11 @@ class MemcachedDriver extends AbstractDriver {
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int $expires
* @return DriverInterface * @return bool
*/ */
public function set(string $key, $value, int $expires = 0): DriverInterface public function set(string $key, $value, int $expires = 0): bool
{ {
if ( ! $this->exists($key)) return $this->conn->set($key, $value, $expires);
{
$this->conn->add($key, $value, $expires);
}
else
{
$this->conn->replace($key, $value, $expires);
}
return $this;
} }
/** /**
@ -136,7 +134,7 @@ class MemcachedDriver extends AbstractDriver {
*/ */
public function delete(string $key): bool public function delete(string $key): bool
{ {
return (bool) $this->conn->delete($key); return $this->conn->delete($key);
} }
/** /**

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -27,7 +27,7 @@ class NullDriver extends AbstractDriver {
* *
* @var array * @var array
*/ */
protected $store = []; protected array $store = [];
/** /**
* NullDriver constructor. * NullDriver constructor.
@ -40,14 +40,6 @@ class NullDriver extends AbstractDriver {
$this->store = []; $this->store = [];
} }
/**
* Clean up nothing
*/
public function __destruct()
{
//noop
}
/** /**
* See if a key currently exists in the cache * See if a key currently exists in the cache
* *
@ -78,12 +70,12 @@ class NullDriver extends AbstractDriver {
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int $expires
* @return DriverInterface * @return bool
*/ */
public function set(string $key, $value, int $expires = 0): DriverInterface public function set(string $key, $value, int $expires = 0): bool
{ {
$this->store[$key] = $value; $this->store[$key] = $value;
return $this; return $this->store[$key] === $value;
} }
/** /**

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -28,7 +28,7 @@ class RedisDriver extends AbstractDriver {
* *
* @var Client * @var Client
*/ */
protected $conn; protected ?Client $conn;
/** /**
* RedisDriver constructor. * RedisDriver constructor.
@ -49,7 +49,8 @@ class RedisDriver extends AbstractDriver {
} }
/** /**
* Disconnect from memcached server * Disconnect from redis server
* @codeCoverageIgnore
*/ */
public function __destruct() public function __destruct()
{ {
@ -85,22 +86,18 @@ class RedisDriver extends AbstractDriver {
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param int $expires * @param int $expires
* @return DriverInterface * @return bool
*/ */
public function set(string $key, $value, int $expires = 0): DriverInterface public function set(string $key, $value, int $expires = 0): bool
{ {
$value = serialize($value); $value = serialize($value);
if ($expires !== 0) if ($expires !== 0)
{ {
$this->conn->set($key, $value, 'EX', $expires); return (bool) $this->conn->set($key, $value, 'EX', $expires);
}
else
{
$this->conn->set($key, $value);
} }
return $this; return (bool)$this->conn->set($key, $value);
} }
/** /**
@ -123,7 +120,7 @@ class RedisDriver extends AbstractDriver {
public function deleteMultiple(array $keys = []): bool public function deleteMultiple(array $keys = []): bool
{ {
$res = $this->conn->del(...$keys); $res = $this->conn->del(...$keys);
return $res === \count($keys); return $res === count($keys);
} }
/** /**

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -16,10 +16,11 @@
namespace Aviat\Banker\Exception; namespace Aviat\Banker\Exception;
use Psr\Cache\CacheException as CacheExceptionInterface; use Psr\Cache\CacheException as CacheExceptionInterface;
use Psr\SimpleCache\CacheException as SimpleCacheExceptionInterface;
/** /**
* Exception interface for all exceptions thrown by an Implementing Library. * Exception interface for all exceptions thrown by an Implementing Library.
*/ */
class CacheException extends \Exception implements CacheExceptionInterface { class CacheException extends \Exception implements CacheExceptionInterface, SimpleCacheExceptionInterface {
} }

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -15,7 +15,8 @@
*/ */
namespace Aviat\Banker\Exception; namespace Aviat\Banker\Exception;
use Psr\Cache\InvalidArgumentException as InvalidArgumentExceptionInterface; use Psr\Cache\InvalidArgumentException as IAEInterface;
use Psr\SimpleCache\InvalidArgumentException as SimpleIAEInterface;
/** /**
* Exception interface for invalid cache arguments. * Exception interface for invalid cache arguments.
@ -23,7 +24,7 @@ use Psr\Cache\InvalidArgumentException as InvalidArgumentExceptionInterface;
* Any time an invalid argument is passed into a method it must throw an * Any time an invalid argument is passed into a method it must throw an
* exception class which implements Psr\Cache\InvalidArgumentException. * exception class which implements Psr\Cache\InvalidArgumentException.
*/ */
class InvalidArgumentException extends CacheException implements InvalidArgumentExceptionInterface { class InvalidArgumentException extends CacheException implements IAEInterface, SimpleIAEInterface {
/** /**
* Constructor * Constructor
@ -32,7 +33,7 @@ class InvalidArgumentException extends CacheException implements InvalidArgument
* @param int $code * @param int $code
* @param \Exception $previous * @param \Exception $previous
*/ */
public function __construct(string $message = "Cache key must be a string.", int $code = 0, \Exception $previous = NULL) public function __construct(string $message = 'Cache key must be a string.', int $code = 0, \Exception $previous = NULL)
{ {
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);
} }

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -15,6 +15,8 @@
*/ */
namespace Aviat\Banker; namespace Aviat\Banker;
use DateInterval;
use DateTimeInterface;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
use Aviat\Banker\Driver\DriverInterface; use Aviat\Banker\Driver\DriverInterface;
@ -29,28 +31,28 @@ class Item implements CacheItemInterface {
* *
* @var DriverInterface * @var DriverInterface
*/ */
protected $driver; protected DriverInterface $driver;
/** /**
* The key of the cache item * The key of the cache item
* *
* @var string * @var string
*/ */
protected $key; protected string $key;
/** /**
* The expiration time * The expiration time
* *
* @var int | null * @var int | null
*/ */
protected $expiresAt; protected ?int $expiresAt;
/** /**
* The time to live * The time to live
* *
* @var int | null * @var int | null
*/ */
protected $ttl; protected ?int $ttl;
/** /**
* The value to save in the cache * The value to save in the cache
@ -65,10 +67,13 @@ class Item implements CacheItemInterface {
* @param DriverInterface $driver * @param DriverInterface $driver
* @param string $key * @param string $key
*/ */
public function __construct(DriverInterface $driver, $key) public function __construct(DriverInterface $driver, string $key)
{ {
$this->driver = $driver; $this->driver = $driver;
$this->key = $key; $this->key = $key;
$this->expiresAt = NULL;
$this->ttl = NULL;
} }
/** /**
@ -143,7 +148,7 @@ class Item implements CacheItemInterface {
/** /**
* Sets the expiration time for this cache item. * Sets the expiration time for this cache item.
* *
* @param \DateTimeInterface|null $expiration * @param DateTimeInterface|null $expiration
* The point in time after which the item MUST be considered expired. * The point in time after which the item MUST be considered expired.
* If null is passed explicitly, a default value MAY be used. If none is set, * If null is passed explicitly, a default value MAY be used. If none is set,
* the value should be stored permanently or for as long as the * the value should be stored permanently or for as long as the
@ -154,7 +159,7 @@ class Item implements CacheItemInterface {
*/ */
public function expiresAt($expiration = NULL): Item public function expiresAt($expiration = NULL): Item
{ {
if ($expiration instanceof \DateTimeInterface) if ($expiration instanceof DateTimeInterface)
{ {
$expiration = $expiration->getTimestamp(); $expiration = $expiration->getTimestamp();
} }
@ -167,7 +172,7 @@ class Item implements CacheItemInterface {
/** /**
* Sets the expiration time for this cache item. * Sets the expiration time for this cache item.
* *
* @param int|\DateInterval|null $time * @param int|DateInterval|null $time
* The period of time from the present after which the item MUST be considered * The period of time from the present after which the item MUST be considered
* expired. An integer parameter is understood to be the time in seconds until * expired. An integer parameter is understood to be the time in seconds until
* expiration. If null is passed explicitly, a default value MAY be used. * expiration. If null is passed explicitly, a default value MAY be used.
@ -179,7 +184,7 @@ class Item implements CacheItemInterface {
*/ */
public function expiresAfter($time = NULL): Item public function expiresAfter($time = NULL): Item
{ {
if ($time instanceof \DateInterval) if ($time instanceof DateInterval)
{ {
$time = $time->format("%s"); $time = $time->format("%s");
} }

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -17,10 +17,11 @@ namespace Aviat\Banker;
use Aviat\Banker\Driver\DriverInterface; use Aviat\Banker\Driver\DriverInterface;
use Aviat\Banker\Exception\InvalidArgumentException; use Aviat\Banker\Exception\InvalidArgumentException;
use Aviat\Banker\{Item, ItemCollection};
use Psr\Cache\{CacheItemInterface, CacheItemPoolInterface}; use Psr\Cache\{CacheItemInterface, CacheItemPoolInterface};
use Psr\Log\{LoggerAwareInterface, LoggerInterface}; use Psr\Log\{LoggerAwareInterface, LoggerInterface};
use function is_string;
/** /**
* The main cache manager * The main cache manager
*/ */
@ -33,14 +34,14 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* *
* @var DriverInterface * @var DriverInterface
*/ */
protected $driver; protected DriverInterface $driver;
/** /**
* Cache Items to be saved * Cache Items to be saved
* *
* @var array * @var array
*/ */
protected $deferred = []; protected array $deferred = [];
/** /**
* Set up the cache backend * Set up the cache backend
@ -76,7 +77,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/ */
public function getItem($key): CacheItemInterface public function getItem($key): CacheItemInterface
{ {
if ( ! \is_string($key)) if ( ! is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
@ -117,7 +118,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
$items = []; $items = [];
foreach($keys as $key) foreach($keys as $key)
{ {
if ( ! \is_string($key)) if ( ! is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
@ -149,7 +150,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/ */
public function hasItem($key): bool public function hasItem($key): bool
{ {
if ( ! \is_string($key)) if ( ! is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
@ -189,7 +190,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/ */
public function deleteItem($key): bool public function deleteItem($key): bool
{ {
if ( ! \is_string($key)) if ( ! is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
@ -219,7 +220,7 @@ final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
{ {
foreach ($keys as $key) foreach ($keys as $key)
{ {
if ( ! \is_string($key)) if ( ! is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }

240
src/Teller.php Normal file
View File

@ -0,0 +1,240 @@
<?php declare(strict_types=1);
/**
* Banker
*
* A Caching library implementing psr/cache (PSR 6)
*
* PHP version 7.2
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2019 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.0.0
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker;
use Aviat\Banker\Exception\InvalidArgumentException;
use Psr\SimpleCache;
use Psr\Log\LoggerInterface;
class Teller implements SimpleCache\CacheInterface {
private Pool $pool;
/**
* Set up the cache backend
*
* @param array $config
* @param LoggerInterface $logger
*/
public function __construct(array $config, ?LoggerInterface $logger = NULL)
{
$this->pool = new Pool($config, $logger);
}
/**
* Fetches a value from the cache.
*
* @param string $key The unique key of this item in the cache.
* @param mixed $default Default value to return if the key does not exist.
*
* @return mixed The value of the item from the cache, or $default in case of cache miss.
*
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function get($key, $default = null)
{
$this->validateKey($key);
$item = $this->pool->getItem($key);
return ($item->isHit()) ? $item->get() : $default;
}
/**
* Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.
*
* @param string $key The key of the item to store.
* @param mixed $value The value of the item to store, must be serializable.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function set($key, $value, $ttl = null): bool
{
$this->validateKey($key);
$item = $this->pool->getItem($key);
$item->set($value);
if ($ttl !== NULL)
{
$item->expiresAfter($ttl);
}
return $this->pool->save($item);
}
/**
* Delete an item from the cache by its unique key.
*
* @param string $key The unique cache key of the item to delete.
*
* @return bool True if the item was successfully removed. False if there was an error.
*
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function delete($key): bool
{
$this->validateKey($key);
return $this->pool->deleteItem($key);
}
/**
* Wipes clean the entire cache's keys.
*
* @return bool True on success and false on failure.
*/
public function clear(): bool
{
return $this->pool->clear();
}
/**
* Obtains multiple cache items by their unique keys.
*
* @param iterable $keys A list of keys that can obtained in a single operation.
* @param mixed $default Default value to return for keys that do not exist.
*
* @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.
*
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function getMultiple($keys, $default = null)
{
$this->validateKeys($keys);
$output = [];
foreach ($keys as $k)
{
$output[$k] = $this->get($k, $default);
}
return $output;
}
/**
* Persists a set of key => value pairs in the cache, with an optional TTL.
*
* @param iterable $values A list of key => value pairs for a multiple-set operation.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if $values is neither an array nor a Traversable,
* or if any of the $values are not a legal value.
*/
public function setMultiple($values, $ttl = null): bool
{
$this->validateKeys($values, TRUE);
$setResults = [];
foreach ($values as $k => $v)
{
$setResults[] = $this->set($k, $v, $ttl);
}
// Only return true if all the results are true
return array_reduce($setResults, fn ($carry, $item) => $item && $carry, TRUE);
}
/**
* Deletes multiple cache items in a single operation.
*
* @param iterable $keys A list of string-based keys to be deleted.
*
* @return bool True if the items were successfully removed. False if there was an error.
*
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function deleteMultiple($keys): bool
{
$this->validateKeys($keys);
return $this->pool->deleteItems((array)$keys);
}
/**
* Determines whether an item is present in the cache.
*
* NOTE: It is recommended that has() is only to be used for cache warming type purposes
* and not to be used within your live applications operations for get/set, as this method
* is subject to a race condition where your has() will return true and immediately after,
* another script can remove it making the state of your app out of date.
*
* @param string $key The cache item key.
*
* @return bool
*
* @throws SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function has($key): bool
{
$this->validateKey($key);
return $this->pool->hasItem($key);
}
/**
* @param $keys
* @param bool $hash
* @throws InvalidArgumentException
*/
private function validateKeys($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));
}
/**
* @param string $key
* @throws InvalidArgumentException
*/
private function validateKey($key): void
{
if ( ! is_string($key))
{
throw new InvalidArgumentException('Cache key must be a string.');
}
if (is_string($key) && preg_match("`[{}()/@:\\\]`", $key) === 1)
{
throw new InvalidArgumentException('Invalid characters in cache key');
}
}
}

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -15,16 +15,14 @@
*/ */
namespace Aviat\Banker\Tests\Driver; namespace Aviat\Banker\Tests\Driver;
use Aviat\Banker\Driver\DriverInterface;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class DriverTestBase extends TestCase { class DriverTestBase extends TestCase {
protected $driver; protected DriverInterface $driver;
public function tearDown(): void
{
$this->driver->__destruct();
}
public function testGetSet(): void public function testGetSet(): void
{ {

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *
@ -214,11 +214,19 @@ class PoolTest extends TestCase {
public function testDeleteItemBadKey(): void public function testDeleteItemBadKey(): void
{ {
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::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);
} }
public function testDeleteItemsBadKey(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->pool->deleteItems([34]);
}
public function testDeleteItemThatDoesNotExist(): void public function testDeleteItemThatDoesNotExist(): void
{ {
$this->pool->clear(); $this->pool->clear();

164
tests/TellerTest.php Normal file
View File

@ -0,0 +1,164 @@
<?php declare(strict_types=1);
/**
* Banker
*
* A Caching library implementing psr/cache
*
* PHP version 7.1
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2018 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 2.0.0
* @link https://git.timshomepage.net/timw4mail/banker
*/
namespace Aviat\Banker\Tests;
use Aviat\Banker\Teller;
use Aviat\Banker\Exception\InvalidArgumentException;
use PHPUnit\Framework\TestCase;
class TellerTest extends TestCase {
protected Teller $teller;
private array $testValues = [
'foo' => 24,
'bar' => '87',
'baz' => [1, 2, 3],
'a' => TRUE,
'b' => 1,
'c' => FALSE,
'd' => 0,
'e' => NULL,
'f' => [
'a' => [
'b' => 'c',
'd' => [1, 2, 3]
]
]
];
public function setUp(): void
{
$this->teller = new Teller([
'driver' => 'null',
'connection' => []
]);
// Call clear to make sure we are working from a clean slate to start
$this->teller->clear();
}
public function testGetSet(): void
{
foreach ($this->testValues as $key => $value)
{
$this->assertTrue($this->teller->set($key, $value, 0), "Failed to set value for key: {$key}");
$received = $this->teller->get($key);
$this->assertEquals($value, $received, "Invalid value returned for key: {$key}");
}
}
public function testGetSetMultiple(): void
{
$this->assertTrue($this->teller->setMultiple($this->testValues));
$received = $this->teller->getMultiple(array_keys($this->testValues));
$this->assertEquals($this->testValues, $received);
}
public function testClear(): void
{
$data = [
'foo' => 'bar',
'bar' => 'baz',
'foobar' => 'foobarbaz'
];
// Set up some data
$this->teller->setMultiple($data);
foreach($data as $key => $val)
{
$this->assertTrue($this->teller->has($key));
$this->assertEquals($val, $this->teller->get($key));
}
// Now we clear it all!
$this->teller->clear();
foreach($data as $key => $val)
{
$this->assertFalse($this->teller->has($key));
$this->assertNull($this->teller->get($key));
}
}
public function testDelete(): void
{
$this->teller->setMultiple($this->testValues);
$this->assertTrue($this->teller->delete('foo'));
$this->assertFalse($this->teller->has('foo'));
// Make sure we get the default value for the key
$this->assertEquals('Q', $this->teller->get('foo', 'Q'));
}
public function testDeleteMultiple(): void
{
$this->teller->setMultiple($this->testValues);
$deleteKeys = ['foo', 'bar', 'baz'];
$hasKeys = ['a', 'b', 'c', 'd', 'e', 'f'];
$this->assertTrue($this->teller->deleteMultiple($deleteKeys));
array_walk($deleteKeys, fn ($key) => $this->assertFalse($this->teller->has($key)));
array_walk($hasKeys, fn ($key) => $this->assertTrue($this->teller->has($key)));
}
public function testBadKeyType(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cache key must be a string.');
$this->teller->get(546567);
}
public function testBadKeysType (): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Keys must be an array or a traversable object');
$keys = (object)[];
$this->teller->getMultiple($keys);
}
/**
* @dataProvider keyValidationTests
*/
public function testKeyValidation($key): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid characters in cache key');
$this->teller->get($key);
}
public function keyValidationTests(): array
{
// {}()/@:\\\
return [
['key' => '{}()/@:\\'],
['key' => 'a: b'],
['key' => 'a/b'],
['key' => '{'],
['key' => 'a@b'],
];
}
}

View File

@ -2,7 +2,7 @@
/** /**
* Banker * Banker
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache (PSR 6)
* *
* PHP version 7.2 * PHP version 7.2
* *