diff --git a/src/Core/Cache/Factory/Cache.php b/src/Core/Cache/Factory/Cache.php index 107c6ab216..b6124c156d 100644 --- a/src/Core/Cache/Factory/Cache.php +++ b/src/Core/Cache/Factory/Cache.php @@ -21,16 +21,14 @@ namespace Friendica\Core\Cache\Factory; -use Friendica\App\BaseURL; use Friendica\Core\Cache\Enum; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Cache\Type; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Database\Database; +use Friendica\Core\Hooks\Capabilities\ICanCreateInstances; use Friendica\Util\Profiler; -use Psr\Log\LoggerInterface; /** * Class CacheFactory @@ -45,39 +43,18 @@ class Cache * @var string The default cache if nothing set */ const DEFAULT_TYPE = Enum\Type::DATABASE; + /** @var ICanCreateInstances */ + protected $instanceCreator; + /** @var IManageConfigValues */ + protected $config; + /** @var Profiler */ + protected $profiler; - /** - * @var IManageConfigValues The IConfiguration to read parameters out of the config - */ - private $config; - - /** - * @var Database The database connection in case that the cache is used the dba connection - */ - private $dba; - - /** - * @var string The hostname, used as Prefix for Caching - */ - private $hostname; - - /** - * @var Profiler The optional profiler if the cached should be profiled - */ - private $profiler; - - /** - * @var LoggerInterface The Friendica Logger - */ - private $logger; - - public function __construct(BaseURL $baseURL, IManageConfigValues $config, Database $dba, Profiler $profiler, LoggerInterface $logger) + public function __construct(ICanCreateInstances $instanceCreator, IManageConfigValues $config, Profiler $profiler) { - $this->hostname = $baseURL->getHost(); - $this->config = $config; - $this->dba = $dba; - $this->profiler = $profiler; - $this->logger = $logger; + $this->config = $config; + $this->instanceCreator = $instanceCreator; + $this->profiler = $profiler; } /** @@ -92,7 +69,7 @@ class Cache */ public function createDistributed(string $type = null): ICanCache { - if ($type === Enum\Type::APCU) { + if ($type === Type\APCuCache::$NAME) { throw new InvalidCacheDriverException('apcu doesn\'t support distributed caching.'); } @@ -117,31 +94,17 @@ class Cache /** * Creates a new Cache instance * - * @param string $type The type of cache + * @param string $strategy The strategy, which cache instance should be used * * @return ICanCache * * @throws InvalidCacheDriverException In case the underlying cache driver isn't valid or not configured properly * @throws CachePersistenceException In case the underlying cache has errors during persistence */ - protected function create(string $type): ICanCache + protected function create(string $strategy): ICanCache { - switch ($type) { - case Enum\Type::MEMCACHE: - $cache = new Type\MemcacheCache($this->hostname, $this->config); - break; - case Enum\Type::MEMCACHED: - $cache = new Type\MemcachedCache($this->hostname, $this->config, $this->logger); - break; - case Enum\Type::REDIS: - $cache = new Type\RedisCache($this->hostname, $this->config); - break; - case Enum\Type::APCU: - $cache = new Type\APCuCache($this->hostname); - break; - default: - $cache = new Type\DatabaseCache($this->hostname, $this->dba); - } + /** @var ICanCache $cache */ + $cache = $this->instanceCreator->create(ICanCache::class, $strategy); $profiling = $this->config->get('system', 'profiling', false); diff --git a/src/Core/Cache/Type/APCuCache.php b/src/Core/Cache/Type/APCuCache.php index 05eb2fa074..02b2d0fbdb 100644 --- a/src/Core/Cache/Type/APCuCache.php +++ b/src/Core/Cache/Type/APCuCache.php @@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; /** @@ -31,12 +30,12 @@ use Friendica\Core\Cache\Exception\InvalidCacheDriverException; */ class APCuCache extends AbstractCache implements ICanCacheInMemory { + public static $NAME = 'apcu'; + use CompareSetTrait; use CompareDeleteTrait; /** - * @param string $hostname - * * @throws InvalidCacheDriverException */ public function __construct(string $hostname) @@ -173,12 +172,4 @@ class APCuCache extends AbstractCache implements ICanCacheInMemory return true; } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::APCU; - } } diff --git a/src/Core/Cache/Type/AbstractCache.php b/src/Core/Cache/Type/AbstractCache.php index 5c00542a77..36e301ad20 100644 --- a/src/Core/Cache/Type/AbstractCache.php +++ b/src/Core/Cache/Type/AbstractCache.php @@ -28,6 +28,8 @@ use Friendica\Core\Cache\Capability\ICanCache; */ abstract class AbstractCache implements ICanCache { + public static $NAME = ''; + /** * @var string The hostname */ @@ -105,4 +107,10 @@ abstract class AbstractCache implements ICanCache return $result; } } + + /** {@inheritDoc} */ + public function getName(): string + { + return static::$NAME; + } } diff --git a/src/Core/Cache/Type/ArrayCache.php b/src/Core/Cache/Type/ArrayCache.php index 8886a886a7..ad87eaf23a 100644 --- a/src/Core/Cache/Type/ArrayCache.php +++ b/src/Core/Cache/Type/ArrayCache.php @@ -29,6 +29,8 @@ use Friendica\Core\Cache\Enum; */ class ArrayCache extends AbstractCache implements ICanCacheInMemory { + public static $NAME = 'array'; + use CompareDeleteTrait; /** @var array Array with the cached data */ @@ -108,12 +110,4 @@ class ArrayCache extends AbstractCache implements ICanCacheInMemory return false; } } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Enum\Type::ARRAY; - } } diff --git a/src/Core/Cache/Type/DatabaseCache.php b/src/Core/Cache/Type/DatabaseCache.php index fa7968b650..18541e0d2b 100644 --- a/src/Core/Cache/Type/DatabaseCache.php +++ b/src/Core/Cache/Type/DatabaseCache.php @@ -32,6 +32,8 @@ use Friendica\Util\DateTimeFormat; */ class DatabaseCache extends AbstractCache implements ICanCache { + public static $NAME = 'database'; + /** * @var Database */ @@ -154,12 +156,4 @@ class DatabaseCache extends AbstractCache implements ICanCache throw new CachePersistenceException('Cannot clear cache', $exception); } } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Enum\Type::DATABASE; - } } diff --git a/src/Core/Cache/Type/MemcacheCache.php b/src/Core/Cache/Type/MemcacheCache.php index d19e7deb1d..09394a1dd3 100644 --- a/src/Core/Cache/Type/MemcacheCache.php +++ b/src/Core/Cache/Type/MemcacheCache.php @@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -34,6 +33,8 @@ use Memcache; */ class MemcacheCache extends AbstractCache implements ICanCacheInMemory { + static $NAME = 'memcached'; + use CompareSetTrait; use CompareDeleteTrait; use MemcacheCommandTrait; @@ -169,12 +170,4 @@ class MemcacheCache extends AbstractCache implements ICanCacheInMemory $cacheKey = $this->getCacheKey($key); return $this->memcache->add($cacheKey, serialize($value), MEMCACHE_COMPRESSED, $ttl); } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::MEMCACHE; - } } diff --git a/src/Core/Cache/Type/MemcachedCache.php b/src/Core/Cache/Type/MemcachedCache.php index 6d994ddf57..45a7a0f1c1 100644 --- a/src/Core/Cache/Type/MemcachedCache.php +++ b/src/Core/Cache/Type/MemcachedCache.php @@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -35,6 +34,8 @@ use Psr\Log\LoggerInterface; */ class MemcachedCache extends AbstractCache implements ICanCacheInMemory { + static $NAME = 'memcached'; + use CompareSetTrait; use CompareDeleteTrait; use MemcacheCommandTrait; @@ -185,12 +186,4 @@ class MemcachedCache extends AbstractCache implements ICanCacheInMemory $cacheKey = $this->getCacheKey($key); return $this->memcached->add($cacheKey, $value, $ttl); } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::MEMCACHED; - } } diff --git a/src/Core/Cache/Type/RedisCache.php b/src/Core/Cache/Type/RedisCache.php index b1fb9ba9c3..36c60a12c1 100644 --- a/src/Core/Cache/Type/RedisCache.php +++ b/src/Core/Cache/Type/RedisCache.php @@ -21,10 +21,8 @@ namespace Friendica\Core\Cache\Type; -use Exception; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -35,6 +33,8 @@ use Redis; */ class RedisCache extends AbstractCache implements ICanCacheInMemory { + public static $NAME = 'redis'; + /** * @var Redis */ @@ -59,18 +59,23 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory $redis_pw = $config->get('system', 'redis_password'); $redis_db = $config->get('system', 'redis_db', 0); - if (!empty($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) { - throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available'); - } elseif (!@$this->redis->connect($redis_host)) { - throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ' isn\'t available'); - } + try { - if (!empty($redis_pw) && !$this->redis->auth($redis_pw)) { - throw new CachePersistenceException('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port); - } + if (!empty($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) { + throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available'); + } else if (!@$this->redis->connect($redis_host)) { + throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ' isn\'t available'); + } - if ($redis_db !== 0 && !$this->redis->select($redis_db)) { - throw new CachePersistenceException('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port); + if (!empty($redis_pw) && !$this->redis->auth($redis_pw)) { + throw new CachePersistenceException('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port); + } + + if ($redis_db !== 0 && !$this->redis->select($redis_db)) { + throw new CachePersistenceException('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port); + } + } catch (\RedisException $exception) { + throw new CachePersistenceException('Redis connection fails unexpectedly', $exception); } } @@ -211,12 +216,4 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory $this->redis->unwatch(); return false; } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::REDIS; - } } diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 98a9f3077d..c3f30ad8d3 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -178,6 +178,20 @@ return [ $_SERVER, ], ], + '$hostname' => [ + 'instanceOf' => App\BaseURL::class, + 'constructParams' => [ + $_SERVER, + ], + 'call' => [ + ['getHost', [], Dice::CHAIN_CALL], + ], + ], + Cache\Type\AbstractCache::class => [ + 'constructParams' => [ + [Dice::INSTANCE => '$hostname'], + ], + ], App\Page::class => [ 'constructParams' => [ [Dice::INSTANCE => '$basepath'], diff --git a/static/strategies.config.php b/static/strategies.config.php index bb3598c369..5d84a7e47f 100644 --- a/static/strategies.config.php +++ b/static/strategies.config.php @@ -19,7 +19,7 @@ * */ -use Friendica\Core\Hooks\Capabilities\BehavioralHookType as H; +use Friendica\Core\Cache; use Friendica\Core\Logger\Type; use Psr\Log; @@ -29,4 +29,11 @@ return [ Type\SyslogLogger::class => ['syslog'], Type\StreamLogger::class => ['stream'], ], + Cache\Capability\ICanCache::class => [ + Cache\Type\APCuCache::class => ['apcu'], + Cache\Type\DatabaseCache::class => ['database', ''], + Cache\Type\MemcacheCache::class => ['memcache'], + Cache\Type\MemcachedCache::class => ['memcached'], + Cache\Type\RedisCache::class => ['redis'], + ] ]; diff --git a/tests/phpunit-addons.xml b/tests/phpunit-addons.xml new file mode 100644 index 0000000000..3793249ab9 --- /dev/null +++ b/tests/phpunit-addons.xml @@ -0,0 +1,24 @@ + + + + ../addon/*/tests/ + + + + + ../addon/ + + + ../addon/*/tests/ + ../addon/*/view/ + ../addon/*/vendor/ + + + diff --git a/tests/src/Core/Cache/DatabaseCacheTest.php b/tests/src/Core/Cache/DatabaseCacheTest.php index 98afa9e248..63cc7e4452 100644 --- a/tests/src/Core/Cache/DatabaseCacheTest.php +++ b/tests/src/Core/Cache/DatabaseCacheTest.php @@ -21,6 +21,7 @@ namespace Friendica\Test\src\Core\Cache; +use Friendica\App\BaseURL; use Friendica\Core\Cache; use Friendica\Test\DatabaseTestTrait; use Friendica\Test\Util\CreateDatabaseTrait;