Refactor cache to remove dependency on container

This commit is contained in:
Timothy Warren 2016-08-01 13:02:26 -04:00
parent 893584696b
commit 6b9770698b
17 changed files with 171 additions and 60 deletions

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project default="full-build" name="animeclient" basedir=".">
<autoloader autoloaderpath="${project.basedir}/vendor/autoload.php" />
<!-- By default, we assume all tools to be on the $PATH -->
<property name="pdepend" value="pdepend" />
<property name="phpcpd" value="phpcpd" />
@ -10,7 +11,7 @@
<property name="sonar" value="sonar-runner" />
<target name="full-build"
depends="prepare,static-analysis,phpunit,phpdox,sonar"
depends="prepare,static-analysis,phpunit,phpdox"
description="Performs static analysis, runs the tests, and generates project documentation"
/>
<target name="quick-build"

View File

@ -19,6 +19,8 @@ use GuzzleHttp\Psr7\ResponseInterface;
use GuzzleHttp\Exception\ClientException;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Cache\CacheInterface;
use Aviat\Ion\Model;
use Aviat\AnimeClient\AnimeClient;

View File

@ -14,6 +14,7 @@
namespace Aviat\AnimeClient\Model;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Model\DB;
/**
* Base model for anime and manga collections
@ -36,11 +37,10 @@ class Collection extends DB {
* Create a new collection object
*
* @param ContainerInterface $container
* @return void
*/
public function __construct(ContainerInterface $container)
{
parent::__construct($container);
parent::__construct($container->get('config'));
try
{

View File

@ -162,7 +162,7 @@ class Manga extends API {
$logger->warning("Non 200 response for search api call");
$logger->warning($response->getBody());
throw new RuntimeException($response->getEffectiveUrl());
throw new \RuntimeException($response->getEffectiveUrl());
}
return Json::decode($response->getBody(), TRUE);

View File

@ -18,7 +18,7 @@ namespace Aviat\Ion\Cache;
interface CacheInterface {
/**
* Retreive a cached value if it exists, otherwise, get the value
* Retrieve a cached value if it exists, otherwise, get the value
* from the passed arguments
*
* @param object $object - object to retrieve fresh value from
@ -29,7 +29,7 @@ interface CacheInterface {
public function get($object, $method, array $args=[]);
/**
* Retreive a fresh value, and update the cache
* Retrieve a fresh value, and update the cache
*
* @param object $object - object to retrieve fresh value from
* @param string $method - method name to call

View File

@ -13,6 +13,7 @@
namespace Aviat\Ion\Cache;
use Aviat\Ion\ConfigInterface;
use Aviat\Ion\Cache\Driver\DriverInterface;
/**
* Class proxying cached and fresh values from the selected cache driver
@ -20,7 +21,7 @@ use Aviat\Ion\ConfigInterface;
class CacheManager implements CacheInterface {
/**
* @var CacheDriverInterface
* @var DriverInterface
*/
protected $driver;

View File

@ -10,12 +10,12 @@
* @license MIT
*/
namespace Aviat\Ion\Cache;
namespace Aviat\Ion\Cache\Driver;
/**
* Interface for cache drivers
*/
interface CacheDriverInterface {
interface DriverInterface {
/**
* Retreive a value from the cache backend
*
@ -29,7 +29,7 @@ interface CacheDriverInterface {
*
* @param string $key
* @param mixed $value
* @return CacheDriverInterface
* @return DriverInterface
*/
public function set($key, $value);
@ -37,7 +37,7 @@ interface CacheDriverInterface {
* Invalidate a cached value
*
* @param string $key
* @return CacheDriverInterface
* @return DriverInterface
*/
public function invalidate($key);
@ -48,4 +48,4 @@ interface CacheDriverInterface {
*/
public function invalidateAll();
}
// End of CacheDriverInterface.php
// End of DriverInterface.php

View File

@ -0,0 +1,62 @@
<?php
/**
* Ion
*
* Building blocks for web development
*
* @package Ion
* @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016
* @license MIT
*/
namespace Aviat\Ion\Cache\Driver;
use Aviat\Ion\Json;
use Aviat\Ion\JsonException;
/**
* Abstract base for Cache drivers to share common functionality
*/
trait DriverTrait {
/**
* Key prefix for key / value cache stores
*/
protected static $CACHE_KEY_PREFIX = "hbac:cache:";
/**
* Set key prefix for cache drivers that have global keys
*
* @param string $key - the raw key name
* @return string - the prefixed key name
*/
protected function prefix($key)
{
return static::$CACHE_KEY_PREFIX . $key;
}
/**
* Converts data to cache to a string representation for storage in a cache
*
* @param mixed $data - data to store in the cache backend
* @return string
*/
protected function serialize($data)
{
return Json::encode($data);
}
/**
* Convert serialized data from cache backend to native types
*
* @param string $data - data from cache backend
* @return mixed
* @throws JsonException
*/
protected function unserialize($data)
{
return Json::decode($data);
}
}
// End of DriverTrait.php

View File

@ -11,32 +11,20 @@
*/
namespace Aviat\Ion\Cache\Driver;
use Aviat\Ion\ConfigInterface;
use Aviat\Ion\Cache\CacheDriverInterface;
/**
* The Driver for no real cache
*/
class NullDriver implements CacheDriverInterface {
class NullDriver implements DriverInterface {
/**
* 'Cache' for Null data store
*/
protected $data;
protected $data = [];
/**
* Create the Null cache driver
*
* @param ConfigInterface $config The configuration management class
*/
public function __construct(ConfigInterface $config)
{
$this->data = [];
}
/**
* Retreive a value from the cache backend
* Retrieve a value from the cache backend
*
* @param string $key
* @return mixed
@ -53,7 +41,7 @@ class NullDriver implements CacheDriverInterface {
*
* @param string $key
* @param mixed $value
* @return CacheDriverInterface
* @return DriverInterface
*/
public function set($key, $value)
{
@ -65,7 +53,7 @@ class NullDriver implements CacheDriverInterface {
* Invalidate a cached value
*
* @param string $key
* @return CacheDriverInterface
* @return DriverInterface
*/
public function invalidate($key)
{

View File

@ -13,11 +13,15 @@
namespace Aviat\Ion\Cache\Driver;
use Aviat\Ion\ConfigInterface;
use Aviat\Ion\Cache\CacheDriverInterface;
use Predis\Client;
class RedisDriver implements CacheDriverInterface {
/**
* Cache Driver for a Redis backend
*/
class RedisDriver implements DriverInterface {
use DriverTrait;
/**
* THe Predis library instance
@ -35,6 +39,10 @@ class RedisDriver implements CacheDriverInterface {
{
$redisConfig = $config->get('redis');
// If you don't have a redis password set, and you attempt to send an
// empty string, Redis will think you want to authenticate with a password
// that is an empty string. To work around this, empty string passwords
// are considered to be a lack of a password
if (array_key_exists('password', $redisConfig) && $redisConfig['password'] === '')
{
unset($redisConfig['password']);
@ -54,36 +62,45 @@ class RedisDriver implements CacheDriverInterface {
/**
* Retrieve a value from the cache backend
*
* @param string $key
* @param string $rawKey
* @return mixed
*/
public function get($key)
public function get($rawKey)
{
return json_decode($this->redis->get($key));
$key = $this->prefix($rawKey);
$serializedData = $this->redis->get($key);
return $this->unserialize($serializedData);
}
/**
* Set a cached value
*
* @param string $key
* @param string $rawKey
* @param mixed $value
* @return CacheDriverInterface
* @return DriverInterface
*/
public function set($key, $value)
public function set($rawKey, $value)
{
$this->redis->set($key, json_encode($value));
$key = $this->prefix($rawKey);
$serializedData = $this->serialize($value);
$this->redis->set($key, $serializedData);
return $this;
}
/**
* Invalidate a cached value
*
* @param string $key
* @return CacheDriverInterface
* @param string $rawKey
* @return DriverInterface
*/
public function invalidate($key)
public function invalidate($rawKey)
{
$key = $this->prefix($rawKey);
$this->redis->del($key);
return $this;
}
@ -94,7 +111,7 @@ class RedisDriver implements CacheDriverInterface {
*/
public function invalidateAll()
{
$this->redis->flushDB();
$this->redis->flushdb();
}
}
// End of RedisDriver.php

View File

@ -13,14 +13,15 @@
namespace Aviat\Ion\Cache\Driver;
use Aviat\Ion\ConfigInterface;
use Aviat\Ion\Cache\CacheDriverInterface;
use Aviat\Ion\Exception\ConfigException;
use Aviat\Ion\Model\DB;
/**
* Driver for caching via a traditional SQL database
*/
class SQLDriver extends DB implements CacheDriverInterface {
class SQLDriver extends DB implements DriverInterface {
use DriverTrait;
/**
* The query builder object
@ -60,12 +61,14 @@ class SQLDriver extends DB implements CacheDriverInterface {
->get();
$row = $query->fetch(\PDO::FETCH_ASSOC);
if ( ! empty($row))
if (empty($row))
{
return json_decode($row['value']);
return NULL;
}
return NULL;
$serializedData = $row['value'];
return $this->unserialize($serializedData);
}
/**
@ -73,15 +76,17 @@ class SQLDriver extends DB implements CacheDriverInterface {
*
* @param string $key
* @param mixed $value
* @return CacheDriverInterface
* @return DriverInterface
*/
public function set($key, $value)
{
$serializedData = $this->serialize($value);
$this->db->set([
'key' => $key,
'value' => json_encode($value),
'value' => $serializedData,
]);
$this->db->insert('cache');
return $this;
@ -91,7 +96,7 @@ class SQLDriver extends DB implements CacheDriverInterface {
* Invalidate a cached value
*
* @param string $key
* @return CacheDriverInterface
* @return DriverInterface
*/
public function invalidate($key)
{

View File

@ -60,7 +60,15 @@ class Json {
*/
public static function decode($json, $assoc = TRUE, $depth = 512, $options = 0)
{
$data = json_decode($json, $assoc, $depth, $options);
// Don't try to decode null
if (empty($json))
{
return NULL;
}
// cast json to string so that streams from guzzle are correctly decoded
$data = json_decode((string) $json, $assoc, $depth, $options);
self::check_json_error();
return $data;
}

View File

@ -31,7 +31,7 @@ class AnimeCollectionModelTest extends AnimeClient_TestCase {
public function testSanity()
{
$friend = new Friend($this->collectionModel);
$this->assertInstanceOf('Aviat\AnimeClient\Model\DB', $this->collectionModel);
$this->assertInstanceOf('Aviat\Ion\Model\DB', $this->collectionModel);
$this->assertInstanceOf('Aviat\AnimeClient\Model\Anime', $friend->anime_model);
}

View File

@ -8,6 +8,7 @@ use GuzzleHttp\Psr7\Response;
use Zend\Diactoros\ServerRequestFactory;
use Zend\Diactoros\Response as HttpResponse;
use Aviat\Ion\Json;
use Aviat\AnimeClient\AnimeClient;
define('ROOT_DIR', __DIR__ . '/../');
@ -119,6 +120,36 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase {
$this->container->set('response', new HttpResponse());
}
/**
* Simplify getting test data
*
* Takes multiple path arguments
*
* @return string - contents of the data file
*/
public function getMockFile()
{
$args = func_get_args();
array_unshift($args, TEST_DATA_DIR);
$filePath = implode(DIRECTORY_SEPARATOR, $args);
return file_get_contents($filePath);
}
/**
* Simplify getting mocked test data
*
* Takes multiple path arguments
*
* @return mixed - the decoded data
*/
public function getMockFileData()
{
$rawData = call_user_func_array([$this, 'getMockFile'], func_get_args());
return Json::decode($rawData);
}
/**
* Create a mock guzzle client for testing
* api call methods

View File

@ -1,12 +1,12 @@
<?php
use Aviat\AnimeClient\Model\DB as BaseDBModel;
use Aviat\Ion\Model\DB as BaseDBModel;
class BaseDBModelTest extends AnimeClient_TestCase {
public function testBaseDBModelSanity()
{
$baseDBModel = new BaseDBModel($this->container);
$baseDBModel = new BaseDBModel($this->container->get('config'));
$this->assertTrue(is_object($baseDBModel));
}
}

View File

@ -3,9 +3,6 @@
* Global setup for unit tests
*/
use Aviat\Ion\Json;
use Aviat\AnimeClient\AnimeClient;
// Work around the silly timezone error
$timezone = ini_get('date.timezone');
if ($timezone === '' || $timezone === FALSE)

View File

@ -6,7 +6,6 @@
use Aviat\Ion\Enum;
use Aviat\Ion\Friend;
use Aviat\Ion\Json;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Transformer\AbstractTransformer;
use Aviat\Ion\View;
use Aviat\Ion\View\HtmlView;