aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/cache/Factory.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/classes/cache/Factory.php')
-rw-r--r--lib/classes/cache/Factory.php206
1 files changed, 206 insertions, 0 deletions
diff --git a/lib/classes/cache/Factory.php b/lib/classes/cache/Factory.php
new file mode 100644
index 0000000..b5c8359
--- /dev/null
+++ b/lib/classes/cache/Factory.php
@@ -0,0 +1,206 @@
+<?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.
+ *
+ * @package studip
+ * @subpackage lib
+ *
+ * @author Marco Diedrich (mdiedric@uos)
+ * @author Marcus Lunzenauer (mlunzena@uos.de)
+ * @copyright 2007 (c) Authors
+ * @since 1.6
+ * @license GPL2 or any later version
+ */
+class Factory
+{
+ /**
+ * the default cache class
+ *
+ * @var string
+ */
+ const DEFAULT_CACHE_CLASS = DbCache::class;
+
+ /**
+ * singleton instance
+ *
+ * @var Cache|null
+ */
+ private static ?Cache $cache = null;
+
+
+ /**
+ * config instance
+ *
+ * @var Config|null
+ */
+ private static ?Config $config = null;
+
+
+ /**
+ * Returns the currently used config instance
+ *
+ * @return Config an instance of class Config used by this factory to
+ * determine the class of the actual implementation of
+ * the StudipCache interface; if no config was set, it
+ * returns the instance returned by Config#getInstance
+ * @see Config
+ */
+ public static function getConfig()
+ {
+ return self::$config ?? Config::getInstance();
+ }
+
+
+ /**
+ * @param Config $config an instance of class Config which will be used to
+ * determine the class of the implementation of interface
+ * StudipCache
+ */
+ public static function setConfig(Config $config)
+ {
+ self::$config = $config;
+ self::$cache = NULL;
+ }
+
+ /**
+ * Resets the configuration and voids the cache instance.
+ */
+ public static function unconfigure()
+ {
+ self::$cache = NULL;
+ }
+
+ /**
+ * Returns a cache instance.
+ *
+ * @param bool $apply_proxied_operations Whether or not to apply any
+ * proxied (disable this in tests!)
+ * @return Cache the cache instance
+ */
+ public static function getCache(bool $apply_proxied_operations = true): Cache
+ {
+ if (self::$cache === null) {
+ $proxied = false;
+
+ if (!$GLOBALS['CACHING_ENABLE']) {
+ 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.
+ if (isset($GLOBALS['GLOBAL_CACHING_ENABLE']) && $GLOBALS['GLOBAL_CACHING_ENABLE']) {
+ $proxied = true;
+ }
+ } else {
+ try {
+ $class = self::loadCacheClass();
+ $args = self::retrieveConstructorArguments();
+
+ self::$cache = self::instantiateCache($class, $args);
+ } catch (\Exception $e) {
+ error_log(__METHOD__ . ': ' . $e->getMessage());
+ PageLayout::addBodyElements(MessageBox::error(__METHOD__ . ': ' . $e->getMessage()));
+ $class = self::DEFAULT_CACHE_CLASS;
+ self::$cache = new $class();
+ }
+ }
+
+ // If proxy should be used, inject it. Otherwise apply pending
+ // operations, if any.
+ if ($proxied) {
+ 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
+ // in a try/catch block. Otherwise there are no means to
+ // execute migration 166 which creates the neccessary tables
+ // for said operation.
+ try {
+ StudipCacheOperation::apply(self::$cache);
+ } catch (\Exception $e) {
+ }
+ }
+ }
+
+ return self::$cache;
+ }
+
+
+ /**
+ * Load configured cache class and return its name.
+ *
+ * @return string the name of the configured cache class
+ */
+ public static function loadCacheClass()
+ {
+ $cacheConfig = self::getConfig()->SYSTEMCACHE;
+
+ $cache_class = $cacheConfig['type'] ?: null;
+
+ # default class
+ if ($cache_class === null) {
+ $version = new DBSchemaVersion();
+ if ($version->get(1) < 224) {
+ // db cache is not yet available, use StudipMemoryCache
+ return 'StudipMemoryCache';
+ }
+
+ return self::DEFAULT_CACHE_CLASS;
+ }
+
+ if (!class_exists($cache_class)) {
+ throw new UnexpectedValueException("Could not find class: '$cache_class'");
+ }
+
+ return $cache_class;
+ }
+
+ /**
+ * Return an array of arguments required for instantiation of the cache
+ * class.
+ *
+ * @return array the array of arguments
+ */
+ public static function retrieveConstructorArguments()
+ {
+ $cacheConfig = self::getConfig()->SYSTEMCACHE;
+
+ return $cacheConfig ?: [];
+ }
+
+ /**
+ * Return an instance of a given class using some arguments. Unless the
+ * 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
+ *
+ * @return Cache an instance of the specified class
+ * @throws \ReflectionException
+ */
+ public static function instantiateCache($class, $arguments)
+ {
+ $reflection_class = new ReflectionClass($class);
+ $cache = (is_array($arguments['config']) && count($arguments['config']) > 0)
+ ? $reflection_class->newInstanceArgs($arguments['config'])
+ : $reflection_class->newInstance();
+
+ if ($class !== MemoryCache::class) {
+ return new Wrapper($cache);
+ }
+
+ return $cache;
+ }
+}