Lots of fixes and tests
This commit is contained in:
parent
b1fb6dccaa
commit
03bf558d62
@ -24,8 +24,9 @@
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"predis/predis": "^1.1",
|
||||
"psr/log": "^1.0",
|
||||
"psr/cache": "^1.0"
|
||||
"psr/cache": "^1.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"consolidation/robo": "1.0.0-RC2",
|
||||
@ -36,7 +37,6 @@
|
||||
"phploc/phploc": "^3.0",
|
||||
"phpmd/phpmd": "^2.4",
|
||||
"phpunit/phpunit": "^5.5",
|
||||
"predis/predis": "^1.1",
|
||||
"sebastian/phpcpd": "^2.0",
|
||||
"squizlabs/php_codesniffer": "^3.0.0@alpha",
|
||||
"theseer/phpdox": "^0.9.0"
|
||||
|
@ -16,10 +16,14 @@
|
||||
|
||||
namespace Aviat\Banker\Driver;
|
||||
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
|
||||
/**
|
||||
* Base class for cache backends
|
||||
*/
|
||||
abstract class Driver implements DriverInterface {
|
||||
abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
|
||||
|
||||
use \Aviat\Banker\LoggerTrait;
|
||||
|
||||
/**
|
||||
* The object encapsulating the connection to the cache backend
|
||||
@ -41,4 +45,9 @@ abstract class Driver implements DriverInterface {
|
||||
* @param array $config - Connection parameters for the specified backend
|
||||
*/
|
||||
abstract public function __construct(array $config = []);
|
||||
|
||||
/**
|
||||
* Common destructor
|
||||
*/
|
||||
abstract public function __destruct();
|
||||
}
|
@ -77,4 +77,13 @@ interface DriverInterface {
|
||||
* @return boolean
|
||||
*/
|
||||
public function flush();
|
||||
|
||||
/**
|
||||
* Set the specified key to expire at the given time
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $expires
|
||||
* @return boolean
|
||||
*/
|
||||
public function expiresAt($key, $expires);
|
||||
}
|
@ -21,7 +21,7 @@ use Aviat\Banker\Exception\CacheException;
|
||||
/**
|
||||
* Redis cache backend
|
||||
*/
|
||||
class MemcacheDriver extends Driver {
|
||||
class MemcacheDriver extends AbstractDriver {
|
||||
|
||||
/**
|
||||
* Driver for PHP Memcache extension
|
||||
@ -94,7 +94,15 @@ class MemcacheDriver extends Driver {
|
||||
*/
|
||||
public function set($key, $value, $expires = 0)
|
||||
{
|
||||
$this->conn->set($key, $value, 0, $expires);
|
||||
if ($this->exists($key))
|
||||
{
|
||||
$this->conn->replace($key, $value, 0, $expires);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->conn->set($key, $value, 0, $expires);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -133,4 +141,19 @@ class MemcacheDriver extends Driver {
|
||||
{
|
||||
return $this->conn->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified key to expire at the given time
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $expires
|
||||
* @return DriverInterface
|
||||
*/
|
||||
public function expiresAt($key, $expires)
|
||||
{
|
||||
$value = $this->get($key);
|
||||
$timediff = $expires - time();
|
||||
|
||||
return $this->set($key, $value, $timediff);
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ use MemcachedException;
|
||||
/**
|
||||
* Memcached cache backend
|
||||
*/
|
||||
class MemcachedDriver extends Driver {
|
||||
class MemcachedDriver extends AbstractDriver {
|
||||
|
||||
/**
|
||||
* Driver for PHP Memcache extension
|
||||
@ -39,9 +39,18 @@ class MemcachedDriver extends Driver {
|
||||
throw new CacheException("Memcached driver requires memcached extensions");
|
||||
}
|
||||
|
||||
$this->conn = new Memcached();
|
||||
|
||||
$this->conn->addServer($config['host'], $config['port']);
|
||||
try
|
||||
{
|
||||
$this->conn = new Memcached();
|
||||
$this->conn->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
|
||||
$this->conn->addServer($config['host'], $config['port']);
|
||||
}
|
||||
catch (MemcachedException $e)
|
||||
{
|
||||
// Rewrite MemcachedException as a CacheException to
|
||||
// match the requirements of the interface
|
||||
throw new CacheException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,7 +104,15 @@ class MemcachedDriver extends Driver {
|
||||
*/
|
||||
public function set($key, $value, $expires = 0)
|
||||
{
|
||||
$this->conn->set($key, $value, $expires);
|
||||
if ( ! $this->exists($key))
|
||||
{
|
||||
$this->conn->add($key, $value, $expires);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->conn->replace($key, $value, $expires);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -130,4 +147,23 @@ class MemcachedDriver extends Driver {
|
||||
{
|
||||
return $this->conn->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified key to expire at the given time
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $expires
|
||||
* @return boolean
|
||||
*/
|
||||
public function expiresAt($key, $expires)
|
||||
{
|
||||
if ($this->exists($key))
|
||||
{
|
||||
return $this->conn->touch($key, $expires);
|
||||
}
|
||||
|
||||
$this->getLogger()->warn("Tried to set expiration on a key that does not exist");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace Aviat\Banker\Driver;
|
||||
* Cache backend for use without a cache server. Only does transient
|
||||
* in-memory caching
|
||||
*/
|
||||
class NullDriver extends Driver {
|
||||
class NullDriver extends AbstractDriver {
|
||||
|
||||
/**
|
||||
* In memory store
|
||||
@ -39,6 +39,14 @@ class NullDriver extends Driver {
|
||||
{
|
||||
$this->store = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up nothing
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
//noop
|
||||
}
|
||||
|
||||
/**
|
||||
* See if a key currently exists in the cache
|
||||
@ -59,7 +67,9 @@ class NullDriver extends Driver {
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
return $this->store[$key];
|
||||
return ($this->exists($key))
|
||||
? $this->store[$key]
|
||||
: NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,4 +144,17 @@ class NullDriver extends Driver {
|
||||
$this->store = [];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified key to expire at the given time
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $expires
|
||||
* @return boolean
|
||||
*/
|
||||
public function expiresAt($key, $expires)
|
||||
{
|
||||
//noop
|
||||
return TRUE;
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ use Predis\Client;
|
||||
/**
|
||||
* Redis cache backend
|
||||
*/
|
||||
class RedisDriver extends Driver {
|
||||
class RedisDriver extends AbstractDriver {
|
||||
|
||||
/**
|
||||
* The object encapsulating the connection to the Redis server
|
||||
@ -107,8 +107,16 @@ class RedisDriver extends Driver {
|
||||
public function set($key, $value, $expires = 0)
|
||||
{
|
||||
$value = \serialize($value);
|
||||
|
||||
$this->conn->set($key, $value, "EX {$expires}");
|
||||
|
||||
if ($expires !== 0)
|
||||
{
|
||||
$this->conn->set($key, $value, "EX {$expires}");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->conn->set($key, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Banker
|
||||
*
|
||||
* A Caching library implementing psr/cache
|
||||
*
|
||||
* PHP version 5.6
|
||||
*
|
||||
* @package Banker
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2016 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 1.0.0
|
||||
* @link https://git.timshomepage.net/timw4mail/banker
|
||||
*/
|
||||
|
||||
namespace Aviat\Banker\Driver;
|
||||
|
||||
/**
|
||||
* SQL cache backend
|
||||
*/
|
||||
class SQLDriver extends Driver {
|
||||
|
||||
}
|
@ -26,4 +26,15 @@ use Psr\Cache\InvalidArgumentException as InvalidArgumentExceptionInterface;
|
||||
*/
|
||||
class InvalidArgumentException extends CacheException implements InvalidArgumentExceptionInterface {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param \Exception $previous
|
||||
*/
|
||||
public function __construct($message = "Cache key must be a string.", $code = 0, \Exception $previous = NULL)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
43
src/Item.php
43
src/Item.php
@ -100,7 +100,12 @@ class Item implements CacheItemInterface {
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->driver->get($this->key);
|
||||
if ($this->isHit())
|
||||
{
|
||||
return $this->driver->get($this->key);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,6 +155,13 @@ class Item implements CacheItemInterface {
|
||||
*/
|
||||
public function expiresAt($expiration = NULL)
|
||||
{
|
||||
if ($time instanceof \DateTimeInterface)
|
||||
{
|
||||
$time = $time->getTimestamp();
|
||||
}
|
||||
|
||||
$this->expiresAt = (int) $time;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -168,7 +180,34 @@ class Item implements CacheItemInterface {
|
||||
*/
|
||||
public function expiresAfter($time = 0)
|
||||
{
|
||||
$this->ttl = $time;
|
||||
if ($time instanceof \DateInterval)
|
||||
{
|
||||
$time = $time->format("%s");
|
||||
}
|
||||
|
||||
$this->ttl = (int) $time;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current value to the cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if ($this->expiresAt !== NULL && $this->expiresAt !== 0)
|
||||
{
|
||||
$setResult = $this->driver->set($this->key, $this->value);
|
||||
$expResult = $this->driver->expiresAt($this->key, $this->expiresAt);
|
||||
|
||||
return $setResult && $expResult;
|
||||
}
|
||||
else if ($this->ttl !== NULL && $this->ttl !== 0)
|
||||
{
|
||||
return $this->driver->set($this->key, $this->value, $this->ttl);
|
||||
}
|
||||
|
||||
return $this->driver->set($this->key, $this->value);
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ use Psr\Cache\CacheItemInterface;
|
||||
* Collection of Psr\Cache\CacheItemIterface objects to be returned by getItems
|
||||
*
|
||||
* @see http://php.net/manual/en/class.arrayiterator.php
|
||||
* @see http://php.net/manual/en/class.jsonserializable.php
|
||||
*/
|
||||
class ItemCollection extends \ArrayIterator implements \JsonSerializable {
|
||||
|
||||
|
68
src/LoggerTrait.php
Normal file
68
src/LoggerTrait.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Banker
|
||||
*
|
||||
* A Caching library implementing psr/cache
|
||||
*
|
||||
* PHP version 5.6
|
||||
*
|
||||
* @package Banker
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2016 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 1.0.0
|
||||
* @link https://git.timshomepage.net/timw4mail/banker
|
||||
*/
|
||||
|
||||
namespace Aviat\Banker;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* Trait for keeping track of logger objects
|
||||
*/
|
||||
trait LoggerTrait {
|
||||
|
||||
/**
|
||||
* Logger instance to use
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger = NULL;
|
||||
|
||||
/**
|
||||
* Return the existing logger instance or
|
||||
* a NullLogger, if no instance set
|
||||
*
|
||||
* @return LoggerInterface
|
||||
*/
|
||||
protected function getLogger()
|
||||
{
|
||||
if ($this->logger === NULL)
|
||||
{
|
||||
$this->logger = new NullLogger();
|
||||
}
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a logger to keep track of errors
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
* @return self
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
|
||||
// Set the logger for the current driver too
|
||||
if (isset($this->driver))
|
||||
{
|
||||
$this->driver->setLogger($logger);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
74
src/Pool.php
74
src/Pool.php
@ -18,16 +18,20 @@ namespace Aviat\Banker;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
use Aviat\Banker\Driver;
|
||||
use Aviat\Banker\Driver\DriverInterface;
|
||||
use Aviat\Banker\Exception\InvalidArgumentException;
|
||||
use Aviat\Banker\Item;
|
||||
use Aviat\Banker\ItemCollection;
|
||||
|
||||
/**
|
||||
* The main cache manager
|
||||
*/
|
||||
class Pool implements CacheItemPoolInterface {
|
||||
class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
|
||||
|
||||
use LoggerTrait;
|
||||
|
||||
/**
|
||||
* Driver class for handling the chosen caching backend
|
||||
@ -48,9 +52,14 @@ class Pool implements CacheItemPoolInterface {
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
public function __construct(array $config, LoggerInterface $logger = NULL)
|
||||
{
|
||||
$this->driver = $this->loadDriver($config);
|
||||
|
||||
if ( ! is_null($logger))
|
||||
{
|
||||
$this->setLogger($logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +82,13 @@ class Pool implements CacheItemPoolInterface {
|
||||
{
|
||||
if ( ! is_string($key))
|
||||
{
|
||||
throw new InvalidArgumentException("Cache key must be a string.");
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
|
||||
// If a deferred item exists, return that
|
||||
if (array_key_exists($key, $this->deferred))
|
||||
{
|
||||
return $this->deferred[$key];
|
||||
}
|
||||
|
||||
$item = new Item($this->driver, $key);
|
||||
@ -98,11 +113,32 @@ class Pool implements CacheItemPoolInterface {
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
// Get the set of items selected
|
||||
$items = [];
|
||||
if (empty($keys))
|
||||
{
|
||||
return new ItemCollection([]);
|
||||
}
|
||||
|
||||
foreach($keys as $key)
|
||||
{
|
||||
$items[$key] = $this->getItem($key);
|
||||
if ( ! is_string($key))
|
||||
{
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the set of items selected
|
||||
$items = [];
|
||||
$rawItems = $this->driver->getMultiple($keys);
|
||||
foreach($rawItems as $key => $val)
|
||||
{
|
||||
if (array_key_exists($key, $this->deferred))
|
||||
{
|
||||
$items[$key] = $this->deferred[$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
$items[$key] = new Item($this->driver, $key);
|
||||
}
|
||||
}
|
||||
|
||||
return new ItemCollection($items);
|
||||
@ -129,7 +165,13 @@ class Pool implements CacheItemPoolInterface {
|
||||
{
|
||||
if ( ! is_string($key))
|
||||
{
|
||||
throw new InvalidArgumentException("Cache item must be a string");
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
|
||||
// See if there are any deferred items
|
||||
if (array_key_exists($key, $this->deferred))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return $this->driver->exists($key);
|
||||
@ -163,7 +205,7 @@ class Pool implements CacheItemPoolInterface {
|
||||
{
|
||||
if ( ! is_string($key))
|
||||
{
|
||||
throw new InvalidArgumentException("Cache item must be a string");
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
|
||||
if ( ! $this->hasItem($key))
|
||||
@ -195,7 +237,7 @@ class Pool implements CacheItemPoolInterface {
|
||||
{
|
||||
if ( ! is_string($key))
|
||||
{
|
||||
throw new InvalidArgumentException("Cache item must be a string");
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +255,7 @@ class Pool implements CacheItemPoolInterface {
|
||||
*/
|
||||
public function save(CacheItemInterface $item)
|
||||
{
|
||||
|
||||
return $item->save();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -227,7 +269,8 @@ class Pool implements CacheItemPoolInterface {
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item)
|
||||
{
|
||||
$this->deferred[] = $item;
|
||||
$this->deferred[$item->getKey()] = $item;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,6 +292,11 @@ class Pool implements CacheItemPoolInterface {
|
||||
{
|
||||
$result = $result && $this->save($item);
|
||||
}
|
||||
|
||||
if ($result === TRUE)
|
||||
{
|
||||
$this->deferred = [];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@ -262,7 +310,7 @@ class Pool implements CacheItemPoolInterface {
|
||||
protected function loadDriver(array $driverConfig)
|
||||
{
|
||||
$driver = ucfirst(strtolower($driverConfig['driver']));
|
||||
$class = "Driver\\${driver}Driver";
|
||||
$class = __NAMESPACE__ . "\\Driver\\${driver}Driver";
|
||||
|
||||
return new $class($driverConfig['connection']);
|
||||
}
|
||||
|
@ -7,6 +7,11 @@ use PHPUnit\Framework\TestCase;
|
||||
class DriverTestBase extends TestCase {
|
||||
|
||||
protected $driver;
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->driver->__destruct();
|
||||
}
|
||||
|
||||
public function testGetSet()
|
||||
{
|
||||
|
14
tests/Driver/NullDriverTest.php
Normal file
14
tests/Driver/NullDriverTest.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Aviat\Banker\Tests\Driver;
|
||||
|
||||
use Aviat\Banker\Driver\NullDriver;
|
||||
|
||||
class NullDriverTest extends DriverTestBase {
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$this->driver = new NullDriver();
|
||||
$this->driver->flush();
|
||||
}
|
||||
}
|
@ -2,6 +2,14 @@
|
||||
|
||||
namespace Aviat\Banker\Tests\Driver;
|
||||
|
||||
class RedisDriverTest extends DriverTestBase {
|
||||
use Aviat\Banker\Driver\RedisDriver;
|
||||
|
||||
class RedisDriverTest extends DriverTestBase {
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$this->driver = new RedisDriver();
|
||||
$this->driver->flush();
|
||||
}
|
||||
|
||||
}
|
120
tests/Friend.php
Normal file
120
tests/Friend.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Aviat\Banker\Tests;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
use InvalidArgumentException;
|
||||
use BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Friend class for testing
|
||||
*/
|
||||
class Friend {
|
||||
|
||||
/**
|
||||
* Object to create a friend of
|
||||
* @var object
|
||||
*/
|
||||
private $_friend_;
|
||||
|
||||
/**
|
||||
* Reflection class of the object
|
||||
* @var object
|
||||
*/
|
||||
private $_reflect_;
|
||||
|
||||
/**
|
||||
* Create a friend object
|
||||
*
|
||||
* @param object $obj
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($obj)
|
||||
{
|
||||
if ( ! is_object($obj))
|
||||
{
|
||||
throw new InvalidArgumentException("Friend must be an object");
|
||||
}
|
||||
|
||||
$this->_friend_ = $obj;
|
||||
$this->_reflect_ = new ReflectionClass($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a friend's property
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
if ($this->_reflect_->hasProperty($key))
|
||||
{
|
||||
$property = $this->_get_property($key);
|
||||
return $property->getValue($this->_friend_);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a friend's property
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
{
|
||||
if ($this->_reflect_->hasProperty($key))
|
||||
{
|
||||
$property = $this->_get_property($key);
|
||||
$property->setValue($this->_friend_, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a protected or private method on the friend
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if ( ! $this->_reflect_->hasMethod($method))
|
||||
{
|
||||
throw new BadMethodCallException("Method '{$method}' does not exist");
|
||||
}
|
||||
|
||||
$friendMethod = new ReflectionMethod($this->_friend_, $method);
|
||||
$friendMethod->setAccessible(TRUE);
|
||||
return $friendMethod->invokeArgs($this->_friend_, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over parent classes to get a ReflectionProperty
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @param string $name
|
||||
* @return ReflectionProperty|null
|
||||
*/
|
||||
private function _get_property($name)
|
||||
{
|
||||
try
|
||||
{
|
||||
$property = $this->_reflect_->getProperty($name);
|
||||
$property->setAccessible(TRUE);
|
||||
return $property;
|
||||
}
|
||||
// Return NULL on any exception, so no further logic needed
|
||||
// in the catch block
|
||||
catch (\Exception $e)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
23
tests/ItemCollectionTest.php
Normal file
23
tests/ItemCollectionTest.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Aviat\Banker\Tests;
|
||||
|
||||
use Aviat\Banker\ItemCollection;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ItemCollectionTest extends TestCase {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->collection = new ItemCollection([]);
|
||||
}
|
||||
|
||||
public function testJsonSerialize()
|
||||
{
|
||||
$this->assertEquals([], $this->collection->jsonSerialize());
|
||||
|
||||
$json = json_encode($this->collection);
|
||||
$result = json_decode($json);
|
||||
$this->assertEquals([], $result);
|
||||
}
|
||||
}
|
39
tests/ItemTest.php
Normal file
39
tests/ItemTest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Aviat\Banker\Tests;
|
||||
|
||||
use Aviat\Banker\Item;
|
||||
use Aviat\Banker\ItemCollection;
|
||||
use Aviat\Banker\Driver\NullDriver;
|
||||
use Aviat\Banker\Exception\InvalidArgumentException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ItemTest extends TestCase {
|
||||
|
||||
protected $key = 'foo';
|
||||
protected $item;
|
||||
protected $driver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->driver = new NullDriver();
|
||||
$this->item = new Item($this->driver, $this->key);
|
||||
}
|
||||
|
||||
public function testGetKey()
|
||||
{
|
||||
$this->assertEquals($this->key, $this->item->getKey());
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
// No value set yet
|
||||
$this->assertNull($this->item->get());
|
||||
|
||||
// Set a value
|
||||
$this->item->set('bar')
|
||||
->save();
|
||||
|
||||
$this->assertEquals('bar', $this->item->get());
|
||||
}
|
||||
}
|
314
tests/PoolTest.php
Normal file
314
tests/PoolTest.php
Normal file
@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
namespace Aviat\Banker\Tests;
|
||||
|
||||
use Aviat\Banker\Pool;
|
||||
use Aviat\Banker\Item;
|
||||
use Aviat\Banker\ItemCollection;
|
||||
use Aviat\Banker\Exception\InvalidArgumentException;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\SyslogHandler;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
class PoolTest extends TestCase {
|
||||
|
||||
protected $pool;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->pool = new Pool([
|
||||
'driver' => 'null',
|
||||
'connection' => []
|
||||
]);
|
||||
}
|
||||
|
||||
public function testGetDefaultLogger()
|
||||
{
|
||||
$friend = new Friend($this->pool);
|
||||
$driverFriend = new Friend($friend->driver);
|
||||
|
||||
// Check that a valid logger is set
|
||||
$this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being set");
|
||||
$this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set");
|
||||
|
||||
// Make sure we get the default Null logger
|
||||
$this->assertTrue(is_a($friend->getLogger(), NullLogger::class));
|
||||
$this->assertTrue(is_a($driverFriend->getLogger(), NullLogger::class));
|
||||
}
|
||||
|
||||
public function testSetLoggerInConstructor()
|
||||
{
|
||||
$logger = new Logger('test');
|
||||
$logger->pushHandler(new SyslogHandler(Logger::WARNING));
|
||||
|
||||
$pool = new Pool([
|
||||
'driver' => 'null',
|
||||
'connection' => [],
|
||||
], $logger);
|
||||
|
||||
$friend = new Friend($pool);
|
||||
$driverFriend = new Friend($friend->driver);
|
||||
|
||||
// Check that a valid logger is set
|
||||
$this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being set");
|
||||
$this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set");
|
||||
|
||||
// Make sure we aren't just getting the default Null logger
|
||||
$this->assertFalse(is_a($friend->getLogger(), NullLogger::class));
|
||||
$this->assertFalse(is_a($driverFriend->getLogger(), NullLogger::class));
|
||||
}
|
||||
|
||||
public function testGetSetLogger()
|
||||
{
|
||||
$logger = new Logger('test');
|
||||
$logger->pushHandler(new SyslogHandler(Logger::WARNING));
|
||||
|
||||
$this->pool->setLogger($logger);
|
||||
|
||||
$friend = new Friend($this->pool);
|
||||
$driverFriend = new Friend($friend->driver);
|
||||
|
||||
// Check that a valid logger is set
|
||||
$this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being set");
|
||||
$this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set");
|
||||
|
||||
// Make sure we aren't just getting the default Null logger
|
||||
$this->assertFalse(is_a($friend->getLogger(), NullLogger::class));
|
||||
$this->assertFalse(is_a($driverFriend->getLogger(), NullLogger::class));
|
||||
}
|
||||
|
||||
public function testGetItem()
|
||||
{
|
||||
$item = $this->pool->getItem('foo');
|
||||
$this->assertInstanceOf(Item::class, $item);
|
||||
}
|
||||
|
||||
public function testItemBadKey()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage("Cache key must be a string.");
|
||||
|
||||
$this->pool->getItem([]);
|
||||
}
|
||||
|
||||
public function testGetItems()
|
||||
{
|
||||
$collection = $this->pool->getItems(['foo', 'bar', 'baz']);
|
||||
$this->assertInstanceOf(ItemCollection::class, $collection);
|
||||
|
||||
foreach($collection as $item)
|
||||
{
|
||||
$this->assertInstanceOf(Item::class, $item);
|
||||
}
|
||||
}
|
||||
|
||||
public function testEmptyGetItems()
|
||||
{
|
||||
$collection = $this->pool->getItems();
|
||||
|
||||
$this->assertInstanceOf(ItemCollection::class, $collection);
|
||||
$this->assertEquals(0, count($collection));
|
||||
}
|
||||
|
||||
public function testHasItem()
|
||||
{
|
||||
// The key doesn't exist yet
|
||||
$this->assertFalse($this->pool->hasItem('foobar'));
|
||||
|
||||
// Create the item
|
||||
$item = $this->pool->getItem('foobar')
|
||||
->set('baz')
|
||||
->save();
|
||||
|
||||
// The item exists now
|
||||
$this->assertTrue($this->pool->hasItem('foobar'));
|
||||
}
|
||||
|
||||
public function testHasItemBadKey()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage("Cache key must be a string.");
|
||||
|
||||
$this->pool->hasItem(34);
|
||||
}
|
||||
|
||||
public function testClear()
|
||||
{
|
||||
// Call clear to make sure we are working from a clean slate to start
|
||||
$this->pool->clear();
|
||||
|
||||
$data = [
|
||||
'foo' => 'bar',
|
||||
'bar' => 'baz',
|
||||
'foobar' => 'foobarbaz'
|
||||
];
|
||||
|
||||
// Set up some data
|
||||
$this->setupDataInCache($data);
|
||||
|
||||
foreach($data as $key => $val)
|
||||
{
|
||||
$this->assertTrue($this->pool->hasItem($key));
|
||||
$item = $this->pool->getItem($key);
|
||||
$this->assertEquals($val, $item->get());
|
||||
}
|
||||
|
||||
// Now we clear it all!
|
||||
$this->pool->clear();
|
||||
|
||||
foreach($data as $key => $val)
|
||||
{
|
||||
$this->assertFalse($this->pool->hasItem($key));
|
||||
$item = $this->pool->getItem($key);
|
||||
$this->assertNull($item->get());
|
||||
}
|
||||
}
|
||||
|
||||
public function testDeleteItemBadKey()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage("Cache key must be a string.");
|
||||
|
||||
$this->pool->deleteItem(34);
|
||||
}
|
||||
|
||||
public function testDeleteItemThatDoesNotExist()
|
||||
{
|
||||
$this->pool->clear();
|
||||
$this->assertFalse($this->pool->deleteItem('foo'));
|
||||
}
|
||||
|
||||
public function testDeleteItem()
|
||||
{
|
||||
// Start with a clean slate
|
||||
$this->pool->clear();
|
||||
|
||||
$data = [
|
||||
'foo' => 'bar',
|
||||
'bar' => 'baz',
|
||||
'foobar' => 'foobarbaz'
|
||||
];
|
||||
|
||||
$this->setupDataInCache($data);
|
||||
|
||||
$this->pool->deleteItem('foo');
|
||||
|
||||
// The item no longer exists
|
||||
$this->assertFalse($this->pool->hasItem('foo'));
|
||||
$item = $this->pool->getItem('foo');
|
||||
$this->assertNull($item->get());
|
||||
|
||||
// The other items still exist
|
||||
foreach(['bar', 'foobar'] as $key)
|
||||
{
|
||||
$this->assertTrue($this->pool->hasItem($key));
|
||||
$item = $this->pool->getItem($key);
|
||||
$this->assertFalse(is_null($item->get()));
|
||||
}
|
||||
}
|
||||
|
||||
public function testDeleteItems()
|
||||
{
|
||||
$this->pool->clear();
|
||||
|
||||
$data = [
|
||||
'foo' => 'bar',
|
||||
'bar' => 'baz',
|
||||
'foobar' => 'foobarbaz'
|
||||
];
|
||||
|
||||
$this->setupDataInCache($data);
|
||||
|
||||
$this->pool->deleteItems(['foo', 'bar']);
|
||||
|
||||
foreach(['foo', 'bar'] as $key)
|
||||
{
|
||||
$this->assertFalse($this->pool->hasItem($key));
|
||||
$item = $this->pool->getItem($key);
|
||||
$this->assertNull($item->get());
|
||||
}
|
||||
}
|
||||
|
||||
public function testSaveDeferred()
|
||||
{
|
||||
$this->pool->clear();
|
||||
|
||||
$data = [
|
||||
'foo' => 'bar',
|
||||
'bar' => 'baz',
|
||||
'foobar' => 'foobarbaz'
|
||||
];
|
||||
|
||||
$this->setupDeferredData($data);
|
||||
|
||||
// See that the data is returned by the pool
|
||||
foreach($data as $key => $val)
|
||||
{
|
||||
$this->assertTrue($this->pool->hasItem($key));
|
||||
$item = $this->pool->getItem($key);
|
||||
|
||||
// The cache hasn't been updated yet, even
|
||||
// though the pool data has
|
||||
$this->assertNotEquals($data[$key], $item->get());
|
||||
}
|
||||
}
|
||||
|
||||
public function testCommit()
|
||||
{
|
||||
$this->pool->clear();
|
||||
|
||||
// If there are no deferred items, this will return true
|
||||
$this->assertTrue($this->pool->commit());
|
||||
|
||||
$data = [
|
||||
'foo' => 'bar',
|
||||
'bar' => 'baz',
|
||||
'foobar' => 'foobarbaz'
|
||||
];
|
||||
|
||||
$this->setupDeferredData($data);
|
||||
|
||||
// See that the data is returned by the pool
|
||||
foreach($this->pool->getItems(array_keys($data)) as $key => $item)
|
||||
{
|
||||
$this->assertTrue($this->pool->hasItem($key));
|
||||
|
||||
// The cache hasn't been updated yet, even
|
||||
// though the pool data has
|
||||
$this->assertNotEquals($data[$key], $item->get());
|
||||
}
|
||||
|
||||
$this->pool->commit();
|
||||
|
||||
// See that the data is saved in the cache backend
|
||||
foreach($this->pool->getItems(array_keys($data)) as $key => $item)
|
||||
{
|
||||
$this->assertTrue($this->pool->hasItem($key));
|
||||
$this->assertEquals($data[$key], $item->get());
|
||||
}
|
||||
}
|
||||
|
||||
protected function setupDeferredData($data)
|
||||
{
|
||||
foreach($data as $key => $val)
|
||||
{
|
||||
$item = $this->pool->getItem($key)
|
||||
->set($val);
|
||||
|
||||
$this->assertTrue($this->pool->saveDeferred($item));
|
||||
}
|
||||
}
|
||||
|
||||
protected function setupDataInCache($data)
|
||||
{
|
||||
foreach($data as $key => $val)
|
||||
{
|
||||
$item = $this->pool->getItem($key)
|
||||
->set($val);
|
||||
|
||||
$this->pool->save($item);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user