summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2015-09-20 12:38:35 -0400
committerFrederic Guillot <fred@kanboard.net>2015-09-20 12:38:35 -0400
commitfe57edd9e87832dbd14ea8ffd2dc2f16ac1ceb6f (patch)
treeb8124f61496c9ce6d0d805e83e2818c6746711f9
parent8079b5af64fbebd14a3a0e470bc48bcb4a9bade3 (diff)
Add abstract cache layer
-rw-r--r--ChangeLog2
-rw-r--r--app/Core/Cache.php58
-rw-r--r--app/Core/Cache/Base.php38
-rw-r--r--app/Core/Cache/CacheInterface.php45
-rw-r--r--app/Core/Cache/MemoryCache.php65
-rw-r--r--app/Core/MemoryCache.php32
-rw-r--r--app/Helper/User.php4
-rw-r--r--app/ServiceProvider/ClassProvider.php4
-rw-r--r--tests/units/Core/Cache/MemoryCacheTest.php62
-rw-r--r--tests/units/Helper/UserHelperTest.php166
10 files changed, 383 insertions, 93 deletions
diff --git a/ChangeLog b/ChangeLog
index e0cbd5ed..4d0140db 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,8 @@ Improvements:
* Remove unnecessary margin for calendar header
* Show localized documentation if available
* Add event subtask.delete
+* Add abstract storage layer
+* Add abstract cache layer
Bug fixes:
diff --git a/app/Core/Cache.php b/app/Core/Cache.php
deleted file mode 100644
index 670a76e0..00000000
--- a/app/Core/Cache.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-
-namespace Core;
-
-use Pimple\Container;
-
-abstract class Cache
-{
- /**
- * Container instance
- *
- * @access protected
- * @var \Pimple\Container
- */
- protected $container;
-
- abstract public function init();
- abstract public function set($key, $value);
- abstract public function get($key);
- abstract public function flush();
- abstract public function remove($key);
-
- /**
- * Constructor
- *
- * @access public
- * @param \Pimple\Container $container
- */
- public function __construct(Container $container)
- {
- $this->container = $container;
- $this->init();
- }
-
- /**
- * Proxy cache
- *
- * Note: Arguments must be scalar types
- *
- * @access public
- * @param string $container Container name
- * @param string $method Container method
- * @return mixed
- */
- public function proxy($container, $method)
- {
- $args = func_get_args();
- $key = 'proxy_'.implode('_', $args);
- $result = $this->get($key);
-
- if ($result === null) {
- $result = call_user_func_array(array($this->container[$container], $method), array_splice($args, 2));
- $this->set($key, $result);
- }
-
- return $result;
- }
-}
diff --git a/app/Core/Cache/Base.php b/app/Core/Cache/Base.php
new file mode 100644
index 00000000..a16c12f0
--- /dev/null
+++ b/app/Core/Cache/Base.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Core\Cache;
+
+/**
+ * Base class for cache drivers
+ *
+ * @package cache
+ * @author Frederic Guillot
+ */
+abstract class Base
+{
+ /**
+ * Proxy cache
+ *
+ * Note: Arguments must be scalar types
+ *
+ * @access public
+ * @param string $class Class instance
+ * @param string $method Container method
+ * @return mixed
+ */
+ public function proxy($class, $method)
+ {
+ $args = func_get_args();
+ array_shift($args);
+
+ $key = 'proxy:'.get_class($class).':'.implode(':', $args);
+ $result = $this->get($key);
+
+ if ($result === null) {
+ $result = call_user_func_array(array($class, $method), array_splice($args, 1));
+ $this->set($key, $result);
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Core/Cache/CacheInterface.php b/app/Core/Cache/CacheInterface.php
new file mode 100644
index 00000000..8675ef8e
--- /dev/null
+++ b/app/Core/Cache/CacheInterface.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Core\Cache;
+
+/**
+ * Cache Interface
+ *
+ * @package cache
+ * @author Frederic Guillot
+ */
+interface CacheInterface
+{
+ /**
+ * Save a new value in the cache
+ *
+ * @access public
+ * @param string $key
+ * @param string $value
+ */
+ public function set($key, $value);
+
+ /**
+ * Fetch value from cache
+ *
+ * @access public
+ * @param string $key
+ * @return mixed Null when not found, cached value otherwise
+ */
+ public function get($key);
+
+ /**
+ * Clear all cache
+ *
+ * @access public
+ */
+ public function flush();
+
+ /**
+ * Remove cached value
+ *
+ * @access public
+ * @param string $key
+ */
+ public function remove($key);
+}
diff --git a/app/Core/Cache/MemoryCache.php b/app/Core/Cache/MemoryCache.php
new file mode 100644
index 00000000..b1de96bc
--- /dev/null
+++ b/app/Core/Cache/MemoryCache.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Core\Cache;
+
+/**
+ * Memory Cache
+ *
+ * @package cache
+ * @author Frederic Guillot
+ */
+class MemoryCache extends Base implements CacheInterface
+{
+ /**
+ * Container
+ *
+ * @access private
+ * @var array
+ */
+ private $storage = array();
+
+ /**
+ * Save a new value in the cache
+ *
+ * @access public
+ * @param string $key
+ * @param string $value
+ */
+ public function set($key, $value)
+ {
+ $this->storage[$key] = $value;
+ }
+
+ /**
+ * Fetch value from cache
+ *
+ * @access public
+ * @param string $key
+ * @return mixed Null when not found, cached value otherwise
+ */
+ public function get($key)
+ {
+ return isset($this->storage[$key]) ? $this->storage[$key] : null;
+ }
+
+ /**
+ * Clear all cache
+ *
+ * @access public
+ */
+ public function flush()
+ {
+ $this->storage = array();
+ }
+
+ /**
+ * Remove cached value
+ *
+ * @access public
+ * @param string $key
+ */
+ public function remove($key)
+ {
+ unset($this->storage[$key]);
+ }
+}
diff --git a/app/Core/MemoryCache.php b/app/Core/MemoryCache.php
deleted file mode 100644
index f80a66ef..00000000
--- a/app/Core/MemoryCache.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-namespace Core;
-
-class MemoryCache extends Cache
-{
- private $storage = array();
-
- public function init()
- {
- }
-
- public function set($key, $value)
- {
- $this->storage[$key] = $value;
- }
-
- public function get($key)
- {
- return isset($this->storage[$key]) ? $this->storage[$key] : null;
- }
-
- public function flush()
- {
- $this->storage = array();
- }
-
- public function remove($key)
- {
- unset($this->storage[$key]);
- }
-}
diff --git a/app/Helper/User.php b/app/Helper/User.php
index cb596fb0..3108a79a 100644
--- a/app/Helper/User.php
+++ b/app/Helper/User.php
@@ -99,7 +99,7 @@ class User extends \Core\Base
return true;
}
- return $this->memoryCache->proxy('acl', 'handleProjectAdminPermissions', $project_id);
+ return $this->memoryCache->proxy($this->container['acl'], 'handleProjectAdminPermissions', $project_id);
}
/**
@@ -114,7 +114,7 @@ class User extends \Core\Base
return true;
}
- return $this->memoryCache->proxy('acl', 'handleProjectManagerPermissions', $project_id);
+ return $this->memoryCache->proxy($this->container['acl'], 'handleProjectManagerPermissions', $project_id);
}
/**
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index a5677948..899574e9 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -72,12 +72,14 @@ class ClassProvider implements ServiceProviderInterface
'Helper',
'HttpClient',
'Lexer',
- 'MemoryCache',
'Request',
'Router',
'Session',
'Template',
),
+ 'Core\Cache' => array(
+ 'MemoryCache',
+ ),
'Integration' => array(
'BitbucketWebhook',
'GithubWebhook',
diff --git a/tests/units/Core/Cache/MemoryCacheTest.php b/tests/units/Core/Cache/MemoryCacheTest.php
new file mode 100644
index 00000000..b28604ed
--- /dev/null
+++ b/tests/units/Core/Cache/MemoryCacheTest.php
@@ -0,0 +1,62 @@
+<?php
+
+require_once __DIR__.'/../../Base.php';
+
+use Core\Cache\MemoryCache;
+
+class MemoryCacheTest extends Base
+{
+ public function testKeyNotFound()
+ {
+ $c = new MemoryCache;
+ $this->assertEquals(null, $c->get('mykey'));
+ }
+
+ public function testSetValue()
+ {
+ $c = new MemoryCache;
+ $c->set('mykey', 'myvalue');
+ $this->assertEquals('myvalue', $c->get('mykey'));
+ }
+
+ public function testRemoveValue()
+ {
+ $c = new MemoryCache;
+ $c->set('mykey', 'myvalue');
+ $c->remove('mykey');
+ $this->assertEquals(null, $c->get('mykey'));
+ }
+
+ public function testFlushAll()
+ {
+ $c = new MemoryCache;
+ $c->set('mykey', 'myvalue');
+ $c->flush();
+ $this->assertEquals(null, $c->get('mykey'));
+ }
+
+ public function testProxy()
+ {
+ $c = new MemoryCache;
+
+ $class = $this
+ ->getMockBuilder('stdClass')
+ ->setMethods(array('doSomething'))
+ ->getMock();
+
+ $class
+ ->expects($this->once())
+ ->method('doSomething')
+ ->with(
+ $this->equalTo(1),
+ $this->equalTo(2)
+ )
+ ->will($this->returnValue(3));
+
+ // First call will store the computed value
+ $this->assertEquals(3, $c->proxy($class, 'doSomething', 1, 2));
+
+ // Second call get directly the cached value
+ $this->assertEquals(3, $c->proxy($class, 'doSomething', 1, 2));
+ }
+}
diff --git a/tests/units/Helper/UserHelperTest.php b/tests/units/Helper/UserHelperTest.php
index 947f606a..24f2b3b2 100644
--- a/tests/units/Helper/UserHelperTest.php
+++ b/tests/units/Helper/UserHelperTest.php
@@ -3,6 +3,10 @@
require_once __DIR__.'/../Base.php';
use Helper\User;
+use Model\Project;
+use Model\ProjectPermission;
+use Model\User as UserModel;
+use Core\Session;
class UserHelperTest extends Base
{
@@ -13,4 +17,166 @@ class UserHelperTest extends Base
$this->assertEquals('CN', $h->getInitials('chuck norris'));
$this->assertEquals('A', $h->getInitials('admin'));
}
+
+ public function testIsProjectAdministrationAllowedForProjectAdmin()
+ {
+ $h = new User($this->container);
+ $p = new Project($this->container);
+ $pp = new ProjectPermission($this->container);
+ $u = new UserModel($this->container);
+ $session = new Session;
+
+ // We create our user
+ $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest')));
+
+ // We create a project and set our user as project manager
+ $this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
+ $this->assertTrue($pp->addMember(1, 2));
+ $this->assertTrue($pp->isMember(1, 2));
+ $this->assertFalse($pp->isManager(1, 2));
+
+ // We fake a session for him
+ $session['user'] = array(
+ 'id' => 2,
+ 'is_admin' => false,
+ 'is_project_admin' => true,
+ );
+
+ $this->assertTrue($h->isProjectAdministrationAllowed(1));
+ }
+
+ public function testIsProjectAdministrationAllowedForProjectMember()
+ {
+ $h = new User($this->container);
+ $p = new Project($this->container);
+ $pp = new ProjectPermission($this->container);
+ $u = new UserModel($this->container);
+ $session = new Session;
+
+ // We create our user
+ $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest')));
+
+ // We create a project and set our user as project member
+ $this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
+ $this->assertTrue($pp->addMember(1, 2));
+ $this->assertTrue($pp->isMember(1, 2));
+ $this->assertFalse($pp->isManager(1, 2));
+
+ // We fake a session for him
+ $session['user'] = array(
+ 'id' => 2,
+ 'is_admin' => false,
+ 'is_project_admin' => false,
+ );
+
+ $this->assertFalse($h->isProjectAdministrationAllowed(1));
+ }
+
+ public function testIsProjectAdministrationAllowedForProjectManager()
+ {
+ $h = new User($this->container);
+ $p = new Project($this->container);
+ $pp = new ProjectPermission($this->container);
+ $u = new UserModel($this->container);
+ $session = new Session;
+
+ // We create our user
+ $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest')));
+
+ // We create a project and set our user as project member
+ $this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
+ $this->assertTrue($pp->addManager(1, 2));
+ $this->assertTrue($pp->isMember(1, 2));
+ $this->assertTrue($pp->isManager(1, 2));
+
+ // We fake a session for him
+ $session['user'] = array(
+ 'id' => 2,
+ 'is_admin' => false,
+ 'is_project_admin' => false,
+ );
+
+ $this->assertFalse($h->isProjectAdministrationAllowed(1));
+ }
+
+ public function testIsProjectManagementAllowedForProjectAdmin()
+ {
+ $h = new User($this->container);
+ $p = new Project($this->container);
+ $pp = new ProjectPermission($this->container);
+ $u = new UserModel($this->container);
+ $session = new Session;
+
+ // We create our user
+ $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest')));
+
+ // We create a project and set our user as project manager
+ $this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
+ $this->assertTrue($pp->addMember(1, 2));
+ $this->assertTrue($pp->isMember(1, 2));
+ $this->assertFalse($pp->isManager(1, 2));
+
+ // We fake a session for him
+ $session['user'] = array(
+ 'id' => 2,
+ 'is_admin' => false,
+ 'is_project_admin' => true,
+ );
+
+ $this->assertTrue($h->isProjectManagementAllowed(1));
+ }
+
+ public function testIsProjectManagementAllowedForProjectMember()
+ {
+ $h = new User($this->container);
+ $p = new Project($this->container);
+ $pp = new ProjectPermission($this->container);
+ $u = new UserModel($this->container);
+ $session = new Session;
+
+ // We create our user
+ $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest')));
+
+ // We create a project and set our user as project member
+ $this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
+ $this->assertTrue($pp->addMember(1, 2));
+ $this->assertTrue($pp->isMember(1, 2));
+ $this->assertFalse($pp->isManager(1, 2));
+
+ // We fake a session for him
+ $session['user'] = array(
+ 'id' => 2,
+ 'is_admin' => false,
+ 'is_project_admin' => false,
+ );
+
+ $this->assertFalse($h->isProjectManagementAllowed(1));
+ }
+
+ public function testIsProjectManagementAllowedForProjectManager()
+ {
+ $h = new User($this->container);
+ $p = new Project($this->container);
+ $pp = new ProjectPermission($this->container);
+ $u = new UserModel($this->container);
+ $session = new Session;
+
+ // We create our user
+ $this->assertEquals(2, $u->create(array('username' => 'unittest', 'password' => 'unittest')));
+
+ // We create a project and set our user as project member
+ $this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
+ $this->assertTrue($pp->addManager(1, 2));
+ $this->assertTrue($pp->isMember(1, 2));
+ $this->assertTrue($pp->isManager(1, 2));
+
+ // We fake a session for him
+ $session['user'] = array(
+ 'id' => 2,
+ 'is_admin' => false,
+ 'is_project_admin' => false,
+ );
+
+ $this->assertTrue($h->isProjectManagementAllowed(1));
+ }
}