diff --git a/composer.json b/composer.json
index 8e50f99..6ab4ae2 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,8 @@
},
"require-dev": {
"phpunit/phpunit": "^4.8",
- "squizlabs/php_codesniffer": "^2.0@dev"
+ "squizlabs/php_codesniffer": "^2.0@dev",
+ "mockery/mockery": "^0.9"
},
"license": "GPLv3",
"authors": [
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 434cb9e..5987fb6 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -8,5 +8,8 @@
test/UuidGenerator
+
+ test/KeyCache
+
diff --git a/src/KeyCache/IUuidCache.php b/src/KeyCache/IUuidCache.php
new file mode 100644
index 0000000..2cfb01b
--- /dev/null
+++ b/src/KeyCache/IUuidCache.php
@@ -0,0 +1,81 @@
+ value service to store UUID -> Fedora Paths
+ * not yet indexed into the triplestore (ie. in a transaction)
+ * @author Jared Whiklo
+ * @since 2016-04-12
+ */
+interface IUuidCache
+{
+
+ /**
+ * Sets the value for the provided key.
+ *
+ * @var string $txID
+ * The transaction ID.
+ * @var string $uuid
+ * The UUID.
+ * @var string $path
+ * The Fedora path.
+ * @var int $expire
+ * The number of seconds from now to expire. Default to an hour.
+ * @return bool
+ * Was key set successful.
+ */
+ public function set($txID, $uuid, $path, $expire = 3600);
+
+ /**
+ * Gets the Fedora path for the provided UUID.
+ *
+ * @var string $txID
+ * The transaction ID.
+ * @var string $uuid
+ * The UUID
+ * @return string
+ * The UUID corresponding to the path in the transaction or NULL
+ */
+ public function getByUuid($txID, $uuid);
+
+ /**
+ * Gets the UUID for the provided path.
+ *
+ * @var string $txID
+ * The transaction ID.
+ * @var string $path
+ * The key.
+ * @return string
+ * The UUID corresponding to the path in the transaction or NULL
+ */
+ public function getByPath($txID, $path);
+
+ /**
+ * Delete any pairs related to transaction ID.
+ *
+ * @var string $txID
+ * The transaction ID.
+ * @return void
+ */
+ public function delete($txID);
+
+ /**
+ * Set/reset the transaction to expire in $seconds seconds.
+ *
+ * @var string $txID
+ * The transaction ID.
+ * @var int $seconds
+ * The number of seconds from now to expire.
+ * @return bool
+ * Whether the expiry was set or not.
+ */
+ public function extend($txID, $seconds);
+}
diff --git a/src/KeyCache/RedisKeyCache.php b/src/KeyCache/RedisKeyCache.php
new file mode 100644
index 0000000..2093968
--- /dev/null
+++ b/src/KeyCache/RedisKeyCache.php
@@ -0,0 +1,161 @@
+
+ * @since 2016-04-12
+ */
+class RedisKeyCache implements IUuidCache
+{
+
+ /**
+ * @var Redis $redis
+ * The Redis object.
+ */
+ protected $redis;
+ /**
+ * @var bool $connected
+ * Are we connected to the Redis server yet.
+ */
+ private $connected = false;
+ /**
+ * @var string $host
+ * The hostname of the redis server.
+ */
+ private $host;
+ /**
+ * @var int $port
+ * The port of the redis server.
+ */
+ private $port;
+
+ /**
+ * @param \Redis $instance
+ * An instance of the Redis client
+ */
+ public function __construct(\Redis $instance, $host, $port)
+ {
+ $this->redis = $instance;
+ $this->redis->host = $host;
+ $this->redis->port = $port;
+ }
+
+ /**
+ *
+ */
+ public function __destruct()
+ {
+ $this->redis->close();
+ }
+
+ /**
+ * Create using a hostname and port.
+ *
+ * @param $host
+ * The hostname of the redis server
+ * @param $port
+ * The port of the redis server
+ * @return RedisKeyCache
+ */
+ public static function create($host = "localhost", $port = 6379)
+ {
+ $redis = new \Redis();
+ $redis->connect($host, $port);
+ return new RedisKeyCache($redis, $host, $port);
+ }
+
+ /**
+ * Check if we are connected to the Redis server.
+ *
+ * @return bool Whether we are connected.
+ */
+ private function isConnected()
+ {
+ try {
+ $result = $this->redis->ping();
+ $connected = ($result == "+PONG");
+ } catch (RedisException $e) {
+ error_log("RedisKeyCache: Error communicating with Redis server - " . $e->getMessage());
+ # Try connecting once more.
+ $this->redis->connect($this->host, $this->port);
+ $result = $this->redis->ping();
+ $connected = ($result == "+PONG");
+ }
+ return $connected;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($txID, $uuid, $path, $expire = 3600)
+ {
+ if ($this->isConnected()) {
+ $result = $this->redis->hSetNx($txID, $uuid, $path);
+ if ($result) {
+ $this->redis->expire($txID, $expire);
+ }
+ return $result;
+ }
+ /**
+ * TODO: return exceptions??
+ */
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getByUuid($txId, $uuid)
+ {
+ if ($this->isConnected()) {
+ return $this->redis->hget($txId, $uuid);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getByPath($txId, $path)
+ {
+ if ($this->isConnected()) {
+ $hashes = $this->redis->hgetall($txId);
+ if ($hashes !== false) {
+ $flipped = array_flip($hashes);
+ if (array_key_exists($path, $flipped)) {
+ return $flipped[$path];
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function extend($txId, $expire = 3600)
+ {
+ if ($this->isConnected()) {
+ return $this->redis->expire($txId, $expire);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete($txId)
+ {
+ if ($this->isConnected()) {
+ return $this->redis->del($txId);
+ }
+ }
+}
diff --git a/test/KeyCache/UuidCacheTest.php b/test/KeyCache/UuidCacheTest.php
new file mode 100644
index 0000000..cd22155
--- /dev/null
+++ b/test/KeyCache/UuidCacheTest.php
@@ -0,0 +1,110 @@
+redis = \Mockery::mock('\Redis');
+ $this->redis->shouldReceive('expire')->andReturn(1);
+ $this->redis->shouldReceive('ping')->andReturn("+PONG");
+ $this->redis->shouldReceive('close')->andReturn(null);
+
+ $this->uuid_gen = new UuidGenerator();
+ }
+
+ /**
+ * @covers RedisKeyCache::set
+ * @group UnitTest
+ */
+ public function testAddUuidPair()
+ {
+ // Need both to account for OS X and Linux differences.
+ $this->redis->shouldReceive('hSetNx')->andReturn(1);
+ $this->redis->shouldReceive('hsetnx')->andReturn(1);
+ $redis_cache = new RedisKeyCache($this->redis, 'localhost', 6379);
+
+ $transId = "tx:" . $this->uuid_gen->generateV4();
+ $uuid = $this->uuid_gen->generateV4();
+ $path = "http://localhost:8080/fcrepo/rest/object1";
+
+ $this->assertEquals(1, $redis_cache->set($transId, $uuid, $path), "Error setting uuid->path hash");
+ }
+
+ /**
+ * @covers RedisKeyCache::getByUuid
+ * @group UnitTest
+ */
+ public function testGetByUuid()
+ {
+ $txID = $transId = "tx:" . $this->uuid_gen->generateV4();
+ $uuid = $this->uuid_gen->generateV4();
+ $path = "http://localhost:8080/fcrepo/rest/object1";
+
+ // Need both to account for OS X and Linux differences.
+ $this->redis->shouldReceive('hGet')->with($txID, $uuid)->andReturn($path);
+ $this->redis->shouldReceive('hget')->with($txID, $uuid)->andReturn($path);
+
+ $redis_cache = new RedisKeyCache($this->redis, 'localhost', 6379);
+
+ $this->assertEquals($path, $redis_cache->getByUuid($txID, $uuid), "Error getting by Uuid");
+ }
+
+ /**
+ * @covers RedisKeyCache::getByPath
+ * @group UnitTest
+ */
+ public function testGetByPath()
+ {
+ $txID = $transId = "tx:" . $this->uuid_gen->generateV4();
+
+ $uuid1 = $this->uuid_gen->generateV4();
+ $path1 = "http://localhost:8080/fcrepo/rest/object1";
+
+ $uuid2 = $this->uuid_gen->generateV4();
+ $path2 = "http://localhost:8080/fcrepo/rest/object2";
+
+ $hashes = array(
+ $uuid1 => $path1,
+ $uuid2 => $path2,
+ );
+
+ // Need both to account for OS X and Linux differences.
+ $this->redis->shouldReceive('hGetAll')->with($txID)->andReturn($hashes);
+ $this->redis->shouldReceive('hgetall')->with($txID)->andReturn($hashes);
+
+ $redis_cache = new RedisKeyCache($this->redis, 'localhost', 6379);
+
+ $this->assertEquals($uuid2, $redis_cache->getByPath($txID, $path2), "Error getting by Path");
+ }
+
+ /**
+ * @covers RedisKeyCache::delete
+ * @group UnitTest
+ */
+ public function testDelete()
+ {
+ $txID = $transId = "tx:" . $this->uuid_gen->generateV4();
+
+ $this->redis->shouldReceive('del')->with($txID)->andReturn(1);
+
+ $redis_cache = new RedisKeyCache($this->redis, 'localhost', 6379);
+
+ $this->assertEquals(1, $redis_cache->delete($txID), "Error deleting transaction ID.");
+ }
+
+ public function tearDown()
+ {
+ \Mockery::close();
+ }
+}
diff --git a/test/UuidGenerator/UuidTest.php b/test/UuidGenerator/UuidTest.php
index 063e21e..0227aae 100644
--- a/test/UuidGenerator/UuidTest.php
+++ b/test/UuidGenerator/UuidTest.php
@@ -1,6 +1,6 @@