Skip to content
Snippets Groups Projects
Commit 71724582 authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

allow StudipCachedArray to expire completely and use that in RolePersistence, fixes #1580

Closes #1580

Merge request studip/studip!1009
parent 181142fd
No related branches found
No related tags found
No related merge requests found
......@@ -15,21 +15,24 @@ class StudipCachedArray implements ArrayAccess
protected $data = [];
protected $hash;
/**
* Constructs the cached array
*
* @param string $key Cache key where the array is/should be stored
* an int which will be length of the substring
* of the given chache offset or a callable which
* will return the partition key.
* @param int $duration Duration in seconds for which the item shall be
* stored
* @param string $key Cache key where the array is/should be stored
* an int which will be length of the substring
* of the given chache offset or a callable which
* will return the partition key.
* @param int $duration Duration in seconds for which the item shall be
* stored
*/
public function __construct(string $key, int $duration = StudipCache::DEFAULT_EXPIRATION)
{
$this->key = self::class . "/{$key}";
$this->cache = StudipCacheFactory::getCache();
$this->key = self::class . "/{$key}";
$this->cache = StudipCacheFactory::getCache();
$this->duration = $duration;
$this->hash = $this->getHash();
$this->reset();
}
......@@ -42,10 +45,20 @@ class StudipCachedArray implements ArrayAccess
$this->data = [];
}
/**
* Removes all values from the cache.
*/
public function expire(): void
{
$this->hash = $this->getHash(true);
$this->reset();
}
/**
* Determines whether an offset exists in the array.
*
* @param string $offset Offset
*
* @return bool
*/
public function offsetExists($offset): bool
......@@ -58,6 +71,7 @@ class StudipCachedArray implements ArrayAccess
* Returns the value at given offset or null if it doesn't exist.
*
* @param string $offset Offset
*
* @return mixed
*/
public function offsetGet($offset)
......@@ -75,7 +89,7 @@ class StudipCachedArray implements ArrayAccess
public function offsetSet($offset, $value): void
{
if ($offset === null) {
throw new Exception('Cannot push to cached array, use StudipCachedArray instead');
throw new Exception('Cannot push to cached array, use correct offset instead');
}
if (!isset($this->data[$offset]) || $this->data[$offset] !== $value) {
......@@ -120,9 +134,11 @@ class StudipCachedArray implements ArrayAccess
*/
protected function storeData(string $offset): void
{
$data = $this->swapNullAndFalse($this->data[$offset]);
$this->cache->write(
$this->getCacheKey($offset),
$this->swapNullAndFalse($this->data[$offset]),
$data,
$this->duration
);
}
......@@ -131,11 +147,18 @@ class StudipCachedArray implements ArrayAccess
* Returns the cache key for a specific offset.
*
* @param string $offset Offset of the cached item
*
* @return string
*/
private function getCacheKey(string $offset): string
{
return rtrim($this->key, '/') . "/{$offset}";
$key = rtrim($this->key, '/');
if ($this->hash) {
$key .= "/{$this->hash}";
}
$key .= "/{$offset}";
return $key;
}
/**
......@@ -158,4 +181,21 @@ class StudipCachedArray implements ArrayAccess
return $value;
}
/**
* Loads or creates and stores a hash for this cached array.
*
* @return string
*/
private function getHash(bool $recreate = false): string
{
if (!$recreate) {
$hash = $this->cache->read($this->key);
return $hash === false ? '' : $hash;
}
$hash = md5(uniqid(__CLASS__, true));
$this->cache->write($this->key, $hash);
return $hash;
}
}
......@@ -129,9 +129,10 @@ class RolePersistence
// sweep roles cache
self::expireRolesCache();
self::expireUserCache();
foreach ($statement as $plugin_id) {
unset(self::getPluginRolesCache()[$plugin_id]);
self::expirePluginCache($plugin_id);
}
NotificationCenter::postNotification('RoleDidDelete', $id, $name);
......@@ -338,7 +339,7 @@ class RolePersistence
$statement->execute();
}
unset(self::getPluginRolesCache()[$plugin_id]);
self::expirePluginCache($plugin_id);
foreach ($role_ids as $role_id) {
NotificationCenter::postNotification(
......@@ -370,7 +371,7 @@ class RolePersistence
$statement->execute();
}
unset(self::getPluginRolesCache()[$plugin_id]);
self::expirePluginCache($plugin_id);
foreach ($role_ids as $role_id) {
NotificationCenter::postNotification(
......@@ -488,7 +489,7 @@ class RolePersistence
private static $user_roles_cache = null;
private static $plugin_roles_cache = null;
private static function getUserRolesCache()
private static function getUserRolesCache(): StudipCachedArray
{
if (self::$user_roles_cache === null) {
self::$user_roles_cache = new StudipCachedArray(self::USER_ROLES_CACHE_KEY);
......@@ -496,7 +497,7 @@ class RolePersistence
return self::$user_roles_cache;
}
private static function getPluginRolesCache()
private static function getPluginRolesCache(): StudipCachedArray
{
if (self::$plugin_roles_cache === null) {
self::$plugin_roles_cache = new StudipCachedArray(self::PLUGIN_ROLES_CACHE_KEY);
......@@ -504,13 +505,52 @@ class RolePersistence
return self::$plugin_roles_cache;
}
/**
* Expires all cached roles.
*/
public static function expireRolesCache()
{
StudipCacheFactory::getCache()->expire(self::ROLES_CACHE_KEY);
}
public static function expireUserCache($user_id)
/**
* Expires all cached user role assignments.
*
* @param string|null $user_id Optional user id to expire the cache for.
* If none is given, the whole cache is cleared.
*/
public static function expireUserCache($user_id = null)
{
unset(self::getUserRolesCache()[$user_id]);
if ($user_id === null) {
self::getUserRolesCache()->expire();
} else {
unset(self::getUserRolesCache()[$user_id]);
}
}
/**
* Expires all cached plugin role assignments.
*
* @param string|int|null $plugin_id Optional plugin id to expire the cache
* for. If none is given, the whole cache
* is cleared.
*/
public static function expirePluginCache($plugin_id = null)
{
if ($plugin_id === null) {
self::getPluginRolesCache()->expire();
} else {
unset(self::getPluginRolesCache()[$plugin_id]);
}
}
/**
* Expires all caches
*/
public static function expireCaches(): void
{
self::expireRolesCache();
self::expireUserCache();
self::expirePluginCache();
}
}
......@@ -48,6 +48,21 @@ class StudipCachedArrayTest extends \Codeception\Test\Unit
$this->assertFalse(isset($cache[$key]));
}
/**
* @depends testStorage
* @dataProvider StorageProvider
*/
public function testExpiration($key, $value)
{
$cache = $this->getCachedArray();
$cache[$key] = $value;
$cache->expire();
$this->assertFalse(isset($cache[$key]));
}
public function StorageProvider(): array
{
return [
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment