aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMoritz Strohm <strohm@data-quest.de>2024-05-14 07:22:47 +0000
committerJan-Hendrik Willms <tleilax+studip@gmail.com>2024-05-14 07:22:47 +0000
commit40bdfaf4415ff9f46e63435fc5e61049649802f2 (patch)
treef3ae85d9edaef23db555a829571ff968c21f9af5 /lib
parent636039e25ccc6c33ae758bdb3ddfca4f68327948 (diff)
made Stud.IP cache compatible with PSR-6, re #3701
Merge request studip/studip!2570
Diffstat (limited to 'lib')
-rw-r--r--lib/activities/Activity.php4
-rw-r--r--lib/bootstrap-autoload.php5
-rw-r--r--lib/bootstrap-definitions.php4
-rw-r--r--lib/bootstrap.php4
-rw-r--r--lib/classes/MvvPerm.php4
-rw-r--r--lib/classes/Score.class.php2
-rw-r--r--lib/classes/SemClass.class.php10
-rw-r--r--lib/classes/SemType.class.php10
-rw-r--r--lib/classes/Seminar.class.php4
-rw-r--r--lib/classes/SimpleORMap.class.php12
-rw-r--r--lib/classes/Siteinfo.php6
-rw-r--r--lib/classes/StudipCache.class.php94
-rw-r--r--lib/classes/StudipCachedArray.php20
-rw-r--r--lib/classes/StudipDbCache.class.php123
-rw-r--r--lib/classes/StudipKing.class.php2
-rw-r--r--lib/classes/StudipMemoryCache.class.php84
-rw-r--r--lib/classes/UserLookup.class.php2
-rw-r--r--lib/classes/assets/SASSCompiler.php4
-rw-r--r--lib/classes/cache/Cache.class.php208
-rw-r--r--lib/classes/cache/DbCache.class.php142
-rw-r--r--lib/classes/cache/Exception.php27
-rw-r--r--lib/classes/cache/Factory.class.php (renamed from lib/classes/StudipCacheFactory.class.php)53
-rw-r--r--lib/classes/cache/FileCache.class.php (renamed from lib/classes/StudipFileCache.class.php)191
-rw-r--r--lib/classes/cache/InvalidCacheArgumentException.php28
-rw-r--r--lib/classes/cache/Item.class.php163
-rw-r--r--lib/classes/cache/KeyTrait.php (renamed from lib/classes/StudipCacheKeyTrait.php)10
-rw-r--r--lib/classes/cache/MemcachedCache.class.php (renamed from lib/classes/StudipMemcachedCache.php)110
-rw-r--r--lib/classes/cache/MemoryCache.class.php98
-rw-r--r--lib/classes/cache/Proxy.class.php (renamed from lib/classes/StudipCacheProxy.php)89
-rw-r--r--lib/classes/cache/RedisCache.class.php (renamed from lib/classes/StudipRedisCache.class.php)95
-rw-r--r--lib/classes/cache/Wrapper.class.php (renamed from lib/classes/StudipCacheWrapper.php)76
-rw-r--r--lib/classes/cas/CAS_PGTStorage_Cache.php4
-rw-r--r--lib/cronjobs/purge_cache.class.php4
-rw-r--r--lib/functions.php2
-rw-r--r--lib/models/CourseDate.class.php6
-rw-r--r--lib/models/OERMaterial.php4
-rw-r--r--lib/models/PersonalNotifications.class.php6
-rw-r--r--lib/models/Semester.class.php6
-rw-r--r--lib/models/StudipCacheOperation.php2
-rw-r--r--lib/phplib/CT_Cache.class.php2
-rw-r--r--lib/plugins/db/RolePersistence.class.php4
-rw-r--r--lib/plugins/engine/PluginRepository.class.php2
-rw-r--r--lib/raumzeit/SingleDate.class.php4
43 files changed, 1073 insertions, 657 deletions
diff --git a/lib/activities/Activity.php b/lib/activities/Activity.php
index 3508e5a..e1c918d 100644
--- a/lib/activities/Activity.php
+++ b/lib/activities/Activity.php
@@ -163,7 +163,7 @@ class Activity extends \SimpleORMap
);
//Expire Cache
- \StudipCacheFactory::getCache()->expire('activity/oldest_activity');
+ \Studip\Cache\Factory::getCache()->expire('activity/oldest_activity');
}
/**
@@ -173,7 +173,7 @@ class Activity extends \SimpleORMap
*/
public static function getOldestActivity()
{
- $cache = \StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache_key = 'activity/oldest-activity';
if (!$activity = unserialize($cache->read($cache_key))) {
diff --git a/lib/bootstrap-autoload.php b/lib/bootstrap-autoload.php
index 4e63115..21219fd 100644
--- a/lib/bootstrap-autoload.php
+++ b/lib/bootstrap-autoload.php
@@ -20,6 +20,11 @@ StudipAutoloader::addAutoloadPath('lib/classes/admission');
StudipAutoloader::addAutoloadPath('lib/classes/admission/userfilter');
StudipAutoloader::addAutoloadPath('lib/classes/auth_plugins');
StudipAutoloader::addAutoloadPath('lib/classes/calendar');
+
+StudipAutoloader::addAutoloadPath('lib/classes/cache', 'Studip\\Cache');
+class_alias(\Studip\Cache\Factory::class, 'StudipCacheFactory');
+class_alias(\Studip\Cache\Cache::class, 'StudipCache');
+
StudipAutoloader::addAutoloadPath('lib/classes/exportdocument');
StudipAutoloader::addAutoloadPath('lib/classes/forms');
StudipAutoloader::addAutoloadPath('lib/classes/globalsearch');
diff --git a/lib/bootstrap-definitions.php b/lib/bootstrap-definitions.php
index 17f35d1..ee80135 100644
--- a/lib/bootstrap-definitions.php
+++ b/lib/bootstrap-definitions.php
@@ -14,8 +14,8 @@ return [
),
]);
}),
- StudipCache::class => DI\factory(function () {
- return StudipCacheFactory::getCache();
+ \Studip\Cache\Cache::class => DI\factory(function () {
+ return \Studip\Cache\Factory::getCache();
}),
StudipPDO::class => DI\factory(function () {
return DBManager::get();
diff --git a/lib/bootstrap.php b/lib/bootstrap.php
index 364f9d9..9afc16a 100644
--- a/lib/bootstrap.php
+++ b/lib/bootstrap.php
@@ -170,7 +170,7 @@ if (isset($_SERVER['REQUEST_METHOD'])) {
// bootstrap because the stud.ip cache needs to have a db conenction)
if ($GLOBALS['CACHING_ENABLE']) {
$lookup_hash = null;
- $cached = StudipCacheFactory::getCache()->read('STUDIP#autoloader-classes');
+ $cached = \Studip\Cache\Factory::getCache()->read('STUDIP#autoloader-classes');
if ($cached) {
$class_lookup = json_decode($cached, true);
if (is_array($class_lookup)) {
@@ -182,7 +182,7 @@ if ($GLOBALS['CACHING_ENABLE']) {
register_shutdown_function(function () use ($lookup_hash) {
$cached = json_encode(StudipAutoloader::$class_lookup, JSON_UNESCAPED_UNICODE);
if (md5($cached) !== $lookup_hash) {
- StudipCacheFactory::getCache()->write(
+ \Studip\Cache\Factory::getCache()->write(
'STUDIP#autoloader-classes',
$cached,
7 * 24 * 60 * 60
diff --git a/lib/classes/MvvPerm.php b/lib/classes/MvvPerm.php
index 93f9f44..91e1e35 100644
--- a/lib/classes/MvvPerm.php
+++ b/lib/classes/MvvPerm.php
@@ -563,7 +563,7 @@ class MvvPerm {
private static function getPrivileges($mvv_table)
{
if (self::$privileges === null) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
self::$privileges = unserialize($cache->read(MVV::CACHE_KEY . '/privileges'));
}
@@ -576,7 +576,7 @@ class MvvPerm {
include $config_file; // Defines $privileges
self::$privileges[$mvv_table] = $privileges ?? [];
}
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->write(MVV::CACHE_KEY . '/privileges', serialize(self::$privileges));
}
}
diff --git a/lib/classes/Score.class.php b/lib/classes/Score.class.php
index 8f038f9..f7d8ea3 100644
--- a/lib/classes/Score.class.php
+++ b/lib/classes/Score.class.php
@@ -121,7 +121,7 @@ class Score
public static function GetMyScore($user_or_id = null)
{
$user = $user_or_id ? User::toObject($user_or_id) : User::findCurrent();
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
if ($cache->read("user_score_of_".$user->id)) {
return $cache->read("user_score_of_".$user->id);
}
diff --git a/lib/classes/SemClass.class.php b/lib/classes/SemClass.class.php
index 63be920..2a038e2 100644
--- a/lib/classes/SemClass.class.php
+++ b/lib/classes/SemClass.class.php
@@ -389,7 +389,7 @@ class SemClass implements ArrayAccess
"chdate = UNIX_TIMESTAMP() " .
"WHERE id = :id ".
"");
- StudipCacheFactory::getCache()->expire('DB_SEM_CLASSES_ARRAY');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEM_CLASSES_ARRAY');
return $statement->execute([
'id' => $this->data['id'],
'name' => $this->data['name'],
@@ -453,7 +453,7 @@ class SemClass implements ArrayAccess
DELETE FROM sem_classes
WHERE id = :id
");
- StudipCacheFactory::getCache()->expire('DB_SEM_CLASSES_ARRAY');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEM_CLASSES_ARRAY');
return $statement->execute([
'id' => $this->data['id']
]);
@@ -552,7 +552,7 @@ class SemClass implements ArrayAccess
$db = DBManager::get();
self::$sem_classes = [];
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$class_array = unserialize($cache->read('DB_SEM_CLASSES_ARRAY'));
if (!$class_array) {
@@ -564,7 +564,7 @@ class SemClass implements ArrayAccess
$class_array = $statement->fetchAll(PDO::FETCH_ASSOC);
if ($class_array) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->write('DB_SEM_CLASSES_ARRAY', serialize($class_array));
}
} catch (PDOException $e) {
@@ -593,7 +593,7 @@ class SemClass implements ArrayAccess
*/
static public function refreshClasses()
{
- StudipCacheFactory::getCache()->expire('DB_SEM_CLASSES_ARRAY');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEM_CLASSES_ARRAY');
self::$sem_classes = null;
return self::getClasses();
}
diff --git a/lib/classes/SemType.class.php b/lib/classes/SemType.class.php
index 2365c4e..5be1f19 100644
--- a/lib/classes/SemType.class.php
+++ b/lib/classes/SemType.class.php
@@ -68,7 +68,7 @@ class SemType implements ArrayAccess
"chdate = UNIX_TIMESTAMP() " .
"WHERE id = :id ".
"");
- StudipCacheFactory::getCache()->expire('DB_SEM_TYPES_ARRAY');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEM_TYPES_ARRAY');
return $statement->execute([
'id' => $this->data['id'],
'name' => $this->data['name'],
@@ -89,7 +89,7 @@ class SemType implements ArrayAccess
DELETE FROM sem_types
WHERE id = :id
");
- StudipCacheFactory::getCache()->expire('DB_SEM_TYPES_ARRAY');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEM_TYPES_ARRAY');
return $statement->execute([
'id' => $this->data['id']
]);
@@ -175,7 +175,7 @@ class SemType implements ArrayAccess
$db = DBManager::get();
self::$sem_types = [];
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$types_array = unserialize($cache->read('DB_SEM_TYPES_ARRAY'));
if (!$types_array) {
try {
@@ -185,7 +185,7 @@ class SemType implements ArrayAccess
$statement->execute();
$types_array = $statement->fetchAll(PDO::FETCH_ASSOC);
if ($types_array) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->write('DB_SEM_TYPES_ARRAY', serialize($types_array));
}
} catch (PDOException $e) {
@@ -210,7 +210,7 @@ class SemType implements ArrayAccess
static public function refreshTypes() {
self::$sem_types = null;
- StudipCacheFactory::getCache()->expire('DB_SEM_TYPES_ARRAY');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEM_TYPES_ARRAY');
return self::getTypes();
}
diff --git a/lib/classes/Seminar.class.php b/lib/classes/Seminar.class.php
index 054c337..dda25ee 100644
--- a/lib/classes/Seminar.class.php
+++ b/lib/classes/Seminar.class.php
@@ -303,7 +303,7 @@ class Seminar
{
// Caching
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache_key = 'course/undecorated_data/'. $this->id;
if ($filter) {
@@ -745,7 +745,7 @@ class Seminar
StudipLog::log("SEM_ADD_SINGLEDATE", $this->getId(), $singledate->toString(), 'SingleDateID: '.$singledate->getTerminID());
// logging <<<<<<
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->expire('course/undecorated_data/'. $this->getId());
$this->readSingleDates();
diff --git a/lib/classes/SimpleORMap.class.php b/lib/classes/SimpleORMap.class.php
index 2606086..499149c 100644
--- a/lib/classes/SimpleORMap.class.php
+++ b/lib/classes/SimpleORMap.class.php
@@ -277,7 +277,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate
$relation = $a_config[0] ?? '';
$relation_field = $a_config[1] ?? '';
if (!$relation) {
- list($relation, $relation_field) = explode('_', $a_field);
+ [$relation, $relation_field] = explode('_', $a_field);
}
if (!$relation_field || !$relation) {
throw new UnexpectedValueException('no relation found for autoget/set additional field: ' . $a_field);
@@ -415,7 +415,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate
public static function tableScheme($db_table)
{
if (self::$schemes === null) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
self::$schemes = unserialize($cache->read('DB_TABLE_SCHEMES'));
}
if (!isset(self::$schemes[$db_table])) {
@@ -434,7 +434,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate
}
self::$schemes[$db_table]['db_fields'] = $db_fields;
self::$schemes[$db_table]['pk'] = $pk;
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->write('DB_TABLE_SCHEMES', serialize(self::$schemes));
}
return isset(self::$schemes[$db_table]);
@@ -446,7 +446,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate
*/
public static function expireTableScheme()
{
- StudipCacheFactory::getCache()->expire('DB_TABLE_SCHEMES');
+ \Studip\Cache\Factory::getCache()->expire('DB_TABLE_SCHEMES');
self::$schemes = null;
self::$config = [];
}
@@ -993,7 +993,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate
*/
protected function _getAdditionalValueFromRelation($field)
{
- list($relation, $relation_field) = [$this->additional_fields()[$field]['relation'],
+ [$relation, $relation_field] = [$this->additional_fields()[$field]['relation'],
$this->additional_fields()[$field]['relation_field']];
if (!array_key_exists($field, $this->additional_data)) {
$this->_setAdditionalValue($field, $this->getRelationValue($relation, $relation_field));
@@ -1010,7 +1010,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate
*/
protected function _setAdditionalValueFromRelation($field, $value)
{
- list($relation, $relation_field) = [$this->additional_fields()[$field]['relation'],
+ [$relation, $relation_field] = [$this->additional_fields()[$field]['relation'],
$this->additional_fields()[$field]['relation_field']];
$this->$relation->$field = $value;
unset($this->additional_data[$field]);
diff --git a/lib/classes/Siteinfo.php b/lib/classes/Siteinfo.php
index ba7386b..247b836 100644
--- a/lib/classes/Siteinfo.php
+++ b/lib/classes/Siteinfo.php
@@ -419,7 +419,7 @@ class SiteinfoMarkupEngine {
}
function coregroup() {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
if (!($remotefile = $cache->read('coregroup'))) {
$remotefile = file_get_contents('https://develop.studip.de/studip/extern.php?module=Persons&config_id=8d1dafc3afca2bce6125d57d4119b631&range_id=4498a5bc62d7974d0a0ac3e97aca5296', false, get_default_http_stream_context('https://develop.studip.de'));
$cache->write('coregroup', $remotefile);
@@ -428,7 +428,7 @@ class SiteinfoMarkupEngine {
}
function toplist($item) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
if ($found_in_cache = $cache->read(__METHOD__ . $item)) {
return $found_in_cache;
}
@@ -531,7 +531,7 @@ class SiteinfoMarkupEngine {
}
function indicator($key) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
if ($found_in_cache = $cache->read(__METHOD__ . $key)) {
return $found_in_cache;
}
diff --git a/lib/classes/StudipCache.class.php b/lib/classes/StudipCache.class.php
deleted file mode 100644
index ba929f9..0000000
--- a/lib/classes/StudipCache.class.php
+++ /dev/null
@@ -1,94 +0,0 @@
-<?php
-/**
- * An interface which has to be implemented by instances returned from
- * StudipCacheFactory#getCache
- *
- * @package studip
- * @subpackage lib
- *
- * @author Marco Diedrich (mdiedric@uos)
- * @author Marcus Lunzenauer (mlunzena@uos.de)
- * @copyright (c) Authors
- * @since 1.6
- * @license GPL2 or any later version
- */
-
-interface StudipCache
-{
- const DEFAULT_EXPIRATION = 12 * 60 * 60; // 12 hours
-
- /**
- * Expire item from the cache.
- *
- * Example:
- *
- * # expires foo
- * $cache->expire('foo');
- *
- * @param string $arg a single key
- */
- public function expire($arg);
-
- /**1
- * Expire all items from the cache.
- */
- public function flush();
-
- /**
- * Retrieve item from the server.
- *
- * Example:
- *
- * # reads foo
- * $foo = $cache->reads('foo');
- *
- * @param string $arg a single key
- *
- * @return mixed the previously stored data if an item with such a key
- * exists on the server or FALSE on failure.
- */
- public function read($arg);
-
- /**
- * Store data at the server.
- *
- * @param string $name the item's key.
- * @param mixed $content the item's content (will be serialized if necessary).
- * @param int $expires the item's expiry time in seconds. Optional, defaults to 12h.
- *
- * @return bool returns TRUE on success or FALSE on failure.
- */
- public function write($name, $content, $expires = self::DEFAULT_EXPIRATION);
-
- /**
- * @return string A translateable display name for this cache class.
- */
- public static function getDisplayName(): string;
-
- /**
- * Get some statistics from cache, like number of entries, hit rate or
- * whatever the underlying cache provides.
- * Results are returned in form of an array like
- * "[
- * [
- * 'name' => <displayable name>
- * 'value' => <value of the current stat>
- * ]
- * ]"
- *
- * @return array
- */
- public function getStats(): array;
-
- /**
- * Return the Vue component name and props that handle configuration.
- * The associative array is of the form
- * [
- * 'component' => <Vue component name>,
- * 'props' => <Properties for component>
- * ]
- *
- * @return array
- */
- public static function getConfig(): array;
-}
diff --git a/lib/classes/StudipCachedArray.php b/lib/classes/StudipCachedArray.php
index 1232d00..46723f4 100644
--- a/lib/classes/StudipCachedArray.php
+++ b/lib/classes/StudipCachedArray.php
@@ -27,10 +27,10 @@ class StudipCachedArray implements ArrayAccess
* @param int $duration Duration in seconds for which the item shall be
* stored
*/
- public function __construct(string $key, int $duration = StudipCache::DEFAULT_EXPIRATION)
+ public function __construct(string $key, int $duration = \Studip\Cache\Cache::DEFAULT_EXPIRATION)
{
$this->key = self::class . "/{$key}";
- $this->cache = StudipCacheFactory::getCache();
+ $this->cache = \Studip\Cache\Factory::getCache();
$this->duration = $duration;
$this->hash = $this->getHash();
@@ -116,11 +116,14 @@ class StudipCachedArray implements ArrayAccess
protected function loadData(string $offset)
{
if (!array_key_exists($offset, $this->data)) {
- $cached = $this->cache->read($this->getCacheKey($offset));
- $this->data[$offset] = $this->swapNullAndFalse($cached);
+ // Get the cache item from the cache:
+ $item = $this->cache->getItem($this->getCacheKey($offset));
+ if ($item->isHit()) {
+ $this->data[$offset] = $this->swapNullAndFalse($item->get());
+ }
}
- return $this->data[$offset];
+ return $this->data[$offset] ?? null;
}
/**
@@ -132,13 +135,12 @@ class StudipCachedArray implements ArrayAccess
*/
protected function storeData(string $offset): void
{
- $data = $this->swapNullAndFalse($this->data[$offset]);
-
- $this->cache->write(
+ $item = new \Studip\Cache\Item(
$this->getCacheKey($offset),
- $data,
+ $this->swapNullAndFalse($this->data[$offset]),
$this->duration
);
+ $this->cache->save($item);
}
/**
diff --git a/lib/classes/StudipDbCache.class.php b/lib/classes/StudipDbCache.class.php
deleted file mode 100644
index 865825e..0000000
--- a/lib/classes/StudipDbCache.class.php
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-/**
- * StudipCache implementation using database table
- *
- * @package studip
- * @subpackage cache
- *
- * @author Elmar Ludwig <elmar.ludwig@uos.de>
- */
-class StudipDbCache implements StudipCache
-{
-
- /**
- * @return string A translateable display name for this cache class.
- */
- public static function getDisplayName(): string
- {
- return _('Datenbank');
- }
-
- /**
- * Expire item from the cache.
- *
- * @param string $arg a single key
- */
- public function expire($arg)
- {
- $db = DBManager::get();
-
- $stmt = $db->prepare('DELETE FROM cache WHERE cache_key = ?');
- $stmt->execute([$arg]);
- }
-
- /**
- * Expire all items from the cache.
- */
- public function flush()
- {
- $db = DBManager::get();
-
- $db->exec('TRUNCATE TABLE cache');
- }
-
- /**
- * Delete all expired items from the cache.
- */
- public function purge()
- {
- $db = DBManager::get();
-
- $stmt = $db->prepare('DELETE FROM cache WHERE expires < ?');
- $stmt->execute([time()]);
- }
-
- /**
- * Retrieve item from the server.
- *
- * @param string $arg a single key
- *
- * @return mixed the previously stored data if an item with such a key
- * exists on the server or FALSE on failure.
- */
- public function read($arg)
- {
- $db = DBManager::get();
-
- $stmt = $db->prepare('SELECT content FROM cache WHERE cache_key = ? AND expires > ?');
- $stmt->execute([$arg, time()]);
- $result = $stmt->fetchColumn();
-
- return $result !== false ? unserialize($result) : false;
- }
-
- /**
- * Store data at the server.
- *
- * @param string $name the item's key.
- * @param mixed $content the item's content (will be serialized if necessary).
- * @param int $expired the item's expiry time in seconds. Optional, defaults to 12h.
- *
- * @return bool returns TRUE on success or FALSE on failure.
- */
- public function write($name, $content, $expires = self::DEFAULT_EXPIRATION)
- {
- $db = DBManager::get();
-
- $stmt = $db->prepare('REPLACE INTO cache VALUES(?, ?, ?)');
- return $stmt->execute([$name, serialize($content), time() + $expires]);
- }
-
- /**
- * Return statistics.
- *
- * @see StudipCache::getStats()
- *
- * @return array|array[]
- */
- public function getStats(): array
- {
- return [
- __CLASS__ => [
- 'name' => _('Anzahl Einträge'),
- 'value' => DBManager::get()->fetchColumn("SELECT COUNT(*) FROM `cache`")
- ]
- ];
- }
-
- /**
- * Return the Vue component name and props that handle configuration.
- *
- * @see StudipCache::getConfig()
- *
- * @return array
- */
- public static function getConfig(): array
- {
- return [
- 'component' => null,
- 'props' => []
- ];
- }
-
-}
diff --git a/lib/classes/StudipKing.class.php b/lib/classes/StudipKing.class.php
index 2d1f15c..3a61c57 100644
--- a/lib/classes/StudipKing.class.php
+++ b/lib/classes/StudipKing.class.php
@@ -63,7 +63,7 @@ class StudipKing {
private static function get_kings()
{
if (self::$kings === null) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
# read cache (unserializing a cache miss - FALSE - does not matter)
$kings = unserialize($cache->read(self::CACHE_KEY));
diff --git a/lib/classes/StudipMemoryCache.class.php b/lib/classes/StudipMemoryCache.class.php
deleted file mode 100644
index d38385a..0000000
--- a/lib/classes/StudipMemoryCache.class.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * The php memory implementation of the StudipCache interface.
- *
- * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
- * @license GPL2 or any later version
- * @since Stud.IP 5.0
- */
-class StudipMemoryCache implements StudipCache
-{
- protected $memory_cache = [];
-
- /**
- * Expires just a single key.
- *
- * @param string the key
- */
- public function expire($key)
- {
- unset($this->memory_cache[$key]);
- }
-
- /**
- * Expire all items from the cache.
- */
- public function flush()
- {
- $this->memory_cache = [];
- }
-
- /**
- * Reads just a single key from the cache.
- *
- * @param string the key
- *
- * @return mixed the corresponding value
- */
- public function read($key)
- {
- if (!isset($this->memory_cache[$key])) {
- return false;
- }
- if ($this->memory_cache[$key]['expires'] < time()) {
- $this->expire($key);
- return false;
- }
- return $this->memory_cache[$key]['data'];
- }
-
- /**
- * Store data at the server.
- *
- * @param string the item's key.
- * @param mixed the item's content (will be serialized if necessary).
- * @param int the item's expiry time in seconds. Defaults to 12h.
- *
- * @returns mixed returns TRUE on success or FALSE on failure.
- *
- */
- public function write($name, $content, $expires = self::DEFAULT_EXPIRATION)
- {
- $this->memory_cache[$name] = [
- 'expires' => time() + $expires,
- 'data' => $content,
- ];
-
- return true;
- }
-
- public static function getDisplayName(): string
- {
- return 'Memory cache';
- }
-
- public function getStats(): array
- {
- return [];
- }
-
- public static function getConfig(): array
- {
- return [];
- }
-}
diff --git a/lib/classes/UserLookup.class.php b/lib/classes/UserLookup.class.php
index ddf9276..bdd9fc3 100644
--- a/lib/classes/UserLookup.class.php
+++ b/lib/classes/UserLookup.class.php
@@ -239,7 +239,7 @@ class UserLookup
return call_user_func(self::$types[$type]['values']);
}
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache_key = "UserLookup/{$type}/values";
$cached_values = $cache->read($cache_key);
if ($cached_values) {
diff --git a/lib/classes/assets/SASSCompiler.php b/lib/classes/assets/SASSCompiler.php
index 2dcda2d..0b03a8c 100644
--- a/lib/classes/assets/SASSCompiler.php
+++ b/lib/classes/assets/SASSCompiler.php
@@ -2,7 +2,7 @@
namespace Assets;
use Assets;
-use StudipCacheFactory;
+use Studip\Cache\Factory;
use Studip;
use ScssPhp\ScssPhp\Compiler as ScssCompiler;
@@ -82,7 +82,7 @@ class SASSCompiler implements Compiler
*/
private function getPrefix()
{
- $cache = StudipCacheFactory::getCache();
+ $cache = Studip\Cache\Factory::getCache();
$prefix = $cache->read(self::CACHE_KEY);
diff --git a/lib/classes/cache/Cache.class.php b/lib/classes/cache/Cache.class.php
new file mode 100644
index 0000000..366945d
--- /dev/null
+++ b/lib/classes/cache/Cache.class.php
@@ -0,0 +1,208 @@
+<?php
+
+namespace Studip\Cache;
+
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\CacheItemPoolInterface;
+
+/**
+ * An abstract class which has to be extended by instances returned from
+ * \Studip\Cache\Factory#getCache
+ *
+ * @author Marco Diedrich (mdiedric@uos)
+ * @author Marcus Lunzenauer (mlunzena@uos.de)
+ * @author Moritz Strohm <strohm@data-quest.de>
+ * @copyright (c) Authors
+ * @since 1.6
+ * @license GPL2 or any later version
+ */
+abstract class Cache implements CacheItemPoolInterface
+{
+ const DEFAULT_EXPIRATION = 12 * 60 * 60; // 12 hours
+
+ /**
+ * @return string A translateable display name for this cache class.
+ */
+ abstract public static function getDisplayName(): string;
+
+ /**
+ * Get some statistics from cache, like number of entries, hit rate or
+ * whatever the underlying cache provides.
+ * Results are returned in form of an array like
+ * "[
+ * [
+ * 'name' => <displayable name>
+ * 'value' => <value of the current stat>
+ * ]
+ * ]"
+ *
+ * @return array
+ */
+ abstract public function getStats(): array;
+
+ /**
+ * Return the Vue component name and props that handle configuration.
+ * The associative array is of the form
+ * [
+ * 'component' => <Vue component name>,
+ * 'props' => <Properties for component>
+ * ]
+ *
+ * @return array
+ */
+ abstract public static function getConfig(): array;
+
+ /**
+ * Expire item from the cache.
+ *
+ * Example:
+ *
+ * # expires foo
+ * $cache->expire('foo');
+ *
+ * @param string $arg a single key
+ */
+ abstract public function expire($arg);
+
+ /**
+ * Expire all items from the cache.
+ */
+ abstract public function flush();
+
+ /**
+ * @see CacheItemPoolInterface::getItem
+ */
+ abstract public function getItem($key);
+
+ /**
+ * @see CacheItemPoolInterface::hasItem
+ */
+ abstract public function hasItem($key);
+
+ /**
+ * @var array An array of deferred items that shall be saved only
+ * when commit() is called. This is only used in PSR-6 cache methods.
+ */
+ protected array $deferred_items = [];
+
+ /**
+ * Retrieve item from the server.
+ *
+ * Example:
+ *
+ * # reads foo
+ * $foo = $cache->reads('foo');
+ *
+ * @param string $arg a single key
+ *
+ * @return mixed the previously stored data if an item with such a key
+ * exists on the server or FALSE on failure.
+ *
+ * @deprecated To be removed with Stud.IP 7.0.
+ */
+ public function read($arg)
+ {
+ $item = $this->getItem($arg);
+ if ($item->isHit()) {
+ return $item->get();
+ }
+ return false;
+ }
+
+ /**
+ * Store data at the server.
+ *
+ * @param string $name the item's key.
+ * @param mixed $content the item's content (will be serialized if necessary).
+ * @param int $expires the item's expiry time in seconds. Optional, defaults to 12h.
+ *
+ * @return bool returns TRUE on success or FALSE on failure.
+
+ * @deprecated To be removed with Stud.IP 7.0.
+ */
+ public function write($name, $content, $expires = self::DEFAULT_EXPIRATION)
+ {
+ $item = new Item($name, $content, $expires);
+
+ return $this->save($item);
+ }
+
+ /**
+ * Calculates the expiration by a cache item. If that cannot be determined,
+ * the default expiration period is returned.
+ *
+ * @param Item $item The item from which to get the expiration time.
+ *
+ * @return int The time from now until the expiration in seconds.
+ */
+ public function getExpiration(CacheItemInterface $item) : int
+ {
+ $expiration = self::DEFAULT_EXPIRATION;
+ if ($item instanceof Item) {
+ $expiration = $item->getExpirationInSeconds();
+ }
+ return $expiration;
+ }
+
+ // PSR-6 CacheItemPoolInterface:
+
+ /**
+ * @see CacheItemPoolInterface::getItems
+ */
+ public function getItems(array $keys = [])
+ {
+ $items = [];
+ foreach ($keys as $key) {
+ $item = $this->getItem($key);
+ if ($item instanceof Item) {
+ $items[] = $item;
+ }
+ }
+ return $items;
+ }
+
+ /**
+ * @see CacheItemPoolInterface::clear
+ */
+ public function clear()
+ {
+ $this->deferred_items = [];
+ $this->flush();
+ }
+
+ /**
+ * @see CacheItemPoolInterface::deleteItem
+ */
+ public function deleteItem($key)
+ {
+ $this->expire($key);
+ }
+
+ /**
+ * @see CacheItemPoolInterface::deleteItems
+ */
+ public function deleteItems(array $keys)
+ {
+ foreach ($keys as $key) {
+ $this->expire($key);
+ }
+ }
+
+ /**
+ * @see CacheItemPoolInterface::saveDeferred
+ */
+ public function saveDeferred(CacheItemInterface $item)
+ {
+ $this->deferred_items[] = $item;
+ }
+
+ /**
+ * @see CacheItemPoolInterface::commit
+ */
+ public function commit()
+ {
+ foreach ($this->deferred_items as $item) {
+ $this->save($item);
+ }
+ }
+}
diff --git a/lib/classes/cache/DbCache.class.php b/lib/classes/cache/DbCache.class.php
new file mode 100644
index 0000000..3361af0
--- /dev/null
+++ b/lib/classes/cache/DbCache.class.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace Studip\Cache;
+
+use DBManager;
+
+/**
+ * StudipCache implementation using database table
+ *
+ * @author Elmar Ludwig <elmar.ludwig@uos.de>
+ */
+class DbCache extends Cache
+{
+ /**
+ * @return string A display name (that can be translated) for this cache class.
+ */
+ public static function getDisplayName(): string
+ {
+ return _('Datenbank');
+ }
+
+ /**
+ * Expire item from the cache.
+ *
+ * @param string $arg a single key
+ */
+ public function expire($arg)
+ {
+ $db = DBManager::get();
+
+ $stmt = $db->prepare('DELETE FROM cache WHERE cache_key = ?');
+ $stmt->execute([$arg]);
+ }
+
+ /**
+ * Expire all items from the cache.
+ */
+ public function flush()
+ {
+ $db = DBManager::get();
+
+ $db->exec('TRUNCATE TABLE cache');
+ }
+
+ /**
+ * Delete all expired items from the cache.
+ */
+ public function purge()
+ {
+ $db = DBManager::get();
+
+ $stmt = $db->prepare('DELETE FROM cache WHERE expires < ?');
+ $stmt->execute([time()]);
+ }
+
+ /**
+ * Return statistics.
+ *
+ * @return array|array[]
+ *@see Cache::getStats()
+ *
+ */
+ public function getStats(): array
+ {
+ return [
+ __CLASS__ => [
+ 'name' => _('Anzahl Einträge'),
+ 'value' => DBManager::get()->fetchColumn("SELECT COUNT(*) FROM `cache`")
+ ]
+ ];
+ }
+
+ /**
+ * Return the Vue component name and props that handle configuration.
+ *
+ * @return array
+ *@see Cache::getConfig()
+ *
+ */
+ public static function getConfig(): array
+ {
+ return [
+ 'component' => null,
+ 'props' => []
+ ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getItem($key)
+ {
+ $query = "SELECT `content`, `expires`
+ FROM `cache`
+ WHERE `cache_key` = :key
+ AND `expires` > UNIX_TIMESTAMP()";
+ $result = DBManager::get()->fetchOne($query, [':key' => $key]);
+
+ $item = new Item($key);
+ if (!empty($result)) {
+ $item->setHit();
+ if ($result['content']) {
+ $item->set(unserialize($result['content']));
+ }
+ if ($result['expires']) {
+ $expiration = new \DateTime();
+ $expiration->setTimestamp($result['expires']);
+ $item->expiresAt($expiration);
+ }
+ }
+ return $item;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function hasItem($key)
+ {
+ $query = "SELECT 1
+ FROM `cache`
+ WHERE `cache_key` = :key
+ AND `expires` > UNIX_TIMESTAMP()";
+ return (bool) DBManager::get()->fetchColumn($query, [':key' => $key]);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function save(\Psr\Cache\CacheItemInterface $item)
+ {
+ $expiration = $this->getExpiration($item);
+ if ($expiration < 1) {
+ // The item would expire immediately.
+ return false;
+ }
+
+ return DBManager::get()->execute(
+ 'REPLACE INTO `cache` VALUES (?, ?, ?)',
+ [$item->getKey(), serialize($item->get()), $expiration]
+ );
+ }
+}
diff --git a/lib/classes/cache/Exception.php b/lib/classes/cache/Exception.php
new file mode 100644
index 0000000..64ee364
--- /dev/null
+++ b/lib/classes/cache/Exception.php
@@ -0,0 +1,27 @@
+<?php
+/*
+ * CacheException.class.php
+ * This file is part of Stud.IP.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * @author Moritz Strohm <strohm@data-quest.de>
+ * @copyright 2024
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ * @since 6.0
+ */
+
+namespace Studip\Cache;
+
+/**
+ * The CacheException class is an implementation of the CacheException interface
+ * of PSR-6 that behaves like a StudipException.
+ */
+class Exception extends \StudipException implements \Psr\Cache\CacheException
+{
+ //Nothing here, since there is nothing to implement.
+}
diff --git a/lib/classes/StudipCacheFactory.class.php b/lib/classes/cache/Factory.class.php
index 77c5973..b5c8359 100644
--- a/lib/classes/StudipCacheFactory.class.php
+++ b/lib/classes/cache/Factory.class.php
@@ -1,4 +1,15 @@
<?php
+
+namespace Studip\Cache;
+
+use Config;
+use DBSchemaVersion;
+use MessageBox;
+use PageLayout;
+use ReflectionClass;
+use StudipCacheOperation;
+use UnexpectedValueException;
+
/**
* This factory retrieves the instance of StudipCache configured for use in
* this Stud.IP installation.
@@ -12,30 +23,29 @@
* @since 1.6
* @license GPL2 or any later version
*/
-
-class StudipCacheFactory
+class Factory
{
/**
* the default cache class
*
* @var string
*/
- const DEFAULT_CACHE_CLASS = StudipDbCache::class;
+ const DEFAULT_CACHE_CLASS = DbCache::class;
/**
* singleton instance
*
- * @var StudipCache
+ * @var Cache|null
*/
- private static $cache;
+ private static ?Cache $cache = null;
/**
* config instance
*
- * @var Config
+ * @var Config|null
*/
- private static $config = null;
+ private static ?Config $config = null;
/**
@@ -49,7 +59,7 @@ class StudipCacheFactory
*/
public static function getConfig()
{
- return is_null(self::$config) ? Config::getInstance() : self::$config;
+ return self::$config ?? Config::getInstance();
}
@@ -58,7 +68,7 @@ class StudipCacheFactory
* determine the class of the implementation of interface
* StudipCache
*/
- public static function setConfig($config)
+ public static function setConfig(Config $config)
{
self::$config = $config;
self::$cache = NULL;
@@ -77,15 +87,15 @@ class StudipCacheFactory
*
* @param bool $apply_proxied_operations Whether or not to apply any
* proxied (disable this in tests!)
- * @return StudipCache the cache instance
+ * @return Cache the cache instance
*/
- public static function getCache($apply_proxied_operations = true)
+ public static function getCache(bool $apply_proxied_operations = true): Cache
{
- if (is_null(self::$cache)) {
+ if (self::$cache === null) {
$proxied = false;
if (!$GLOBALS['CACHING_ENABLE']) {
- self::$cache = new StudipMemoryCache();
+ self::$cache = new MemoryCache();
// Proxy cache operations if CACHING_ENABLE is different from the globally set
// caching value. This should only be the case in cli mode.
@@ -98,7 +108,7 @@ class StudipCacheFactory
$args = self::retrieveConstructorArguments();
self::$cache = self::instantiateCache($class, $args);
- } catch (Exception $e) {
+ } catch (\Exception $e) {
error_log(__METHOD__ . ': ' . $e->getMessage());
PageLayout::addBodyElements(MessageBox::error(__METHOD__ . ': ' . $e->getMessage()));
$class = self::DEFAULT_CACHE_CLASS;
@@ -109,7 +119,7 @@ class StudipCacheFactory
// If proxy should be used, inject it. Otherwise apply pending
// operations, if any.
if ($proxied) {
- self::$cache = new StudipCacheProxy(self::$cache);
+ self::$cache = new Proxy(self::$cache);
} elseif ($GLOBALS['CACHING_ENABLE'] && $apply_proxied_operations) {
// Even if the above condition will try to eliminate most
// failures, the following operation still needs to be wrapped
@@ -118,7 +128,7 @@ class StudipCacheFactory
// for said operation.
try {
StudipCacheOperation::apply(self::$cache);
- } catch (Exception $e) {
+ } catch (\Exception $e) {
}
}
}
@@ -174,10 +184,11 @@ class StudipCacheFactory
* memory cache is instantiated, the cache will be wrapped in a wrapper
* class that uses a memory cache to reduce accesses to the cache.
*
- * @param string $class the name of the class
- * @param array $arguments an array of arguments to be used by the constructor
+ * @param string $class the name of the class
+ * @param array $arguments an array of arguments to be used by the constructor
*
- * @return StudipCache an instance of the specified class
+ * @return Cache an instance of the specified class
+ * @throws \ReflectionException
*/
public static function instantiateCache($class, $arguments)
{
@@ -186,8 +197,8 @@ class StudipCacheFactory
? $reflection_class->newInstanceArgs($arguments['config'])
: $reflection_class->newInstance();
- if ($class !== StudipMemoryCache::class) {
- return new StudipCacheWrapper($cache);
+ if ($class !== MemoryCache::class) {
+ return new Wrapper($cache);
}
return $cache;
diff --git a/lib/classes/StudipFileCache.class.php b/lib/classes/cache/FileCache.class.php
index 9eae66c..e94395a 100644
--- a/lib/classes/StudipFileCache.class.php
+++ b/lib/classes/cache/FileCache.class.php
@@ -1,46 +1,27 @@
<?php
-# Lifter010: TODO
-// +--------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipFileCache.class.php
-//
-//
-//
-// Copyright (c) 2007 André Noack <noack@data-quest.de>
-// +--------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +--------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// +--------------------------------------------------------------------------+
+
+namespace Studip\Cache;
+
+use Config;
+use Exception;
/**
- * StudipCache implementation using files
- *
- * @package studip
- * @subpackage cache
+ * Cache implementation using files
*
* @author André Noack <noack@data-quest.de>
- * @version 2
+ * @copyright 2007 André Noack <noack@data-quest.de>
+ * @license GPL2 or any later version
*/
-class StudipFileCache implements StudipCache
+class FileCache extends Cache
{
- use StudipCacheKeyTrait;
+ use KeyTrait;
/**
* full path to cache directory
*
* @var string
*/
- private $dir;
+ private string $dir;
/**
* @return string A translateable display name for this cache class.
@@ -55,26 +36,28 @@ class StudipFileCache implements StudipCache
* $CACHING_FILECACHE_PATH or is set to
* $TMP_PATH/studip_cache
*
- * @param string the path to use
- * @return void
- * @throws exception if the directory does not exist or could not be
+ * @param string $path the path to use
+ * @throws Exception if the directory does not exist or could not be
* created
*/
- public function __construct($path = '')
+ public function __construct(string $path = '')
{
$this->dir = $path
- ?: (Config::get()->SYSTEMCACHE['type'] == 'StudipFileCache' ?
- Config::get()->SYSTEMCACHE['config']['path'] : '')
+ ?: (
+ Config::get()->SYSTEMCACHE['type'] === self::class
+ ? Config::get()->SYSTEMCACHE['config']['path']
+ : ''
+ )
?: $GLOBALS['CACHING_FILECACHE_PATH']
?: ($GLOBALS['TMP_PATH'] . '/' . 'studip_cache');
$this->dir = rtrim($this->dir, '\\/') . '/';
if (!is_dir($this->dir) && !@mkdir($this->dir, 0700)) {
- throw new Exception('Could not create directory: ' . $this->dir);
+ throw new \Exception('Could not create directory: ' . $this->dir);
}
if (!is_writable($this->dir)) {
- throw new Exception('Can not write to directory: ' . $this->dir);
+ throw new \Exception('Can not write to directory: ' . $this->dir);
}
}
@@ -91,9 +74,11 @@ class StudipFileCache implements StudipCache
/**
* expire cache item
*
- * @see StudipCache::expire()
* @param string $arg
+ *
* @return void
+ * @throws Exception
+ * @see Cache::expire()
*/
public function expire($arg)
{
@@ -113,61 +98,20 @@ class StudipFileCache implements StudipCache
}
/**
- * retrieve cache item from filesystem
- * tests first if item is expired
- *
- * @see StudipCache::read()
- * @param string $arg a cache key
- * @return string|bool
- */
- public function read($arg)
- {
- $key = $this->getCacheKey($arg);
-
- if ($file = $this->check($key)){
- $f = @fopen($file, 'rb');
- if ($f) {
- @flock($f, LOCK_SH);
- $result = stream_get_contents($f);
- @fclose($f);
- }
- return unserialize($result);
- }
- return false;
- }
-
- /**
- * store data as cache item in filesystem
- *
- * @see StudipCache::write()
- * @param string $arg a cache key
- * @param mixed $content data to store
- * @param int $expire expiry time in seconds, default 12h
- * @return int|bool the number of bytes that were written to the file,
- * or false on failure
- */
- public function write($arg, $content, $expire = self::DEFAULT_EXPIRATION)
- {
- $key = $this->getCacheKey($arg);
-
- $this->expire($key);
- $file = $this->getPathAndFile($key, $expire);
- return @file_put_contents($file, serialize($content), LOCK_EX);
- }
-
- /**
* checks if specified cache item is expired
* if expired the cache file is deleted
*
* @param string $key a cache key to check
- * @return string|bool the path to the cache file or false if expired
+ *
+ * @return array|bool the path to the cache file or false if expired
+ * @throws Exception
*/
private function check($key)
{
if ($file = $this->getPathAndFile($key)){
- list($id, $expire) = explode('-', basename($file));
+ [$id, $expire] = explode('-', basename($file));
if (time() < $expire) {
- return $file;
+ return [$file, $expire];
} else {
@unlink($file);
}
@@ -183,16 +127,18 @@ class StudipFileCache implements StudipCache
* the filename is constructed from the hashed cache key
* and the timestamp of expiration
*
- * @param string $key a cache key
- * @param int $expire expiry time in seconds
+ * @param string $key a cache key
+ * @param int|null $expire expiry time in seconds
+ *
* @return string|bool full path to cache item or false on failure
+ * @throws Exception
*/
- private function getPathAndFile($key, $expire = null)
+ private function getPathAndFile(string $key, ?int $expire = null): bool|string
{
$id = hash('md5', $key);
$path = $this->dir . mb_substr($id, 0, 2);
if (!is_dir($path) && !@mkdir($path, 0700)) {
- throw new Exception('Could not create directory: ' . $path);
+ throw new \Exception('Could not create directory: ' . $path);
}
if (!is_null($expire)){
return $path . '/' . $id . '-' . (time() + $expire);
@@ -208,16 +154,17 @@ class StudipFileCache implements StudipCache
/**
* purges expired entries from the cache directory
*
- * @param bool echo messages if set to false
+ * @param bool $be_quiet echo messages if set to false
+ *
* @return int the number of deleted files
*/
- public function purge($be_quiet = true)
+ public function purge(bool $be_quiet = true): int
{
$now = time();
$deleted = 0;
foreach (@glob($this->dir . '*', GLOB_ONLYDIR) as $current_dir){
foreach (@glob("{$current_dir}/*") as $file){
- list($id, $expire) = explode('-', basename($file));
+ [$id, $expire] = explode('-', basename($file));
if ($expire < $now) {
if (@unlink($file)) {
++$deleted;
@@ -225,8 +172,8 @@ class StudipFileCache implements StudipCache
echo "File: {$file} deleted.\n";
}
}
- } else if (!$be_quiet){
- echo "File: {$file} expires on " . strftime('%x %X', $expire) . "\n";
+ } else if (!$be_quiet) {
+ echo "File: {$file} expires on " . date('Y-m-d H:i:s', $expire) . "\n";
}
}
}
@@ -243,7 +190,7 @@ class StudipFileCache implements StudipCache
return [
__CLASS__ => [
'name' => _('Anzahl Einträge'),
- 'value' => DBManager::get()->fetchColumn("SELECT COUNT(*) FROM `cache`")
+ 'value' => \DBManager::get()->fetchColumn("SELECT COUNT(*) FROM `cache`")
]
];
}
@@ -273,4 +220,58 @@ class StudipFileCache implements StudipCache
];
}
+ /**
+ * @inheritDoc
+ */
+ public function getItem($key)
+ {
+ $real_key = $this->getCacheKey($key);
+
+ $item = new \Studip\Cache\Item($key);
+
+ $file_data = $this->check($real_key);
+ if ($file_data) {
+ $file = $file_data[0];
+ $expire = $file_data[1];
+ $f = @fopen($file, 'rb');
+ if ($f) {
+ @flock($f, LOCK_SH);
+ $result = stream_get_contents($f);
+ @fclose($f);
+ }
+ $item->setHit();
+ $item->set(unserialize($result));
+ $expiration = new \DateTime();
+ $expiration->setTimestamp($expire);
+ $item->expiresAt($expiration);
+ }
+ return $item;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function hasItem($key)
+ {
+ $real_key = $this->getCacheKey($key);
+ $file_data = $this->check($real_key);
+ return $file_data !== false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function save(\Psr\Cache\CacheItemInterface $item)
+ {
+ $expiration = $this->getExpiration($item);
+ if ($expiration < 1) {
+ //The item would expire immediately.
+ return false;
+ }
+
+ $real_key = $this->getCacheKey($item->getKey());
+ $this->expire($real_key);
+ $file = $this->getPathAndFile($real_key, $expiration);
+ return @file_put_contents($file, serialize($item->get()), LOCK_EX);
+ }
}
diff --git a/lib/classes/cache/InvalidCacheArgumentException.php b/lib/classes/cache/InvalidCacheArgumentException.php
new file mode 100644
index 0000000..e85c6b2
--- /dev/null
+++ b/lib/classes/cache/InvalidCacheArgumentException.php
@@ -0,0 +1,28 @@
+<?php
+/*
+ * CacheException.class.php
+ * This file is part of Stud.IP.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * @author Moritz Strohm <strohm@data-quest.de>
+ * @copyright 2024
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ * @since 6.0
+ */
+
+namespace Studip\Cache;
+
+
+/**
+ * The InvalidCacheArgumentException is an implementation of the InvalidArgumentException interface
+ * of PSR-6 that behaves like a StudipException.
+ */
+class InvalidCacheArgumentException extends \StudipException implements \Psr\Cache\InvalidArgumentException
+{
+ //Nothing here, since there is nothing to implement.
+}
diff --git a/lib/classes/cache/Item.class.php b/lib/classes/cache/Item.class.php
new file mode 100644
index 0000000..1a09f1d
--- /dev/null
+++ b/lib/classes/cache/Item.class.php
@@ -0,0 +1,163 @@
+<?php
+/**
+ * Item.class.php
+ * This file is part of Stud.IP.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * @author Moritz Strohm <strohm@data-quest.de>
+ * @copyright 2024
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ * @since 6.0
+ */
+
+namespace Studip\Cache;
+
+use DateInterval;
+use DateTime;
+use Psr\Cache\CacheItemInterface;
+
+/**
+ * \Studip\Cache\CacheItem implements the CacheItemInterface of PSR-6. It holds the value and the
+ * key of a cache item and also provides additional methods to get the expiration of the item.
+ */
+class Item implements CacheItemInterface
+{
+ /**
+ * @var string The key of the item in the cache.
+ */
+ protected string $key;
+
+ /**
+ * @var mixed The value of the item.
+ */
+ protected mixed $value;
+
+ /**
+ * @var DateTime|null The expiration as DateTime object or null if the expiration is not defined.
+ */
+ protected ?DateTime $expiration = null;
+
+ /**
+ * @var bool An indicator whether the item has been found in the cache (true) or not (false).
+ */
+ protected bool $cache_hit = false;
+
+ /**
+ * The constructor of \Studip\Cache\CacheItem.
+ *
+ * @param string $key The key of the item in the cache.
+ * @param mixed $value The value of the item.
+ * @param int|null $expiration The expiration of the item in seconds, if applicable.
+ * @param bool $cache_hit Whether the item shall be constructed as cache hit (true) or not (false).
+ *
+ */
+ public function __construct(
+ string $key,
+ mixed $value = null,
+ ?int $expiration = null,
+ bool $cache_hit = false
+ ) {
+ $this->key = $key;
+ $this->value = $value;
+ $this->cache_hit = $cache_hit;
+ $this->expiresAfter($expiration);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function get()
+ {
+ return $this->value;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isHit()
+ {
+ return $this->cache_hit;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function set($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function expiresAt($expiration)
+ {
+ $this->expiration = $expiration;
+ return $this;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function expiresAfter($time)
+ {
+ $this->expiration = new DateTime();
+ if ($time instanceof DateInterval) {
+ $this->expiration = $this->expiration->add($time);
+ } elseif (is_integer($time)) {
+ $this->expiration->setTimestamp(time() + $time);
+ } else {
+ $this->expiration->setTimestamp(time() + Cache::DEFAULT_EXPIRATION);
+ }
+ return $this;
+ }
+
+ // \Studip\Cache\CacheItem specific methods:
+
+ /**
+ * Sets the item to be a cache hit.
+ *
+ * @return void
+ */
+ public function setHit() : void
+ {
+ $this->cache_hit = true;
+ }
+
+ /**
+ * Returns the expiration, if set.
+ *
+ * @return DateTime|null A DateTime object with the expiration date and time
+ * or null if the expiration is not defined.
+ */
+ public function getExpiration() : ?DateTime
+ {
+ return $this->expiration;
+ }
+
+ /**
+ * Returns the seconds from the current timestamp until the expiration of the item.
+ *
+ * @return int The seconds until the item expires
+ */
+ public function getExpirationInSeconds() : int
+ {
+ if ($this->expiration) {
+ return $this->expiration->getTimestamp() - time();
+ }
+ return 0;
+ }
+}
diff --git a/lib/classes/StudipCacheKeyTrait.php b/lib/classes/cache/KeyTrait.php
index 62eb142..021aaba 100644
--- a/lib/classes/StudipCacheKeyTrait.php
+++ b/lib/classes/cache/KeyTrait.php
@@ -1,4 +1,6 @@
<?php
+namespace Studip\Cache;
+
/**
* Trait for unique cache hashes per key for each system based on db configuration which should
* be sufficient to eliminate cache mishaps.
@@ -9,9 +11,9 @@
* @subpackage cache
* @since Stud.IP 5.0
*/
-trait StudipCacheKeyTrait
+trait KeyTrait
{
- protected $cache_prefix = null;
+ protected ?string $cache_prefix = null;
/**
* Returns a prefix cache key based on db configuration.
@@ -19,11 +21,11 @@ trait StudipCacheKeyTrait
* @param string $offset
* @return string
*/
- protected function getCacheKey($offset)
+ protected function getCacheKey(string $offset): string
{
if ($this->cache_prefix === null) {
$this->cache_prefix = md5("{$GLOBALS['DB_STUDIP_HOST']}|{$GLOBALS['DB_STUDIP_DATABASE']}");
}
- return "{$this->cache_prefix}/{$offset}";
+ return "$this->cache_prefix/$offset";
}
}
diff --git a/lib/classes/StudipMemcachedCache.php b/lib/classes/cache/MemcachedCache.class.php
index 0e44dd5..5d9033b 100644
--- a/lib/classes/StudipMemcachedCache.php
+++ b/lib/classes/cache/MemcachedCache.class.php
@@ -1,31 +1,23 @@
<?php
-/**
- * Copyright (C) 2007 - Marcus Lunzenauer <mlunzena@uos.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
+namespace Studip\Cache;
+use Memcached;
+use Psr\Cache\CacheItemInterface;
/**
* Cache implementation using memcached.
*
- * @package studip
- * @subpackage cache
- *
- * @author mlunzena
+ * @author Marcus Lunzenauer <mlunzena@uos.de>
* @copyright (c) Authors
+ * @license GPL2 or any later version
* @since 5.0
*/
-
-class StudipMemcachedCache implements StudipCache
+class MemcachedCache extends Cache
{
- use StudipCacheKeyTrait;
+ use KeyTrait;
- private $memcache;
+ private Memcached $memcache;
/**
* @return string A translateable display name for this cache class.
@@ -38,18 +30,18 @@ class StudipMemcachedCache implements StudipCache
public function __construct($servers)
{
if (!extension_loaded('memcached')) {
- throw new Exception('Memcache extension missing.');
+ throw new \Exception('Memcache extension missing.');
}
- $prefix = Config::get()->STUDIP_INSTALLATION_ID;
- $this->memcache = new Memcached('studip' . $prefix ? '-' . $prefix : '');
+ $prefix = \Config::get()->STUDIP_INSTALLATION_ID;
+ $this->memcache = new Memcached('studip' . ($prefix ? '-' . $prefix : ''));
if (count($this->memcache->getServerList()) === 0) {
foreach ($servers as $server) {
$status = $this->memcache->addServer($server['hostname'], (int) $server['port']);
if (!$status) {
- throw new Exception("Could not add server: {$server['hostname']} @ port {$server['port']}");
+ throw new \Exception("Could not add server: {$server['hostname']} @ port {$server['port']}");
}
}
}
@@ -81,40 +73,6 @@ class StudipMemcachedCache implements StudipCache
}
/**
- * Retrieve item from the server.
- *
- * Example:
- *
- * # reads foo
- * $foo = $cache->reads('foo');
- *
- * @param string $arg a single key
- * @returns mixed the previously stored data if an item with such a key
- * exists on the server or FALSE on failure.
- */
- public function read($arg)
- {
- $key = $this->getCacheKey($arg);
- return $this->memcache->get($key);
- }
-
- /**
- * Store data at the server.
- *
- * @param string $arg the item's key.
- * @param string $content the item's content.
- * @param int $expire the item's expiry time in seconds. Defaults to 12h.
- *
- * @returns mixed returns TRUE on success or FALSE on failure.
- *
- */
- public function write($arg, $content, $expire = self::DEFAULT_EXPIRATION)
- {
- $key = $this->getCacheKey($arg);
- return $this->memcache->set($key, $content, $expire);
- }
-
- /**
* Return statistics.
*
* @StudipCache::getStats()
@@ -123,20 +81,19 @@ class StudipMemcachedCache implements StudipCache
*/
public function getStats(): array
{
- $stats = $this->memcache->getStats();
- return $stats;
+ return $this->memcache->getStats();
}
/**
* Return the Vue component name and props that handle configuration.
*
- * @see StudipCache::getConfig()
+ * @see Cache::getConfig()
*
* @return array
*/
public static function getConfig(): array
{
- $currentCache = Config::get()->SYSTEMCACHE;
+ $currentCache = \Config::get()->SYSTEMCACHE;
// Set default config for this cache
$currentConfig = [
@@ -154,4 +111,41 @@ class StudipMemcachedCache implements StudipCache
];
}
+ /**
+ * @inheritDoc
+ */
+ public function getItem($key)
+ {
+ $item = new Item($key);
+ $value = $this->memcache->get($this->getCacheKey($key));
+ if ($this->memcache->getResultCode() !== Memcached::RES_NOTFOUND) {
+ // Set the value, even if it is the boolean value false:
+ $item->setHit();
+ $item->set($value);
+ }
+ return $item;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function hasItem($key)
+ {
+ return $this->memcache->checkKey($this->getCacheKey($key));
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function save(CacheItemInterface $item)
+ {
+ $expiration = $this->getExpiration($item);
+ if ($expiration < 1) {
+ // The item would expire immediately.
+ return false;
+ }
+
+ $real_key = $this->getCacheKey($item->getKey());
+ return $this->memcache->set($real_key, $item->get(), $expiration);
+ }
}
diff --git a/lib/classes/cache/MemoryCache.class.php b/lib/classes/cache/MemoryCache.class.php
new file mode 100644
index 0000000..93f6bbd
--- /dev/null
+++ b/lib/classes/cache/MemoryCache.class.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace Studip\Cache;
+
+use DateTime;
+use Psr\Cache\CacheItemInterface;
+
+/**
+ * The php memory implementation of the StudipCache interface.
+ *
+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
+ * @license GPL2 or any later version
+ * @since Stud.IP 5.0
+ */
+class MemoryCache extends Cache
+{
+ protected array $memory_cache = [];
+
+ /**
+ * Expires just a single key.
+ *
+ * @param string the key
+ */
+ public function expire($key)
+ {
+ unset($this->memory_cache[$key]);
+ }
+
+ /**
+ * Expire all items from the cache.
+ */
+ public function flush()
+ {
+ $this->memory_cache = [];
+ }
+
+ public static function getDisplayName(): string
+ {
+ return 'Memory cache';
+ }
+
+ public function getStats(): array
+ {
+ return [];
+ }
+
+ public static function getConfig(): array
+ {
+ return [];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getItem($key)
+ {
+ $item = new Item($key);
+ if (!isset($this->memory_cache[$key])) {
+ return $item;
+ }
+ if ($this->memory_cache[$key]['expires'] < time()) {
+ $this->expire($key);
+ return $item;
+ }
+ $item->setHit();
+ $item->set($this->memory_cache[$key]['data']);
+ if (!empty($this->memory_cache[$key]['expires'])) {
+ $expiration = new DateTime();
+ $expiration->setTimestamp($this->memory_cache[$key]['expires']);
+ $item->expiresAt($expiration);
+ }
+ return $item;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function hasItem($key)
+ {
+ return isset($this->memory_cache[$key])
+ && $this->memory_cache[$key]['expires'] < time();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function save(CacheItemInterface $item)
+ {
+ $expiration = $this->getExpiration($item);
+
+ $this->memory_cache[$item->getKey()] = [
+ 'expires' => $expiration + time(),
+ 'data' => $item->get(),
+ ];
+
+ return true;
+ }
+}
diff --git a/lib/classes/StudipCacheProxy.php b/lib/classes/cache/Proxy.class.php
index 686f812..6791fb7 100644
--- a/lib/classes/StudipCacheProxy.php
+++ b/lib/classes/cache/Proxy.class.php
@@ -1,4 +1,9 @@
<?php
+
+namespace Studip\Cache;
+
+use StudipCacheOperation;
+
/**
* Proxies a StudipCache and stores the expire operation in the database.
* These operations are lateron applied to the cache they should have
@@ -8,18 +13,18 @@
* @license GPL2 or any later version
* @since Stud.IP 3.3
*/
-class StudipCacheProxy implements StudipCache
+class Proxy extends Cache
{
- protected $actual_cache;
- protected $proxy_these;
+ protected Cache $actual_cache;
+ protected array $proxy_these;
/**
- * @param StudipCache $cache The actual cache object
- * @param mixed $proxy_these List of operations to proxy (should be
- * an array but a space seperated string
- * is also valid)
+ * @param Cache $cache The actual cache object
+ * @param mixed $proxy_these List of operations to proxy (should be an
+ * array but a space seperated string is also
+ * valid)
*/
- public function __construct(StudipCache $cache, $proxy_these = ['expire'])
+ public function __construct(Cache $cache, $proxy_these = ['expire'])
{
if (!is_array($proxy_these)) {
$proxy_these = words($proxy_these);
@@ -43,7 +48,7 @@ class StudipCacheProxy implements StudipCache
$operation = new StudipCacheOperation([$key, 'expire']);
$operation->parameters = serialize([]);
$operation->store();
- } catch (Exception $e) {
+ } catch (\Exception $e) {
}
}
@@ -60,58 +65,58 @@ class StudipCacheProxy implements StudipCache
$operation = new StudipCacheOperation(['', 'flush']);
$operation->parameters = serialize([]);
$operation->store();
- } catch (Exception $e) {
+ } catch (\Exception $e) {
}
}
return $this->actual_cache->flush();
}
- /**
- * Reads just a single key from the cache.
- *
- * @param string $key The item's key
- * @return mixed The corresponding value
- */
- public function read($key)
+ public static function getDisplayName(): string
{
- return $this->actual_cache->read($key);
+ return static::class;
}
- /**
- * Store data at the server.
- *
- * @param string $key The item's key
- * @param string $content The item's conten
- * @param int $expires The item's expiry time in seconds, defaults to 12h
- * @return bool Returns TRUE on success or FALSE on failure
- */
- public function write($key, $content, $expires = self::DEFAULT_EXPIRATION)
+ public function getStats(): array
{
- if (in_array('write', $this->proxy_these)) {
- try {
- $operation = new StudipCacheOperation([$key, 'write']);
- $operation->parameters = serialize([$content, $expires]);
- $operation->store();
- } catch (Exception $e) {
- }
- }
+ return $this->actual_cache->getStats();
+ }
- return $this->actual_cache->write($key, $content, $expires);
+ public static function getConfig(): array
+ {
+ return [];
}
- public static function getDisplayName(): string
+ /**
+ * @inheritDoc
+ */
+ public function getItem($key)
{
- return static::class;
+ return $this->actual_cache->getItem($key);
}
- public function getStats(): array
+ /**
+ * @inheritDoc
+ */
+ public function hasItem($key)
{
- return $this->actual_cache->getStats();
+ return $this->actual_cache->hasItem($key);
}
- public static function getConfig(): array
+ /**
+ * @inheritDoc
+ */
+ public function save(\Psr\Cache\CacheItemInterface $item)
{
- return [];
+ if (in_array('save', $this->proxy_these)) {
+ try {
+ $operation = new StudipCacheOperation([$item->getKey(), 'save']);
+ $operation->parameters = serialize([$item]);
+ $operation->store();
+ } catch (\Exception $e) {
+ }
+ }
+
+ return $this->actual_cache->save($item);
}
}
diff --git a/lib/classes/StudipRedisCache.class.php b/lib/classes/cache/RedisCache.class.php
index 7b9570b..9ea8711 100644
--- a/lib/classes/StudipRedisCache.class.php
+++ b/lib/classes/cache/RedisCache.class.php
@@ -1,4 +1,15 @@
<?php
+
+namespace Studip\Cache;
+
+use BadMethodCallException;
+use Config;
+use DateTime;
+use Exception;
+use Psr\Cache\CacheItemInterface;
+use Redis;
+use RedisException;
+
/**
* Cache implementation using redis.
*
@@ -8,9 +19,9 @@
* @subpackage cache
* @since Stud.IP 5.0
*/
-class StudipRedisCache implements StudipCache
+class RedisCache extends Cache
{
- use StudipCacheKeyTrait;
+ use KeyTrait;
private $redis;
@@ -28,6 +39,8 @@ class StudipRedisCache implements StudipCache
* @param string $hostname Hostname of redis server
* @param int $port Port of redis server
* @param string $auth Optional auth token/password
+ *
+ * @throws RedisException
*/
public function __construct($hostname, $port, string $auth = '')
{
@@ -74,41 +87,6 @@ class StudipRedisCache implements StudipCache
}
/**
- * Retrieve item from the server.
- *
- * Example:
- *
- * # reads foo
- * $foo = $cache->reads('foo');
- *
- * @param string $arg a single key
- * @return mixed the previously stored data if an item with such a key
- * exists on the server or FALSE on failure.
- */
- public function read($arg)
- {
- $key = $this->getCacheKey($arg);
-
- $result = $this->redis->get($key);
-
- return ($result === null) ? null : unserialize($result);
- }
-
- /**
- * Store data at the server.
- *
- * @param string the item's key.
- * @param string the item's content.
- * @param int the item's expiry time in seconds. Defaults to 12h.
- * @return mixed returns TRUE on success or FALSE on failure.
- */
- public function write($name, $content, $expire = self::DEFAULT_EXPIRATION)
- {
- $key = $this->getCacheKey($name);
- return $this->redis->setEx($key, $expire, serialize($content));
- }
-
- /**
* Expire all items from the cache.
*/
public function flush()
@@ -174,4 +152,47 @@ class StudipRedisCache implements StudipCache
'props' => $currentConfig
];
}
+
+ /**
+ * @inheritDoc
+ */
+ public function getItem($key)
+ {
+ $item = new Item($key);
+ $real_key = $this->getCacheKey($key);
+ $result = $this->redis->get($real_key);
+ if ($result === null) {
+ return $item;
+ }
+ $item->setHit();
+ $item->set(unserialize($result));
+ $expiration = new DateTime();
+ $expiration->setTimestamp($this->redis->expiretime($real_key));
+ $item->expiresAt($expiration);
+ return $item;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function hasItem($key)
+ {
+ $real_key = $this->getCacheKey($key);
+ return $this->redis->get($real_key) !== null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function save(CacheItemInterface $item)
+ {
+ $expiration = $this->getExpiration($item);
+ if ($expiration < 1) {
+ // The item would expire immediately.
+ return false;
+ }
+
+ $real_key = $this->getCacheKey($item->getKey());
+ return $this->redis->setEx($real_key, $expiration, serialize($item->get()));
+ }
}
diff --git a/lib/classes/StudipCacheWrapper.php b/lib/classes/cache/Wrapper.class.php
index 6c75c01..7448932 100644
--- a/lib/classes/StudipCacheWrapper.php
+++ b/lib/classes/cache/Wrapper.class.php
@@ -1,5 +1,9 @@
<?php
+namespace Studip\Cache;
+
+use Psr\Cache\CacheItemInterface;
+
/**
* The cache wrapper wraps a memory cache around another cache. This should
* reduce the accesses to the actual cache.
@@ -8,17 +12,15 @@
* @license GPL2 or any later version
* @since Stud.IP 5.4
*/
-class StudipCacheWrapper implements StudipCache
+class Wrapper extends Cache
{
- const DEFAULT_MEMORY_EXPIRATION = 60;
-
- protected $actual_cache;
- protected $memory_cache;
+ protected Cache $actual_cache;
+ protected MemoryCache $memory_cache;
- public function __construct(StudipCache $actual_cache)
+ public function __construct(Cache $actual_cache)
{
$this->actual_cache = $actual_cache;
- $this->memory_cache = new StudipMemoryCache();
+ $this->memory_cache = new MemoryCache();
}
/**
@@ -39,47 +41,55 @@ class StudipCacheWrapper implements StudipCache
$this->actual_cache->flush();
}
+ public static function getDisplayName(): string
+ {
+ return static::class;
+ }
+
+ public function getStats(): array
+ {
+ return $this->actual_cache->getStats();
+ }
+
+ public static function getConfig(): array
+ {
+ return [];
+ }
+
/**
- * @inheritdoc
+ * @inheritDoc
*/
- public function read($arg)
+ public function getItem($key)
{
- $cached = $this->memory_cache->read($arg);
- if ($cached !== false) {
+ $cached = $this->memory_cache->getItem($key);
+ if ($cached->isHit()) {
return $cached;
}
- $cached = $this->actual_cache->read($arg);
- if ($cached !== false) {
- $this->memory_cache->write($arg, $cached, self::DEFAULT_MEMORY_EXPIRATION);
+ $cached = $this->actual_cache->getItem($key);
+ if ($cached->isHit()) {
+ $this->memory_cache->save($cached);
}
return $cached;
}
/**
- * @inheritdoc
+ * @inheritDoc
*/
- public function write($name, $content, $expires = self::DEFAULT_EXPIRATION)
+ public function hasItem($key)
{
- if ($this->actual_cache->write($name, $content, $expires)) {
- return $this->memory_cache->write($name, $content, $expires);
- } else {
- return false;
- }
- }
-
- public static function getDisplayName(): string
- {
- return static::class;
- }
-
- public function getStats(): array
- {
- return $this->actual_cache->getStats();
+ return $this->actual_cache->hasItem($key);
}
- public static function getConfig(): array
+ /**
+ * @inheritDoc
+ */
+ public function save(CacheItemInterface $item)
{
- return [];
+ if ($this->actual_cache->save($item)) {
+ return $this->memory_cache->save($item);
+ } else {
+ return false;
+ }
}
}
diff --git a/lib/classes/cas/CAS_PGTStorage_Cache.php b/lib/classes/cas/CAS_PGTStorage_Cache.php
index 284b591..61ce9fa 100644
--- a/lib/classes/cas/CAS_PGTStorage_Cache.php
+++ b/lib/classes/cas/CAS_PGTStorage_Cache.php
@@ -43,7 +43,7 @@ class CAS_PGTStorage_Cache extends CAS_PGTStorage_AbstractStorage
*/
public function write($pgt, $pgt_iou)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache_key = 'pgtiou/' . $pgt_iou;
return $cache->write($cache_key, $pgt);
}
@@ -58,7 +58,7 @@ class CAS_PGTStorage_Cache extends CAS_PGTStorage_AbstractStorage
*/
public function read($pgt_iou)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache_key = 'pgtiou/' . $pgt_iou;
$pgt = $cache->read($cache_key);
$cache->expire($cache_key);
diff --git a/lib/cronjobs/purge_cache.class.php b/lib/cronjobs/purge_cache.class.php
index 4e5682f..d2e3697 100644
--- a/lib/cronjobs/purge_cache.class.php
+++ b/lib/cronjobs/purge_cache.class.php
@@ -70,7 +70,7 @@ class PurgeCacheJob extends CronJob
*/
public function setUp()
{
- require_once 'lib/classes/StudipFileCache.class.php';
+ require_once 'lib/classes/cache/FileCache.class.php';
}
/**
@@ -86,7 +86,7 @@ class PurgeCacheJob extends CronJob
*/
public function execute($last_result, $parameters = [])
{
- $cache = new StudipFileCache();
+ $cache = new \Studip\Cache\FileCache();
$cache->purge(empty($parameters['verbose']));
}
}
diff --git a/lib/functions.php b/lib/functions.php
index 0e806aa..7d9f4f2 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -636,7 +636,7 @@ function get_users_online($active_time = 5, $name_format = 'full_rev')
*/
function get_users_online_count($active_time = 10)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$online_count = $cache->read("online_count/{$active_time}");
if ($online_count === false) {
$query = "SELECT COUNT(*) FROM user_online
diff --git a/lib/models/CourseDate.class.php b/lib/models/CourseDate.class.php
index 59fbb9c..eadeb0a 100644
--- a/lib/models/CourseDate.class.php
+++ b/lib/models/CourseDate.class.php
@@ -364,7 +364,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
// load room-booking, if any
$this->room_booking;
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->expire('course/undecorated_data/'. $this->range_id);
return parent::store();
}
@@ -376,7 +376,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
*/
public function delete()
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->expire('course/undecorated_data/'. $this->range_id);
return parent::delete();
}
@@ -433,7 +433,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
$folders = array_merge($folders, $topic->folders->getArrayCopy());
}
foreach ($folders as $folder) {
- list($files, $typed_folders) = array_values(FileManager::getFolderFilesRecursive($folder->getTypedFolder(), $user_id));
+ [$files, $typed_folders] = array_values(FileManager::getFolderFilesRecursive($folder->getTypedFolder(), $user_id));
foreach ($files as $file) {
$all_files[$file->id] = $file;
}
diff --git a/lib/models/OERMaterial.php b/lib/models/OERMaterial.php
index 6ec7de8..8411d14 100644
--- a/lib/models/OERMaterial.php
+++ b/lib/models/OERMaterial.php
@@ -164,7 +164,7 @@ class OERMaterial extends SimpleORMap
public static function fetchRemoteSearch($text, $tag = false)
{
$cache_name = "oer_remote_searched_for_".md5($text)."_".($tag ? 1 : 0);
- $already_searched = (bool) StudipCacheFactory::getCache()->read($cache_name);
+ $already_searched = (bool) \Studip\Cache\Factory::getCache()->read($cache_name);
if (!$already_searched) {
$hosts = OERHost::findBySQL("index_server = '1' AND allowed_as_index_server = '1' ORDER BY RAND()");
foreach ($hosts as $host) {
@@ -172,7 +172,7 @@ class OERMaterial extends SimpleORMap
$host->fetchRemoteSearch($text, $tag);
}
}
- StudipCacheFactory::getCache()->write($cache_name, "1", 60);
+ \Studip\Cache\Factory::getCache()->write($cache_name, "1", 60);
}
}
diff --git a/lib/models/PersonalNotifications.class.php b/lib/models/PersonalNotifications.class.php
index 721038c..12d9c1b 100644
--- a/lib/models/PersonalNotifications.class.php
+++ b/lib/models/PersonalNotifications.class.php
@@ -262,7 +262,7 @@ class PersonalNotifications extends SimpleORMap
*/
protected static function getCache($user_id)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$hash = self::getCacheHash($user_id);
$cached = $cache->read($hash);
@@ -281,7 +281,7 @@ class PersonalNotifications extends SimpleORMap
*/
protected static function setCache($user_id, $items)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$hash = self::getCacheHash($user_id);
$cache->write($hash, serialize($items), self::CACHE_DURATION);
}
@@ -293,7 +293,7 @@ class PersonalNotifications extends SimpleORMap
*/
protected static function expireCache($user_id)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$hash = self::getCacheHash($user_id);
$cache->expire($hash);
}
diff --git a/lib/models/Semester.class.php b/lib/models/Semester.class.php
index 4eefa3b..03243a5 100644
--- a/lib/models/Semester.class.php
+++ b/lib/models/Semester.class.php
@@ -181,7 +181,7 @@ class Semester extends SimpleORMap
if (!is_array(self::$semester_cache) || $force_reload) {
self::$semester_cache = [];
if (!$force_reload) {
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$semester_data_array = unserialize($cache->read('DB_SEMESTER_DATA'));
if ($semester_data_array) {
foreach ($semester_data_array as $semester_data) {
@@ -202,7 +202,7 @@ class Semester extends SimpleORMap
}
$semester_data[] = $semester->toRawArray();
}
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->write('DB_SEMESTER_DATA', serialize($semester_data));
}
}
@@ -471,7 +471,7 @@ class Semester extends SimpleORMap
*/
public function refreshCache()
{
- StudipCacheFactory::getCache()->expire('DB_SEMESTER_DATA');
+ \Studip\Cache\Factory::getCache()->expire('DB_SEMESTER_DATA');
}
/*
diff --git a/lib/models/StudipCacheOperation.php b/lib/models/StudipCacheOperation.php
index e9c8738..d2287c3 100644
--- a/lib/models/StudipCacheOperation.php
+++ b/lib/models/StudipCacheOperation.php
@@ -42,7 +42,7 @@ class StudipCacheOperation extends SimpleORMap
*/
public static function apply(StudipCache $cache)
{
- self::findEachBySQL(function ($item) use ($cache) {
+ self::findEachBySQL(function (StudipCacheOperation $item) use ($cache): void {
$parameters = unserialize($item->parameters);
array_unshift($parameters, $item->cache_key);
call_user_func_array([$cache, $item->operation], $parameters);
diff --git a/lib/phplib/CT_Cache.class.php b/lib/phplib/CT_Cache.class.php
index 311b27c..d4eccfa 100644
--- a/lib/phplib/CT_Cache.class.php
+++ b/lib/phplib/CT_Cache.class.php
@@ -14,7 +14,7 @@ class CT_Cache
public function ac_start()
{
- $this->cache = StudipCacheFactory::getCache();
+ $this->cache = \Studip\Cache\Factory::getCache();
}
public function ac_get_lock()
diff --git a/lib/plugins/db/RolePersistence.class.php b/lib/plugins/db/RolePersistence.class.php
index b11fa4a..df63a77 100644
--- a/lib/plugins/db/RolePersistence.class.php
+++ b/lib/plugins/db/RolePersistence.class.php
@@ -29,7 +29,7 @@ class RolePersistence
{
if (self::$all_roles === null) {
// read cache
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
// cache miss, retrieve from database
self::$all_roles = $cache->read(self::ROLES_CACHE_KEY);
@@ -675,7 +675,7 @@ class RolePersistence
public static function expireRolesCache()
{
self::$all_roles = null;
- StudipCacheFactory::getCache()->expire(self::ROLES_CACHE_KEY);
+ \Studip\Cache\Factory::getCache()->expire(self::ROLES_CACHE_KEY);
}
/**
diff --git a/lib/plugins/engine/PluginRepository.class.php b/lib/plugins/engine/PluginRepository.class.php
index 14415f4..235e9bd 100644
--- a/lib/plugins/engine/PluginRepository.class.php
+++ b/lib/plugins/engine/PluginRepository.class.php
@@ -55,7 +55,7 @@ class PluginRepository
*/
public function readMetadata($url)
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache_key = 'plugin_metadata/'.$url;
$metadata = $cache->read($cache_key);
diff --git a/lib/raumzeit/SingleDate.class.php b/lib/raumzeit/SingleDate.class.php
index 82a89db..1a58695 100644
--- a/lib/raumzeit/SingleDate.class.php
+++ b/lib/raumzeit/SingleDate.class.php
@@ -292,7 +292,7 @@ class SingleDate
function delete()
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->expire('course/undecorated_data/' . $this->range_id);
$this->chdate = time();
@@ -304,7 +304,7 @@ class SingleDate
function store()
{
- $cache = StudipCacheFactory::getCache();
+ $cache = \Studip\Cache\Factory::getCache();
$cache->expire('course/undecorated_data/' . $this->range_id);
$this->chdate = time();