*
*/
+use Dice\Dice;
use Friendica\App\Mode;
use Friendica\BaseObject;
use Friendica\Util\ExAuth;
require dirname(__DIR__) . '/vendor/autoload.php';
-$dice = new \Dice\Dice();
-$dice = $dice->addRules(include __DIR__ . '/../static/dependencies.config.php');
+$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
BaseObject::setDependencyInjection($dice);
$appMode = $dice->create(Mode::class);
#!/usr/bin/env php
<?php
+use Dice\Dice;
+
require dirname(__DIR__) . '/vendor/autoload.php';
-$dice = new \Dice\Dice();
-$dice = $dice->addRules(include __DIR__ . '/../static/dependencies.config.php');
+$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
(new Friendica\Core\Console($dice, $argv))->execute();
* This script was taken from http://php.net/manual/en/function.pcntl-fork.php
*/
+use Dice\Dice;
use Friendica\Core\Config;
use Friendica\Core\Logger;
use Friendica\Core\Worker;
require dirname(__DIR__) . '/vendor/autoload.php';
-$dice = new \Dice\Dice();
-$dice = $dice->addRules(include __DIR__ . '/../static/dependencies.config.php');
+$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
\Friendica\BaseObject::setDependencyInjection($dice);
$a = \Friendica\BaseObject::getApp();
* @brief Starts the background processing
*/
+use Dice\Dice;
use Friendica\App;
+use Friendica\BaseObject;
use Friendica\Core\Config;
use Friendica\Core\Update;
use Friendica\Core\Worker;
require dirname(__DIR__) . '/vendor/autoload.php';
-$dice = new \Dice\Dice();
-$dice = $dice->addRules(include __DIR__ . '/../static/dependencies.config.php');
+$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
-\Friendica\BaseObject::setDependencyInjection($dice);
-$a = \Friendica\BaseObject::getApp();
+BaseObject::setDependencyInjection($dice);
+$a = BaseObject::getApp();
// Check the database structure and possibly fixes it
Update::check($a->getBasePath(), true, $a->getMode());
* Friendica
*/
+use Dice\Dice;
+
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
die('Vendor path not found. Please execute "bin/composer.phar --no-dev install" on the command line in the web root.');
}
require __DIR__ . '/vendor/autoload.php';
-$dice = new \Dice\Dice();
-$dice = $dice->addRules(include __DIR__ . '/static/dependencies.config.php');
+$dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php');
\Friendica\BaseObject::setDependencyInjection($dice);
use Asika\SimpleConsole\CommandArgsException;
use Friendica\App;
-use Friendica\Core;
+use Friendica\Core\Cache\Cache as CacheClass;
+use Friendica\Core\Cache\ICache;
use RuntimeException;
/**
*/
private $appMode;
+ /**
+ * @var ICache
+ */
+ private $cache;
+
protected function getHelp()
{
$help = <<<HELP
return $help;
}
- public function __construct(App\Mode $appMode, array $argv = null)
+ public function __construct(App\Mode $appMode, ICache $cache, array $argv = null)
{
parent::__construct($argv);
$this->appMode = $appMode;
+ $this->cache = $cache;
}
protected function doExecute()
$this->out('Database isn\'t ready or populated yet, database cache won\'t be available');
}
- Core\Cache::init();
-
if ($this->getOption('v')) {
- $this->out('Cache Driver Name: ' . Core\Cache::$driver_name);
- $this->out('Cache Driver Class: ' . Core\Cache::$driver_class);
+ $this->out('Cache Driver Name: ' . $this->cache->getName());
+ $this->out('Cache Driver Class: ' . get_class($this->cache));
}
switch ($this->getArgument(0)) {
private function executeList()
{
$prefix = $this->getArgument(1);
- $keys = Core\Cache::getAllKeys($prefix);
+ $keys = $this->cache->getAllKeys($prefix);
if (empty($prefix)) {
$this->out('Listing all cache keys:');
private function executeGet()
{
if (count($this->args) >= 2) {
- $key = $this->getArgument(1);
- $value = Core\Cache::get($key);
+ $key = $this->getArgument(1);
+ $value = $this->cache->get($key);
$this->out("{$key} => " . var_export($value, true));
} else {
private function executeSet()
{
if (count($this->args) >= 3) {
- $key = $this->getArgument(1);
- $value = $this->getArgument(2);
- $duration = intval($this->getArgument(3, Core\Cache::FIVE_MINUTES));
+ $key = $this->getArgument(1);
+ $value = $this->getArgument(2);
+ $duration = intval($this->getArgument(3, CacheClass::FIVE_MINUTES));
- if (is_array(Core\Cache::get($key))) {
+ if (is_array($this->cache->get($key))) {
throw new RuntimeException("$key is an array and can't be set using this command.");
}
- $result = Core\Cache::set($key, $value, $duration);
+ $result = $this->cache->set($key, $value, $duration);
if ($result) {
- $this->out("{$key} <= " . Core\Cache::get($key));
+ $this->out("{$key} <= " . $this->cache->get($key));
} else {
$this->out("Unable to set {$key}");
}
private function executeFlush()
{
- $result = Core\Cache::clear();
+ $result = $this->cache->clear();
if ($result) {
$this->out('Cache successfully flushed');
} else {
private function executeClear()
{
- $result = Core\Cache::clear(false);
+ $result = $this->cache->clear(false);
if ($result) {
$this->out('Cache successfully cleared');
} else {
*/
namespace Friendica\Core;
-use Friendica\Factory\CacheDriverFactory;
+use Friendica\BaseObject;
+use Friendica\Core\Cache\Cache as CacheClass;
+use Friendica\Core\Cache\ICache;
/**
* @brief Class for storing data for a short time
*/
-class Cache extends \Friendica\BaseObject
+class Cache extends BaseObject
{
- const MONTH = 2592000;
- const WEEK = 604800;
- const DAY = 86400;
- const HOUR = 3600;
- const HALF_HOUR = 1800;
- const QUARTER_HOUR = 900;
- const FIVE_MINUTES = 300;
- const MINUTE = 60;
- const INFINITE = 0;
-
- /**
- * @var Cache\ICacheDriver
- */
- private static $driver = null;
- public static $driver_class = null;
- public static $driver_name = null;
-
- public static function init()
- {
- self::$driver_name = Config::get('system', 'cache_driver', 'database');
- self::$driver = CacheDriverFactory::create(self::$driver_name);
- self::$driver_class = get_class(self::$driver);
- }
-
- /**
- * Returns the current cache driver
- *
- * @return Cache\ICacheDriver
- */
- private static function getDriver()
- {
- if (self::$driver === null) {
- self::init();
- }
-
- return self::$driver;
- }
+ /** @deprecated Use CacheClass::MONTH */
+ const MONTH = CacheClass::MONTH;
+ /** @deprecated Use CacheClass::WEEK */
+ const WEEK = CacheClass::WEEK;
+ /** @deprecated Use CacheClass::DAY */
+ const DAY = CacheClass::DAY;
+ /** @deprecated Use CacheClass::HOUR */
+ const HOUR = CacheClass::HOUR;
+ /** @deprecated Use CacheClass::HALF_HOUR */
+ const HALF_HOUR = CacheClass::HALF_HOUR;
+ /** @deprecated Use CacheClass::QUARTER_HOUR */
+ const QUARTER_HOUR = CacheClass::QUARTER_HOUR;
+ /** @deprecated Use CacheClass::FIVE_MINUTES */
+ const FIVE_MINUTES = CacheClass::FIVE_MINUTES;
+ /** @deprecated Use CacheClass::MINUTE */
+ const MINUTE = CacheClass::MINUTE;
+ /** @deprecated Use CacheClass::INFINITE */
+ const INFINITE = CacheClass::INFINITE;
/**
* @brief Returns all the cache keys sorted alphabetically
*/
public static function getAllKeys($prefix = null)
{
- $time = microtime(true);
-
- $return = self::getDriver()->getAllKeys($prefix);
-
- self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack());
-
- return $return;
+ return self::getClass(ICache::class)->getAllKeys($prefix);
}
/**
*/
public static function get($key)
{
- $time = microtime(true);
-
- $return = self::getDriver()->get($key);
-
- self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack());
-
- return $return;
+ return self::getClass(ICache::class)->get($key);
}
/**
* @return bool
* @throws \Exception
*/
- public static function set($key, $value, $duration = self::MONTH)
+ public static function set($key, $value, $duration = CacheClass::MONTH)
{
- $time = microtime(true);
-
- $return = self::getDriver()->set($key, $value, $duration);
-
- self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack());
-
- return $return;
+ return self::getClass(ICache::class)->set($key, $value, $duration);
}
/**
*/
public static function delete($key)
{
- $time = microtime(true);
-
- $return = self::getDriver()->delete($key);
-
- self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack());
-
- return $return;
+ return self::getClass(ICache::class)->delete($key);
}
/**
* @param boolean $outdated just remove outdated values
*
* @return bool
+ * @throws \Exception
*/
public static function clear($outdated = true)
{
- return self::getDriver()->clear($outdated);
+ return self::getClass(ICache::class)->clear($outdated);
}
}
namespace Friendica\Core\Cache;
use Exception;
-use Friendica\Core\Cache;
/**
- * APCu Cache Driver.
+ * APCu Cache.
*
* @author Philipp Holzer <admin@philipp.info>
*/
-class APCuCache extends AbstractCacheDriver implements IMemoryCacheDriver
+class APCuCache extends Cache implements IMemoryCache
{
use TraitCompareSet;
use TraitCompareDelete;
/**
* @throws Exception
*/
- public function __construct()
+ public function __construct(string $hostname)
{
if (!self::isAvailable()) {
throw new Exception('APCu is not available.');
}
+
+ parent::__construct($hostname);
}
/**
return true;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName()
+ {
+ return self::TYPE_APCU;
+ }
}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Cache;
-use Friendica\BaseObject;
-
-
-/**
- * Abstract class for common used functions
- *
- * Class AbstractCacheDriver
- *
- * @package Friendica\Core\Cache
- */
-abstract class AbstractCacheDriver extends BaseObject
-{
- /**
- * Returns the prefix (to avoid namespace conflicts)
- *
- * @return string
- * @throws \Exception
- */
- protected function getPrefix()
- {
- // We fetch with the hostname as key to avoid problems with other applications
- return self::getApp()->getHostName();
- }
-
- /**
- * @param string $key The original key
- * @return string The cache key used for the cache
- * @throws \Exception
- */
- protected function getCacheKey($key)
- {
- return $this->getPrefix() . ":" . $key;
- }
-
- /**
- * @param array $keys A list of cached keys
- * @return array A list of original keys
- */
- protected function getOriginalKeys($keys)
- {
- if (empty($keys)) {
- return [];
- } else {
- // Keys are prefixed with the node hostname, let's remove it
- array_walk($keys, function (&$value) {
- $value = preg_replace('/^' . self::getApp()->getHostName() . ':/', '', $value);
- });
-
- sort($keys);
-
- return $keys;
- }
- }
-
- /**
- * Filters the keys of an array with a given prefix
- * Returns the filtered keys as an new array
- *
- * @param array $array The array, which should get filtered
- * @param string|null $prefix The prefix (if null, all keys will get returned)
- *
- * @return array The filtered array with just the keys
- */
- protected function filterArrayKeysByPrefix($array, $prefix = null)
- {
- if (empty($prefix)) {
- return array_keys($array);
- } else {
- $result = [];
-
- foreach (array_keys($array) as $key) {
- if (strpos($key, $prefix) === 0) {
- array_push($result, $key);
- }
- }
-
- return $result;
- }
-
- }
-}
namespace Friendica\Core\Cache;
-
-use Friendica\Core\Cache;
-
/**
- * Implementation of the IMemoryCacheDriver mainly for testing purpose
+ * Implementation of the IMemoryCache mainly for testing purpose
*
* Class ArrayCache
*
* @package Friendica\Core\Cache
*/
-class ArrayCache extends AbstractCacheDriver implements IMemoryCacheDriver
+class ArrayCache extends Cache implements IMemoryCache
{
use TraitCompareDelete;
return false;
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName()
+ {
+ return self::TYPE_ARRAY;
+ }
}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+/**
+ * Abstract class for common used functions
+ *
+ * Class AbstractCache
+ *
+ * @package Friendica\Core\Cache
+ */
+abstract class Cache implements ICache
+{
+ const TYPE_APCU = 'apcu';
+ const TYPE_ARRAY = 'array';
+ const TYPE_DATABASE = 'database';
+ const TYPE_MEMCACHE = 'memcache';
+ const TYPE_MEMCACHED = 'memcached';
+ const TYPE_REDIS = 'redis';
+
+ const MONTH = 2592000;
+ const WEEK = 604800;
+ const DAY = 86400;
+ const HOUR = 3600;
+ const HALF_HOUR = 1800;
+ const QUARTER_HOUR = 900;
+ const FIVE_MINUTES = 300;
+ const MINUTE = 60;
+ const INFINITE = 0;
+
+ /**
+ * @var string The hostname
+ */
+ private $hostName;
+
+ public function __construct(string $hostName)
+ {
+ $this->hostName = $hostName;
+ }
+
+ /**
+ * Returns the prefix (to avoid namespace conflicts)
+ *
+ * @return string
+ * @throws \Exception
+ */
+ protected function getPrefix()
+ {
+ // We fetch with the hostname as key to avoid problems with other applications
+ return $this->hostName;
+ }
+
+ /**
+ * @param string $key The original key
+ * @return string The cache key used for the cache
+ * @throws \Exception
+ */
+ protected function getCacheKey($key)
+ {
+ return $this->getPrefix() . ":" . $key;
+ }
+
+ /**
+ * @param array $keys A list of cached keys
+ * @return array A list of original keys
+ */
+ protected function getOriginalKeys($keys)
+ {
+ if (empty($keys)) {
+ return [];
+ } else {
+ // Keys are prefixed with the node hostname, let's remove it
+ array_walk($keys, function (&$value) {
+ $value = preg_replace('/^' . $this->hostName . ':/', '', $value);
+ });
+
+ sort($keys);
+
+ return $keys;
+ }
+ }
+
+ /**
+ * Filters the keys of an array with a given prefix
+ * Returns the filtered keys as an new array
+ *
+ * @param array $array The array, which should get filtered
+ * @param string|null $prefix The prefix (if null, all keys will get returned)
+ *
+ * @return array The filtered array with just the keys
+ */
+ protected function filterArrayKeysByPrefix($array, $prefix = null)
+ {
+ if (empty($prefix)) {
+ return array_keys($array);
+ } else {
+ $result = [];
+
+ foreach (array_keys($array) as $key) {
+ if (strpos($key, $prefix) === 0) {
+ array_push($result, $key);
+ }
+ }
+
+ return $result;
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Friendica\Database\Database;
+use Friendica\Util\DateTimeFormat;
+
+/**
+ * Database Cache
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class DatabaseCache extends Cache implements ICache
+{
+ /**
+ * @var Database
+ */
+ private $dba;
+
+ public function __construct(string $hostname, Database $dba)
+ {
+ parent::__construct($hostname);
+
+ $this->dba = $dba;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function getAllKeys($prefix = null)
+ {
+ if (empty($prefix)) {
+ $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
+ } else {
+ $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
+ }
+
+ $stmt = $this->dba->select('cache', ['k'], $where);
+
+ $keys = [];
+ while ($key = $this->dba->fetch($stmt)) {
+ array_push($keys, $key['k']);
+ }
+ $this->dba->close($stmt);
+
+ return $keys;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function get($key)
+ {
+ $cache = $this->dba->selectFirst('cache', ['v'], ['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()]);
+
+ if ($this->dba->isResult($cache)) {
+ $cached = $cache['v'];
+ $value = @unserialize($cached);
+
+ // Only return a value if the serialized value is valid.
+ // We also check if the db entry is a serialized
+ // boolean 'false' value (which we want to return).
+ if ($cached === serialize(false) || $value !== false) {
+ return $value;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ if ($ttl > 0) {
+ $fields = [
+ 'v' => serialize($value),
+ 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'),
+ 'updated' => DateTimeFormat::utcNow()
+ ];
+ } else {
+ $fields = [
+ 'v' => serialize($value),
+ 'expires' => -1,
+ 'updated' => DateTimeFormat::utcNow()
+ ];
+ }
+
+ return $this->dba->update('cache', $fields, ['k' => $key], true);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function delete($key)
+ {
+ return $this->dba->delete('cache', ['k' => $key]);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function clear($outdated = true)
+ {
+ if ($outdated) {
+ return $this->dba->delete('cache', ['`expires` < NOW()']);
+ } else {
+ return $this->dba->delete('cache', ['`k` IS NOT NULL ']);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName()
+ {
+ return self::TYPE_DATABASE;
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Core\Cache;
-use Friendica\Database\DBA;
-use Friendica\Util\DateTimeFormat;
-
-/**
- * Database Cache Driver
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver
-{
- /**
- * (@inheritdoc)
- */
- public function getAllKeys($prefix = null)
- {
- if (empty($prefix)) {
- $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
- } else {
- $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
- }
-
- $stmt = DBA::select('cache', ['k'], $where);
-
- $keys = [];
- while ($key = DBA::fetch($stmt)) {
- array_push($keys, $key['k']);
- }
- DBA::close($stmt);
-
- return $keys;
- }
-
- /**
- * (@inheritdoc)
- */
- public function get($key)
- {
- $cache = DBA::selectFirst('cache', ['v'], ['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()]);
-
- if (DBA::isResult($cache)) {
- $cached = $cache['v'];
- $value = @unserialize($cached);
-
- // Only return a value if the serialized value is valid.
- // We also check if the db entry is a serialized
- // boolean 'false' value (which we want to return).
- if ($cached === serialize(false) || $value !== false) {
- return $value;
- }
- }
-
- return null;
- }
-
- /**
- * (@inheritdoc)
- */
- public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
- {
- if ($ttl > 0) {
- $fields = [
- 'v' => serialize($value),
- 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'),
- 'updated' => DateTimeFormat::utcNow()
- ];
- } else {
- $fields = [
- 'v' => serialize($value),
- 'expires' => -1,
- 'updated' => DateTimeFormat::utcNow()
- ];
- }
-
- return DBA::update('cache', $fields, ['k' => $key], true);
- }
-
- /**
- * (@inheritdoc)
- */
- public function delete($key)
- {
- return DBA::delete('cache', ['k' => $key]);
- }
-
- /**
- * (@inheritdoc)
- */
- public function clear($outdated = true)
- {
- if ($outdated) {
- return DBA::delete('cache', ['`expires` < NOW()']);
- } else {
- return DBA::delete('cache', ['`k` IS NOT NULL ']);
- }
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+/**
+ * Cache Interface
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+interface ICache
+{
+ /**
+ * Lists all cache keys
+ *
+ * @param string prefix optional a prefix to search
+ *
+ * @return array Empty if it isn't supported by the cache driver
+ */
+ public function getAllKeys($prefix = null);
+
+ /**
+ * Fetches cached data according to the key
+ *
+ * @param string $key The key to the cached data
+ *
+ * @return mixed Cached $value or "null" if not found
+ */
+ public function get($key);
+
+ /**
+ * Stores data in the cache identified by the key. The input $value can have multiple formats.
+ *
+ * @param string $key The cache key
+ * @param mixed $value The value to store
+ * @param integer $ttl The cache lifespan, must be one of the Cache constants
+ *
+ * @return bool
+ */
+ public function set($key, $value, $ttl = Cache::FIVE_MINUTES);
+
+ /**
+ * Delete a key from the cache
+ *
+ * @param string $key The cache key
+ *
+ * @return bool
+ */
+ public function delete($key);
+
+ /**
+ * Remove outdated data from the cache
+ * @param boolean $outdated just remove outdated values
+ *
+ * @return bool
+ */
+ public function clear($outdated = true);
+
+ /**
+ * Returns the name of the current cache
+ *
+ * @return string
+ */
+ public function getName();
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Core\Cache;
-
-/**
- * Cache Driver Interface
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-interface ICacheDriver
-{
- /**
- * Lists all cache keys
- *
- * @param string prefix optional a prefix to search
- *
- * @return array Empty if it isn't supported by the cache driver
- */
- public function getAllKeys($prefix = null);
-
- /**
- * Fetches cached data according to the key
- *
- * @param string $key The key to the cached data
- *
- * @return mixed Cached $value or "null" if not found
- */
- public function get($key);
-
- /**
- * Stores data in the cache identified by the key. The input $value can have multiple formats.
- *
- * @param string $key The cache key
- * @param mixed $value The value to store
- * @param integer $ttl The cache lifespan, must be one of the Cache constants
- *
- * @return bool
- */
- public function set($key, $value, $ttl = Cache::FIVE_MINUTES);
-
- /**
- * Delete a key from the cache
- *
- * @param string $key The cache key
- *
- * @return bool
- */
- public function delete($key);
-
- /**
- * Remove outdated data from the cache
- * @param boolean $outdated just remove outdated values
- *
- * @return bool
- */
- public function clear($outdated = true);
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+/**
+ * This interface defines methods for Memory-Caches only
+ *
+ * Interface IMemoryCache
+ *
+ * @package Friendica\Core\Cache
+ */
+interface IMemoryCache extends ICache
+{
+ /**
+ * Sets a value if it's not already stored
+ *
+ * @param string $key The cache key
+ * @param mixed $value The old value we know from the cache
+ * @param int $ttl The cache lifespan, must be one of the Cache constants
+ * @return bool
+ */
+ public function add($key, $value, $ttl = Cache::FIVE_MINUTES);
+
+ /**
+ * Compares if the old value is set and sets the new value
+ *
+ * @param string $key The cache key
+ * @param mixed $oldValue The old value we know from the cache
+ * @param mixed $newValue The new value we want to set
+ * @param int $ttl The cache lifespan, must be one of the Cache constants
+ *
+ * @return bool
+ */
+ public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES);
+
+ /**
+ * Compares if the old value is set and removes it
+ *
+ * @param string $key The cache key
+ * @param mixed $value The old value we know and want to delete
+ * @return bool
+ */
+ public function compareDelete($key, $value);
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Cache;
-use Friendica\Core\Cache;
-
-/**
- * This interface defines methods for Memory-Caches only
- *
- * Interface IMemoryCacheDriver
- *
- * @package Friendica\Core\Cache
- */
-interface IMemoryCacheDriver extends ICacheDriver
-{
- /**
- * Sets a value if it's not already stored
- *
- * @param string $key The cache key
- * @param mixed $value The old value we know from the cache
- * @param int $ttl The cache lifespan, must be one of the Cache constants
- * @return bool
- */
- public function add($key, $value, $ttl = Cache::FIVE_MINUTES);
-
- /**
- * Compares if the old value is set and sets the new value
- *
- * @param string $key The cache key
- * @param mixed $oldValue The old value we know from the cache
- * @param mixed $newValue The new value we want to set
- * @param int $ttl The cache lifespan, must be one of the Cache constants
- *
- * @return bool
- */
- public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES);
-
- /**
- * Compares if the old value is set and removes it
- *
- * @param string $key The cache key
- * @param mixed $value The old value we know and want to delete
- * @return bool
- */
- public function compareDelete($key, $value);
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Exception;
+use Friendica\Core\Config\Configuration;
+use Memcache;
+
+/**
+ * Memcache Cache
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class MemcacheCache extends Cache implements IMemoryCache
+{
+ use TraitCompareSet;
+ use TraitCompareDelete;
+
+ /**
+ * @var Memcache
+ */
+ private $memcache;
+
+ /**
+ * @throws Exception
+ */
+ public function __construct(string $hostname, Configuration $config)
+ {
+ if (!class_exists('Memcache', false)) {
+ throw new Exception('Memcache class isn\'t available');
+ }
+
+ parent::__construct($hostname);
+
+ $this->memcache = new Memcache();
+
+ $memcache_host = $config->get('system', 'memcache_host');
+ $memcache_port = $config->get('system', 'memcache_port');
+
+ if (!$this->memcache->connect($memcache_host, $memcache_port)) {
+ throw new Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function getAllKeys($prefix = null)
+ {
+ $keys = [];
+ $allSlabs = $this->memcache->getExtendedStats('slabs');
+ foreach ($allSlabs as $slabs) {
+ foreach (array_keys($slabs) as $slabId) {
+ $cachedump = $this->memcache->getExtendedStats('cachedump', (int)$slabId);
+ foreach ($cachedump as $key => $arrVal) {
+ if (!is_array($arrVal)) {
+ continue;
+ }
+ $keys = array_merge($keys, array_keys($arrVal));
+ }
+ }
+ }
+
+ $keys = $this->getOriginalKeys($keys);
+
+ return $this->filterArrayKeysByPrefix($keys, $prefix);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function get($key)
+ {
+ $return = null;
+ $cachekey = $this->getCacheKey($key);
+
+ // We fetch with the hostname as key to avoid problems with other applications
+ $cached = $this->memcache->get($cachekey);
+
+ // @see http://php.net/manual/en/memcache.get.php#84275
+ if (is_bool($cached) || is_double($cached) || is_long($cached)) {
+ return $return;
+ }
+
+ $value = @unserialize($cached);
+
+ // Only return a value if the serialized value is valid.
+ // We also check if the db entry is a serialized
+ // boolean 'false' value (which we want to return).
+ if ($cached === serialize(false) || $value !== false) {
+ $return = $value;
+ }
+
+ return $return;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ $cachekey = $this->getCacheKey($key);
+
+ // We store with the hostname as key to avoid problems with other applications
+ if ($ttl > 0) {
+ return $this->memcache->set(
+ $cachekey,
+ serialize($value),
+ MEMCACHE_COMPRESSED,
+ time() + $ttl
+ );
+ } else {
+ return $this->memcache->set(
+ $cachekey,
+ serialize($value),
+ MEMCACHE_COMPRESSED
+ );
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function delete($key)
+ {
+ $cachekey = $this->getCacheKey($key);
+ return $this->memcache->delete($cachekey);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function clear($outdated = true)
+ {
+ if ($outdated) {
+ return true;
+ } else {
+ return $this->memcache->flush();
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ $cachekey = $this->getCacheKey($key);
+ return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName()
+ {
+ return self::TYPE_MEMCACHE;
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Core\Cache;
-
-use Exception;
-use Memcache;
-
-/**
- * Memcache Cache Driver
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
-{
- use TraitCompareSet;
- use TraitCompareDelete;
-
- /**
- * @var Memcache
- */
- private $memcache;
-
- /**
- * @param string $memcache_host
- * @param int $memcache_port
- * @throws Exception
- */
- public function __construct($memcache_host, $memcache_port)
- {
- if (!class_exists('Memcache', false)) {
- throw new Exception('Memcache class isn\'t available');
- }
-
- $this->memcache = new Memcache();
-
- if (!$this->memcache->connect($memcache_host, $memcache_port)) {
- throw new Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function getAllKeys($prefix = null)
- {
- $keys = [];
- $allSlabs = $this->memcache->getExtendedStats('slabs');
- foreach ($allSlabs as $slabs) {
- foreach (array_keys($slabs) as $slabId) {
- $cachedump = $this->memcache->getExtendedStats('cachedump', (int)$slabId);
- foreach ($cachedump as $key => $arrVal) {
- if (!is_array($arrVal)) {
- continue;
- }
- $keys = array_merge($keys, array_keys($arrVal));
- }
- }
- }
-
- $keys = $this->getOriginalKeys($keys);
-
- return $this->filterArrayKeysByPrefix($keys, $prefix);
- }
-
- /**
- * (@inheritdoc)
- */
- public function get($key)
- {
- $return = null;
- $cachekey = $this->getCacheKey($key);
-
- // We fetch with the hostname as key to avoid problems with other applications
- $cached = $this->memcache->get($cachekey);
-
- // @see http://php.net/manual/en/memcache.get.php#84275
- if (is_bool($cached) || is_double($cached) || is_long($cached)) {
- return $return;
- }
-
- $value = @unserialize($cached);
-
- // Only return a value if the serialized value is valid.
- // We also check if the db entry is a serialized
- // boolean 'false' value (which we want to return).
- if ($cached === serialize(false) || $value !== false) {
- $return = $value;
- }
-
- return $return;
- }
-
- /**
- * (@inheritdoc)
- */
- public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
- {
- $cachekey = $this->getCacheKey($key);
-
- // We store with the hostname as key to avoid problems with other applications
- if ($ttl > 0) {
- return $this->memcache->set(
- $cachekey,
- serialize($value),
- MEMCACHE_COMPRESSED,
- time() + $ttl
- );
- } else {
- return $this->memcache->set(
- $cachekey,
- serialize($value),
- MEMCACHE_COMPRESSED
- );
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function delete($key)
- {
- $cachekey = $this->getCacheKey($key);
- return $this->memcache->delete($cachekey);
- }
-
- /**
- * (@inheritdoc)
- */
- public function clear($outdated = true)
- {
- if ($outdated) {
- return true;
- } else {
- return $this->memcache->flush();
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
- {
- $cachekey = $this->getCacheKey($key);
- return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Exception;
+use Friendica\Core\Config\Configuration;
+use Memcached;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Memcached Cache
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class MemcachedCache extends Cache implements IMemoryCache
+{
+ use TraitCompareSet;
+ use TraitCompareDelete;
+
+ /**
+ * @var \Memcached
+ */
+ private $memcached;
+
+ /**
+ * @var LoggerInterface
+ */
+ private $logger;
+
+ /**
+ * Due to limitations of the INI format, the expected configuration for Memcached servers is the following:
+ * array {
+ * 0 => "hostname, port(, weight)",
+ * 1 => ...
+ * }
+ *
+ * @param array $memcached_hosts
+ *
+ * @throws \Exception
+ */
+ public function __construct(string $hostname, Configuration $config, LoggerInterface $logger)
+ {
+ if (!class_exists('Memcached', false)) {
+ throw new Exception('Memcached class isn\'t available');
+ }
+
+ parent::__construct($hostname);
+
+ $this->logger = $logger;
+
+ $this->memcached = new Memcached();
+
+ $memcached_hosts = $config->get('system', 'memcached_hosts');
+
+ array_walk($memcached_hosts, function (&$value) {
+ if (is_string($value)) {
+ $value = array_map('trim', explode(',', $value));
+ }
+ });
+
+ $this->memcached->addServers($memcached_hosts);
+
+ if (count($this->memcached->getServerList()) == 0) {
+ throw new Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true));
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function getAllKeys($prefix = null)
+ {
+ $keys = $this->getOriginalKeys($this->memcached->getAllKeys());
+
+ if ($this->memcached->getResultCode() == Memcached::RES_SUCCESS) {
+ return $this->filterArrayKeysByPrefix($keys, $prefix);
+ } else {
+ $this->logger->debug('Memcached \'getAllKeys\' failed', ['result' => $this->memcached->getResultMessage()]);
+ return [];
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function get($key)
+ {
+ $return = null;
+ $cachekey = $this->getCacheKey($key);
+
+ // We fetch with the hostname as key to avoid problems with other applications
+ $value = $this->memcached->get($cachekey);
+
+ if ($this->memcached->getResultCode() === Memcached::RES_SUCCESS) {
+ $return = $value;
+ } else {
+ $this->logger->debug('Memcached \'get\' failed', ['result' => $this->memcached->getResultMessage()]);
+ }
+
+ return $return;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ $cachekey = $this->getCacheKey($key);
+
+ // We store with the hostname as key to avoid problems with other applications
+ if ($ttl > 0) {
+ return $this->memcached->set(
+ $cachekey,
+ $value,
+ $ttl
+ );
+ } else {
+ return $this->memcached->set(
+ $cachekey,
+ $value
+ );
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function delete($key)
+ {
+ $cachekey = $this->getCacheKey($key);
+ return $this->memcached->delete($cachekey);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function clear($outdated = true)
+ {
+ if ($outdated) {
+ return true;
+ } else {
+ return $this->memcached->flush();
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ $cachekey = $this->getCacheKey($key);
+ return $this->memcached->add($cachekey, $value, $ttl);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName()
+ {
+ return self::TYPE_MEMCACHED;
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Cache;
-
-use Friendica\Core\Cache;
-use Friendica\Core\Logger;
-
-use Exception;
-use Memcached;
-
-/**
- * Memcached Cache Driver
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
-{
- use TraitCompareSet;
- use TraitCompareDelete;
-
- /**
- * @var \Memcached
- */
- private $memcached;
-
- /**
- * Due to limitations of the INI format, the expected configuration for Memcached servers is the following:
- * array {
- * 0 => "hostname, port(, weight)",
- * 1 => ...
- * }
- *
- * @param array $memcached_hosts
- * @throws \Exception
- */
- public function __construct(array $memcached_hosts)
- {
- if (!class_exists('Memcached', false)) {
- throw new Exception('Memcached class isn\'t available');
- }
-
- $this->memcached = new Memcached();
-
- array_walk($memcached_hosts, function (&$value) {
- if (is_string($value)) {
- $value = array_map('trim', explode(',', $value));
- }
- });
-
- $this->memcached->addServers($memcached_hosts);
-
- if (count($this->memcached->getServerList()) == 0) {
- throw new Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true));
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function getAllKeys($prefix = null)
- {
- $keys = $this->getOriginalKeys($this->memcached->getAllKeys());
-
- if ($this->memcached->getResultCode() == Memcached::RES_SUCCESS) {
- return $this->filterArrayKeysByPrefix($keys, $prefix);
- } else {
- Logger::log('Memcached \'getAllKeys\' failed with ' . $this->memcached->getResultMessage(), Logger::ALL);
- return [];
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function get($key)
- {
- $return = null;
- $cachekey = $this->getCacheKey($key);
-
- // We fetch with the hostname as key to avoid problems with other applications
- $value = $this->memcached->get($cachekey);
-
- if ($this->memcached->getResultCode() === Memcached::RES_SUCCESS) {
- $return = $value;
- } else {
- Logger::log('Memcached \'get\' failed with ' . $this->memcached->getResultMessage(), Logger::ALL);
- }
-
- return $return;
- }
-
- /**
- * (@inheritdoc)
- */
- public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
- {
- $cachekey = $this->getCacheKey($key);
-
- // We store with the hostname as key to avoid problems with other applications
- if ($ttl > 0) {
- return $this->memcached->set(
- $cachekey,
- $value,
- $ttl
- );
- } else {
- return $this->memcached->set(
- $cachekey,
- $value
- );
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function delete($key)
- {
- $cachekey = $this->getCacheKey($key);
- return $this->memcached->delete($cachekey);
- }
-
- /**
- * (@inheritdoc)
- */
- public function clear($outdated = true)
- {
- if ($outdated) {
- return true;
- } else {
- return $this->memcached->flush();
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
- {
- $cachekey = $this->getCacheKey($key);
- return $this->memcached->add($cachekey, $value, $ttl);
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Friendica\Core\System;
+use Friendica\Util\Profiler;
+
+/**
+ * This class wraps cache driver so they can get profiled - in case the profiler is enabled
+ *
+ * It is using the decorator pattern (@see
+ */
+class ProfilerCache implements ICache, IMemoryCache
+{
+ /**
+ * @var ICache The original cache driver
+ */
+ private $cache;
+
+ /**
+ * @var Profiler The profiler of Friendica
+ */
+ private $profiler;
+
+ public function __construct(ICache $cache, Profiler $profiler)
+ {
+ $this->cache = $cache;
+ $this->profiler = $profiler;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAllKeys($prefix = null)
+ {
+ $time = microtime(true);
+
+ $return = $this->cache->getAllKeys($prefix);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function get($key)
+ {
+ $time = microtime(true);
+
+ $return = $this->cache->get($key);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ $time = microtime(true);
+
+ $return = $this->cache->set($key, $value, $ttl);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function delete($key)
+ {
+ $time = microtime(true);
+
+ $return = $this->cache->delete($key);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clear($outdated = true)
+ {
+ $time = microtime(true);
+
+ $return = $this->cache->clear($outdated);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ if ($this->cache instanceof IMemoryCache) {
+ $time = microtime(true);
+
+ $return = $this->cache->add($key, $value, $ttl);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES)
+ {
+ if ($this->cache instanceof IMemoryCache) {
+ $time = microtime(true);
+
+ $return = $this->cache->compareSet($key, $oldValue, $newValue, $ttl);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function compareDelete($key, $value)
+ {
+ if ($this->cache instanceof IMemoryCache) {
+ $time = microtime(true);
+
+ $return = $this->cache->compareDelete($key, $value);
+
+ $this->profiler->saveTimestamp($time, 'cache', System::callstack());
+
+ return $return;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function GetName()
+ {
+ return $this->cache->getName() . ' (with profiler)';
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Exception;
+use Friendica\Core\Config\Configuration;
+use Redis;
+
+/**
+ * Redis Cache. This driver is based on Memcache driver
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ * @author Roland Haeder <roland@mxchange.org>
+ */
+class RedisCache extends Cache implements IMemoryCache
+{
+ /**
+ * @var Redis
+ */
+ private $redis;
+
+ /**
+ * @throws Exception
+ */
+ public function __construct(string $hostname, Configuration $config)
+ {
+ if (!class_exists('Redis', false)) {
+ throw new Exception('Redis class isn\'t available');
+ }
+
+ parent::__construct($hostname);
+
+ $this->redis = new Redis();
+
+ $redis_host = $config->get('system', 'redis_host');
+ $redis_port = $config->get('system', 'redis_port');
+ $redis_pw = $config->get('system', 'redis_password');
+ $redis_db = $config->get('system', 'redis_db', 0);
+
+ if (!$this->redis->connect($redis_host, $redis_port)) {
+ throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
+ }
+
+ if (isset($redis_pw) && !$this->redis->auth($redis_pw)) {
+ throw new Exception('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port);
+ }
+
+ if ($redis_db !== 0 && !$this->redis->select($redis_db)) {
+ throw new Exception('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port);
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function getAllKeys($prefix = null)
+ {
+ if (empty($prefix)) {
+ $search = '*';
+ } else {
+ $search = $prefix . '*';
+ }
+
+ $list = $this->redis->keys($this->getCacheKey($search));
+
+ return $this->getOriginalKeys($list);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function get($key)
+ {
+ $return = null;
+ $cachekey = $this->getCacheKey($key);
+
+ $cached = $this->redis->get($cachekey);
+ if ($cached === false && !$this->redis->exists($cachekey)) {
+ return null;
+ }
+
+ $value = unserialize($cached);
+
+ // Only return a value if the serialized value is valid.
+ // We also check if the db entry is a serialized
+ // boolean 'false' value (which we want to return).
+ if ($cached === serialize(false) || $value !== false) {
+ $return = $value;
+ }
+
+ return $return;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ $cachekey = $this->getCacheKey($key);
+
+ $cached = serialize($value);
+
+ if ($ttl > 0) {
+ return $this->redis->setex(
+ $cachekey,
+ $ttl,
+ $cached
+ );
+ } else {
+ return $this->redis->set(
+ $cachekey,
+ $cached
+ );
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function delete($key)
+ {
+ $cachekey = $this->getCacheKey($key);
+ return ($this->redis->delete($cachekey) > 0);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function clear($outdated = true)
+ {
+ if ($outdated) {
+ return true;
+ } else {
+ return $this->redis->flushAll();
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
+ {
+ $cachekey = $this->getCacheKey($key);
+ $cached = serialize($value);
+
+ return $this->redis->setnx($cachekey, $cached);
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES)
+ {
+ $cachekey = $this->getCacheKey($key);
+
+ $newCached = serialize($newValue);
+
+ $this->redis->watch($cachekey);
+ // If the old value isn't what we expected, somebody else changed the key meanwhile
+ if ($this->get($key) === $oldValue) {
+ if ($ttl > 0) {
+ $result = $this->redis->multi()
+ ->setex($cachekey, $ttl, $newCached)
+ ->exec();
+ } else {
+ $result = $this->redis->multi()
+ ->set($cachekey, $newCached)
+ ->exec();
+ }
+ return $result !== false;
+ }
+ $this->redis->unwatch();
+ return false;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function compareDelete($key, $value)
+ {
+ $cachekey = $this->getCacheKey($key);
+
+ $this->redis->watch($cachekey);
+ // If the old value isn't what we expected, somebody else changed the key meanwhile
+ if ($this->get($key) === $value) {
+ $result = $this->redis->multi()
+ ->del($cachekey)
+ ->exec();
+ return $result !== false;
+ }
+ $this->redis->unwatch();
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName()
+ {
+ return self::TYPE_REDIS;
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Cache;
-
-use Exception;
-use Friendica\Core\Cache;
-use Redis;
-
-/**
- * Redis Cache Driver. This driver is based on Memcache driver
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- * @author Roland Haeder <roland@mxchange.org>
- */
-class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver
-{
- /**
- * @var Redis
- */
- private $redis;
-
- /**
- * @param string $redis_host
- * @param int $redis_port
- * @param int $redis_db (Default = 0, maximum is 15)
- * @param string? $redis_pw
- * @throws Exception
- */
- public function __construct($redis_host, $redis_port, $redis_db = 0, $redis_pw = null)
- {
- if (!class_exists('Redis', false)) {
- throw new Exception('Redis class isn\'t available');
- }
-
- $this->redis = new Redis();
-
- if (!$this->redis->connect($redis_host, $redis_port)) {
- throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
- }
-
- if (isset($redis_pw) && !$this->redis->auth($redis_pw)) {
- throw new Exception('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port);
- }
-
- if ($redis_db !== 0 && !$this->redis->select($redis_db)) {
- throw new Exception('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port);
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function getAllKeys($prefix = null)
- {
- if (empty($prefix)) {
- $search = '*';
- } else {
- $search = $prefix . '*';
- }
-
- $list = $this->redis->keys($this->getCacheKey($search));
-
- return $this->getOriginalKeys($list);
- }
-
- /**
- * (@inheritdoc)
- */
- public function get($key)
- {
- $return = null;
- $cachekey = $this->getCacheKey($key);
-
- $cached = $this->redis->get($cachekey);
- if ($cached === false && !$this->redis->exists($cachekey)) {
- return null;
- }
-
- $value = unserialize($cached);
-
- // Only return a value if the serialized value is valid.
- // We also check if the db entry is a serialized
- // boolean 'false' value (which we want to return).
- if ($cached === serialize(false) || $value !== false) {
- $return = $value;
- }
-
- return $return;
- }
-
- /**
- * (@inheritdoc)
- */
- public function set($key, $value, $ttl = Cache::FIVE_MINUTES)
- {
- $cachekey = $this->getCacheKey($key);
-
- $cached = serialize($value);
-
- if ($ttl > 0) {
- return $this->redis->setex(
- $cachekey,
- $ttl,
- $cached
- );
- } else {
- return $this->redis->set(
- $cachekey,
- $cached
- );
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function delete($key)
- {
- $cachekey = $this->getCacheKey($key);
- return ($this->redis->delete($cachekey) > 0);
- }
-
- /**
- * (@inheritdoc)
- */
- public function clear($outdated = true)
- {
- if ($outdated) {
- return true;
- } else {
- return $this->redis->flushAll();
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function add($key, $value, $ttl = Cache::FIVE_MINUTES)
- {
- $cachekey = $this->getCacheKey($key);
- $cached = serialize($value);
-
- return $this->redis->setnx($cachekey, $cached);
- }
-
- /**
- * (@inheritdoc)
- */
- public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES)
- {
- $cachekey = $this->getCacheKey($key);
-
- $newCached = serialize($newValue);
-
- $this->redis->watch($cachekey);
- // If the old value isn't what we expected, somebody else changed the key meanwhile
- if ($this->get($key) === $oldValue) {
- if ($ttl > 0) {
- $result = $this->redis->multi()
- ->setex($cachekey, $ttl, $newCached)
- ->exec();
- } else {
- $result = $this->redis->multi()
- ->set($cachekey, $newCached)
- ->exec();
- }
- return $result !== false;
- }
- $this->redis->unwatch();
- return false;
- }
-
- /**
- * (@inheritdoc)
- */
- public function compareDelete($key, $value)
- {
- $cachekey = $this->getCacheKey($key);
-
- $this->redis->watch($cachekey);
- // If the old value isn't what we expected, somebody else changed the key meanwhile
- if ($this->get($key) === $value) {
- $result = $this->redis->multi()
- ->del($cachekey)
- ->exec();
- return $result !== false;
- }
- $this->redis->unwatch();
- return false;
- }
-}
namespace Friendica\Core\Cache;
-use Friendica\Core\Cache;
-
/**
* Trait TraitCompareSetDelete
*
namespace Friendica\Core\Cache;
-use Friendica\Core\Cache;
-
/**
* Trait TraitCompareSetDelete
*
namespace Friendica\Core;
-use Friendica\Factory\CacheDriverFactory;
-use Friendica\Core\Cache\IMemoryCacheDriver;
+use Friendica\BaseObject;
+use Friendica\Core\Cache\Cache;
+use Friendica\Core\Lock\ILock;
/**
- * @brief This class contain Functions for preventing parallel execution of functions
+ * This class contain Functions for preventing parallel execution of functions
*/
-class Lock
+class Lock extends BaseObject
{
- /**
- * @var Lock\ILockDriver;
- */
- static $driver = null;
-
- public static function init()
- {
- $lock_driver = Config::get('system', 'lock_driver', 'default');
-
- try {
- switch ($lock_driver) {
- case 'memcache':
- case 'memcached':
- case 'redis':
- $cache_driver = CacheDriverFactory::create($lock_driver);
- if ($cache_driver instanceof IMemoryCacheDriver) {
- self::$driver = new Lock\CacheLockDriver($cache_driver);
- }
- break;
-
- case 'database':
- self::$driver = new Lock\DatabaseLockDriver();
- break;
-
- case 'semaphore':
- self::$driver = new Lock\SemaphoreLockDriver();
- break;
-
- default:
- self::useAutoDriver();
- }
- } catch (\Exception $exception) {
- Logger::log('Driver \'' . $lock_driver . '\' failed - Fallback to \'useAutoDriver()\'');
- self::useAutoDriver();
- }
- }
-
- /**
- * @brief This method tries to find the best - local - locking method for Friendica
- *
- * The following sequence will be tried:
- * 1. Semaphore Locking
- * 2. Cache Locking
- * 3. Database Locking
- *
- */
- private static function useAutoDriver() {
-
- // 1. Try to use Semaphores for - local - locking
- if (function_exists('sem_get')) {
- try {
- self::$driver = new Lock\SemaphoreLockDriver();
- return;
- } catch (\Exception $exception) {
- Logger::log('Using Semaphore driver for locking failed: ' . $exception->getMessage());
- }
- }
-
- // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
- $cache_driver = Config::get('system', 'cache_driver', 'database');
- if ($cache_driver != 'database') {
- try {
- $lock_driver = CacheDriverFactory::create($cache_driver);
- if ($lock_driver instanceof IMemoryCacheDriver) {
- self::$driver = new Lock\CacheLockDriver($lock_driver);
- }
- return;
- } catch (\Exception $exception) {
- Logger::log('Using Cache driver for locking failed: ' . $exception->getMessage());
- }
- }
-
- // 3. Use Database Locking as a Fallback
- self::$driver = new Lock\DatabaseLockDriver();
- }
-
- /**
- * Returns the current cache driver
- *
- * @return Lock\ILockDriver;
- */
- private static function getDriver()
- {
- if (self::$driver === null) {
- self::init();
- }
-
- return self::$driver;
- }
-
/**
* @brief Acquires a lock for a given name
*
- * @param string $key Name of the lock
+ * @param string $key Name of the lock
* @param integer $timeout Seconds until we give up
- * @param integer $ttl The Lock lifespan, must be one of the Cache constants
+ * @param integer $ttl The Lock lifespan, must be one of the Cache constants
*
* @return boolean Was the lock successful?
+ * @throws \Exception
*/
public static function acquire($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
{
- return self::getDriver()->acquireLock($key, $timeout, $ttl);
+ return self::getClass(ILock::class)->acquireLock($key, $timeout, $ttl);
}
/**
*
* @param string $key Name of the lock
* @param bool $override Overrides the lock to get releases
+ *
* @return void
+ * @throws \Exception
*/
public static function release($key, $override = false)
{
- self::getDriver()->releaseLock($key, $override);
+ return self::getClass(ILock::class)->releaseLock($key, $override);
}
/**
* @brief Releases all lock that were set by us
* @return void
+ * @throws \Exception
*/
public static function releaseAll()
{
- self::getDriver()->releaseAll();
+ self::getClass(ILock::class)->releaseAll();
}
}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Lock;
-use Friendica\BaseObject;
-
-/**
- * Class AbstractLockDriver
- *
- * @package Friendica\Core\Lock
- *
- * Basic class for Locking with common functions (local acquired locks, releaseAll, ..)
- */
-abstract class AbstractLockDriver extends BaseObject implements ILockDriver
-{
- /**
- * @var array The local acquired locks
- */
- protected $acquiredLocks = [];
-
- /**
- * Check if we've locally acquired a lock
- *
- * @param string key The Name of the lock
- * @return bool Returns true if the lock is set
- */
- protected function hasAcquiredLock($key)
- {
- return isset($this->acquireLock[$key]) && $this->acquiredLocks[$key] === true;
- }
-
- /**
- * Mark a locally acquired lock
- *
- * @param string $key The Name of the lock
- */
- protected function markAcquire($key)
- {
- $this->acquiredLocks[$key] = true;
- }
-
- /**
- * Mark a release of a locally acquired lock
- *
- * @param string $key The Name of the lock
- */
- protected function markRelease($key)
- {
- unset($this->acquiredLocks[$key]);
- }
-
- /**
- * Releases all lock that were set by us
- *
- * @return boolean Was the unlock of all locks successful?
- */
- public function releaseAll()
- {
- $return = true;
-
- foreach ($this->acquiredLocks as $acquiredLock => $hasLock) {
- if (!$this->releaseLock($acquiredLock)) {
- $return = false;
- }
- }
-
- return $return;
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Lock;
+
+use Friendica\Core\Cache;
+use Friendica\Core\Cache\IMemoryCache;
+
+class CacheLock extends Lock
+{
+ /**
+ * @var \Friendica\Core\Cache\ICache;
+ */
+ private $cache;
+
+ /**
+ * CacheLock constructor.
+ *
+ * @param IMemoryCache $cache The CacheDriver for this type of lock
+ */
+ public function __construct(IMemoryCache $cache)
+ {
+ $this->cache = $cache;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
+ {
+ $got_lock = false;
+ $start = time();
+
+ $cachekey = self::getLockKey($key);
+
+ do {
+ $lock = $this->cache->get($cachekey);
+ // When we do want to lock something that was already locked by us.
+ if ((int)$lock == getmypid()) {
+ $got_lock = true;
+ }
+
+ // When we do want to lock something new
+ if (is_null($lock)) {
+ // At first initialize it with "0"
+ $this->cache->add($cachekey, 0);
+ // Now the value has to be "0" because otherwise the key was used by another process meanwhile
+ if ($this->cache->compareSet($cachekey, 0, getmypid(), $ttl)) {
+ $got_lock = true;
+ $this->markAcquire($key);
+ }
+ }
+
+ if (!$got_lock && ($timeout > 0)) {
+ usleep(rand(10000, 200000));
+ }
+ } while (!$got_lock && ((time() - $start) < $timeout));
+
+ return $got_lock;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function releaseLock($key, $override = false)
+ {
+ $cachekey = self::getLockKey($key);
+
+ if ($override) {
+ $return = $this->cache->delete($cachekey);
+ } else {
+ $return = $this->cache->compareDelete($cachekey, getmypid());
+ }
+ $this->markRelease($key);
+
+ return $return;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function isLocked($key)
+ {
+ $cachekey = self::getLockKey($key);
+ $lock = $this->cache->get($cachekey);
+ return isset($lock) && ($lock !== false);
+ }
+
+ /**
+ * @param string $key The original key
+ *
+ * @return string The cache key used for the cache
+ */
+ private static function getLockKey($key)
+ {
+ return "lock:" . $key;
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Lock;
-
-use Friendica\Core\Cache;
-use Friendica\Core\Cache\IMemoryCacheDriver;
-
-class CacheLockDriver extends AbstractLockDriver
-{
- /**
- * @var \Friendica\Core\Cache\ICacheDriver;
- */
- private $cache;
-
- /**
- * CacheLockDriver constructor.
- *
- * @param IMemoryCacheDriver $cache The CacheDriver for this type of lock
- */
- public function __construct(IMemoryCacheDriver $cache)
- {
- $this->cache = $cache;
- }
-
- /**
- * (@inheritdoc)
- */
- public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
- {
- $got_lock = false;
- $start = time();
-
- $cachekey = self::getLockKey($key);
-
- do {
- $lock = $this->cache->get($cachekey);
- // When we do want to lock something that was already locked by us.
- if ((int)$lock == getmypid()) {
- $got_lock = true;
- }
-
- // When we do want to lock something new
- if (is_null($lock)) {
- // At first initialize it with "0"
- $this->cache->add($cachekey, 0);
- // Now the value has to be "0" because otherwise the key was used by another process meanwhile
- if ($this->cache->compareSet($cachekey, 0, getmypid(), $ttl)) {
- $got_lock = true;
- $this->markAcquire($key);
- }
- }
-
- if (!$got_lock && ($timeout > 0)) {
- usleep(rand(10000, 200000));
- }
- } while (!$got_lock && ((time() - $start) < $timeout));
-
- return $got_lock;
- }
-
- /**
- * (@inheritdoc)
- */
- public function releaseLock($key, $override = false)
- {
- $cachekey = self::getLockKey($key);
-
- $return = false;
-
- if ($override) {
- $return = $this->cache->delete($cachekey);
- } else {
- $return = $this->cache->compareDelete($cachekey, getmypid());
- }
- $this->markRelease($key);
-
- return $return;
- }
-
- /**
- * (@inheritdoc)
- */
- public function isLocked($key)
- {
- $cachekey = self::getLockKey($key);
- $lock = $this->cache->get($cachekey);
- return isset($lock) && ($lock !== false);
- }
-
- /**
- * @param string $key The original key
- * @return string The cache key used for the cache
- */
- private static function getLockKey($key) {
- return "lock:" . $key;
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Lock;
+
+use Friendica\Core\Cache;
+use Friendica\Database\Database;
+use Friendica\Util\DateTimeFormat;
+
+/**
+ * Locking driver that stores the locks in the database
+ */
+class DatabaseLock extends Lock
+{
+ /**
+ * The current ID of the process
+ *
+ * @var int
+ */
+ private $pid;
+
+ /**
+ * @var Database The database connection of Friendica
+ */
+ private $dba;
+
+ /**
+ * @param null|int $pid The Id of the current process (null means determine automatically)
+ */
+ public function __construct(Database $dba, $pid = null)
+ {
+ $this->dba = $dba;
+ $this->pid = isset($pid) ? $pid : getmypid();
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
+ {
+ $got_lock = false;
+ $start = time();
+
+ do {
+ $this->dba->lock('locks');
+ $lock = $this->dba->selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
+
+ if ($this->dba->isResult($lock)) {
+ if ($lock['locked']) {
+ // We want to lock something that was already locked by us? So we got the lock.
+ if ($lock['pid'] == $this->pid) {
+ $got_lock = true;
+ }
+ }
+ if (!$lock['locked']) {
+ $this->dba->update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]);
+ $got_lock = true;
+ }
+ } else {
+ $this->dba->insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]);
+ $got_lock = true;
+ $this->markAcquire($key);
+ }
+
+ $this->dba->unlock();
+
+ if (!$got_lock && ($timeout > 0)) {
+ usleep(rand(100000, 2000000));
+ }
+ } while (!$got_lock && ((time() - $start) < $timeout));
+
+ return $got_lock;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function releaseLock($key, $override = false)
+ {
+ if ($override) {
+ $where = ['name' => $key];
+ } else {
+ $where = ['name' => $key, 'pid' => $this->pid];
+ }
+
+ $return = $this->dba->delete('locks', $where);
+
+ $this->markRelease($key);
+
+ return $return;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function releaseAll()
+ {
+ $return = $this->dba->delete('locks', ['pid' => $this->pid]);
+
+ $this->acquiredLocks = [];
+
+ return $return;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function isLocked($key)
+ {
+ $lock = $this->dba->selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
+
+ if ($this->dba->isResult($lock)) {
+ return $lock['locked'] !== false;
+ } else {
+ return false;
+ }
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Lock;
-
-use Friendica\Core\Cache;
-use Friendica\Database\DBA;
-use Friendica\Util\DateTimeFormat;
-
-/**
- * Locking driver that stores the locks in the database
- */
-class DatabaseLockDriver extends AbstractLockDriver
-{
- /**
- * The current ID of the process
- *
- * @var int
- */
- private $pid;
-
- /**
- * @param null|int $pid The Id of the current process (null means determine automatically)
- */
- public function __construct($pid = null)
- {
- $this->pid = isset($pid) ? $pid : getmypid();
- }
-
- /**
- * (@inheritdoc)
- */
- public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
- {
- $got_lock = false;
- $start = time();
-
- do {
- DBA::lock('locks');
- $lock = DBA::selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
-
- if (DBA::isResult($lock)) {
- if ($lock['locked']) {
- // We want to lock something that was already locked by us? So we got the lock.
- if ($lock['pid'] == $this->pid) {
- $got_lock = true;
- }
- }
- if (!$lock['locked']) {
- DBA::update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]);
- $got_lock = true;
- }
- } else {
- DBA::insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]);
- $got_lock = true;
- $this->markAcquire($key);
- }
-
- DBA::unlock();
-
- if (!$got_lock && ($timeout > 0)) {
- usleep(rand(100000, 2000000));
- }
- } while (!$got_lock && ((time() - $start) < $timeout));
-
- return $got_lock;
- }
-
- /**
- * (@inheritdoc)
- */
- public function releaseLock($key, $override = false)
- {
- if ($override) {
- $where = ['name' => $key];
- } else {
- $where = ['name' => $key, 'pid' => $this->pid];
- }
-
- $return = DBA::delete('locks', $where);
-
- $this->markRelease($key);
-
- return $return;
- }
-
- /**
- * (@inheritdoc)
- */
- public function releaseAll()
- {
- $return = DBA::delete('locks', ['pid' => $this->pid]);
-
- $this->acquiredLocks = [];
-
- return $return;
- }
-
- /**
- * (@inheritdoc)
- */
- public function isLocked($key)
- {
- $lock = DBA::selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
-
- if (DBA::isResult($lock)) {
- return $lock['locked'] !== false;
- } else {
- return false;
- }
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Lock;
+
+use Friendica\Core\Cache;
+
+/**
+ * Lock Interface
+ *
+ * @author Philipp Holzer <admin@philipp.info>
+ */
+interface ILock
+{
+ /**
+ * Checks, if a key is currently locked to a or my process
+ *
+ * @param string $key The name of the lock
+ *
+ * @return bool
+ */
+ public function isLocked($key);
+
+ /**
+ *
+ * Acquires a lock for a given name
+ *
+ * @param string $key The Name of the lock
+ * @param integer $timeout Seconds until we give up
+ * @param integer $ttl Seconds The lock lifespan, must be one of the Cache constants
+ *
+ * @return boolean Was the lock successful?
+ */
+ public function acquireLock($key, $timeout = 120, $ttl = Cache\Cache::FIVE_MINUTES);
+
+ /**
+ * Releases a lock if it was set by us
+ *
+ * @param string $key The Name of the lock
+ * @param bool $override Overrides the lock to get released
+ *
+ * @return boolean Was the unlock successful?
+ */
+ public function releaseLock($key, $override = false);
+
+ /**
+ * Releases all lock that were set by us
+ *
+ * @return boolean Was the unlock of all locks successful?
+ */
+ public function releaseAll();
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Lock;
-use Friendica\Core\Cache;
-
-/**
- * Lock Driver Interface
- *
- * @author Philipp Holzer <admin@philipp.info>
- */
-interface ILockDriver
-{
- /**
- * Checks, if a key is currently locked to a or my process
- *
- * @param string $key The name of the lock
- * @return bool
- */
- public function isLocked($key);
-
- /**
- *
- * Acquires a lock for a given name
- *
- * @param string $key The Name of the lock
- * @param integer $timeout Seconds until we give up
- * @param integer $ttl Seconds The lock lifespan, must be one of the Cache constants
- *
- * @return boolean Was the lock successful?
- */
- public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES);
-
- /**
- * Releases a lock if it was set by us
- *
- * @param string $key The Name of the lock
- * @param bool $override Overrides the lock to get released
- *
- * @return boolean Was the unlock successful?
- */
- public function releaseLock($key, $override = false);
-
- /**
- * Releases all lock that were set by us
- *
- * @return boolean Was the unlock of all locks successful?
- */
- public function releaseAll();
-}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Lock;
+
+/**
+ * Class AbstractLock
+ *
+ * @package Friendica\Core\Lock
+ *
+ * Basic class for Locking with common functions (local acquired locks, releaseAll, ..)
+ */
+abstract class Lock implements ILock
+{
+ /**
+ * @var array The local acquired locks
+ */
+ protected $acquiredLocks = [];
+
+ /**
+ * Check if we've locally acquired a lock
+ *
+ * @param string key The Name of the lock
+ *
+ * @return bool Returns true if the lock is set
+ */
+ protected function hasAcquiredLock($key)
+ {
+ return isset($this->acquireLock[$key]) && $this->acquiredLocks[$key] === true;
+ }
+
+ /**
+ * Mark a locally acquired lock
+ *
+ * @param string $key The Name of the lock
+ */
+ protected function markAcquire($key)
+ {
+ $this->acquiredLocks[$key] = true;
+ }
+
+ /**
+ * Mark a release of a locally acquired lock
+ *
+ * @param string $key The Name of the lock
+ */
+ protected function markRelease($key)
+ {
+ unset($this->acquiredLocks[$key]);
+ }
+
+ /**
+ * Releases all lock that were set by us
+ *
+ * @return boolean Was the unlock of all locks successful?
+ */
+ public function releaseAll()
+ {
+ $return = true;
+
+ foreach ($this->acquiredLocks as $acquiredLock => $hasLock) {
+ if (!$this->releaseLock($acquiredLock)) {
+ $return = false;
+ }
+ }
+
+ return $return;
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Core\Lock;
+
+use Friendica\Core\Cache;
+
+class SemaphoreLock extends Lock
+{
+ private static $semaphore = [];
+
+ public function __construct()
+ {
+ if (!function_exists('sem_get')) {
+ throw new \Exception('Semaphore lock not supported');
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ private static function semaphoreKey($key)
+ {
+ $temp = get_temppath();
+
+ $file = $temp . '/' . $key . '.sem';
+
+ if (!file_exists($file)) {
+ file_put_contents($file, $key);
+ }
+
+ return ftok($file, 'f');
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
+ {
+ self::$semaphore[$key] = sem_get(self::semaphoreKey($key));
+ if (self::$semaphore[$key]) {
+ if (sem_acquire(self::$semaphore[$key], ($timeout == 0))) {
+ $this->markAcquire($key);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function releaseLock($key, $override = false)
+ {
+ if (empty(self::$semaphore[$key])) {
+ return false;
+ } else {
+ $success = @sem_release(self::$semaphore[$key]);
+ unset(self::$semaphore[$key]);
+ $this->markRelease($key);
+ return $success;
+ }
+ }
+
+ /**
+ * (@inheritdoc)
+ */
+ public function isLocked($key)
+ {
+ return isset(self::$semaphore[$key]);
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Lock;
-
-use Friendica\Core\Cache;
-
-class SemaphoreLockDriver extends AbstractLockDriver
-{
- private static $semaphore = [];
-
- public function __construct()
- {
- if (!function_exists('sem_get')) {
- throw new \Exception('Semaphore lock not supported');
- }
- }
-
- /**
- * (@inheritdoc)
- */
- private static function semaphoreKey($key)
- {
- $temp = get_temppath();
-
- $file = $temp . '/' . $key . '.sem';
-
- if (!file_exists($file)) {
- file_put_contents($file, $key);
- }
-
- return ftok($file, 'f');
- }
-
- /**
- * (@inheritdoc)
- */
- public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
- {
- self::$semaphore[$key] = sem_get(self::semaphoreKey($key));
- if (self::$semaphore[$key]) {
- if (sem_acquire(self::$semaphore[$key], ($timeout == 0))) {
- $this->markAcquire($key);
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * (@inheritdoc)
- */
- public function releaseLock($key, $override = false)
- {
- if (empty(self::$semaphore[$key])) {
- return false;
- } else {
- $success = @sem_release(self::$semaphore[$key]);
- unset(self::$semaphore[$key]);
- $this->markRelease($key);
- return $success;
- }
- }
-
- /**
- * (@inheritdoc)
- */
- public function isLocked($key)
- {
- return isset(self::$semaphore[$key]);
- }
-}
use Friendica\BaseObject;
use Friendica\Network\HTTPException\InternalServerErrorException;
+use Friendica\Util\BaseURL;
use Friendica\Util\XML;
/**
*/
public static function baseUrl($ssl = false)
{
- return self::getApp()->getBaseURL($ssl);
+ return self::getClass(BaseURL::class)->get($ssl);
}
/**
+++ /dev/null
-<?php
-
-namespace Friendica\Factory;
-
-use Friendica\Core\Cache;
-use Friendica\Core\Cache\ICacheDriver;
-use Friendica\Core\Config;
-
-/**
- * Class CacheDriverFactory
- *
- * @package Friendica\Core\Cache
- *
- * A basic class to generate a CacheDriver
- */
-class CacheDriverFactory
-{
- /**
- * This method creates a CacheDriver for the given cache driver name
- *
- * @param string $driver The name of the cache driver
- * @return ICacheDriver The instance of the CacheDriver
- * @throws \Exception The exception if something went wrong during the CacheDriver creation
- */
- public static function create($driver) {
-
- switch ($driver) {
- case 'memcache':
- $memcache_host = Config::get('system', 'memcache_host');
- $memcache_port = Config::get('system', 'memcache_port');
-
- return new Cache\MemcacheCacheDriver($memcache_host, $memcache_port);
- break;
-
- case 'memcached':
- $memcached_hosts = Config::get('system', 'memcached_hosts');
-
- return new Cache\MemcachedCacheDriver($memcached_hosts);
- break;
- case 'redis':
- $redis_host = Config::get('system', 'redis_host');
- $redis_port = Config::get('system', 'redis_port');
- $redis_pw = Config::get('system', 'redis_password');
- $redis_db = Config::get('system', 'redis_db', 0);
-
- return new Cache\RedisCacheDriver($redis_host, $redis_port, $redis_db, $redis_pw);
- break;
-
- case 'apcu':
- return new Cache\APCuCache();
- break;
-
- default:
- return new Cache\DatabaseCacheDriver();
- }
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Cache;
+use Friendica\Core\Cache\ICache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Database\Database;
+use Friendica\Util\BaseURL;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class CacheFactory
+ *
+ * @package Friendica\Core\Cache
+ *
+ * A basic class to generate a CacheDriver
+ */
+class CacheFactory
+{
+ /**
+ * @var string The default cache if nothing set
+ */
+ const DEFAULT_TYPE = Cache\Cache::TYPE_DATABASE;
+
+ /**
+ * @var Configuration The configuration 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, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
+ {
+ $this->hostname = $baseURL->getHostname();
+ $this->config = $config;
+ $this->dba = $dba;
+ $this->profiler = $profiler;
+ $this->logger = $logger;
+ }
+
+ /**
+ * This method creates a CacheDriver for the given cache driver name
+ *
+ * @param string $type The cache type to create (default is per config)
+ *
+ * @return ICache The instance of the CacheDriver
+ * @throws \Exception The exception if something went wrong during the CacheDriver creation
+ */
+ public function create(string $type = null)
+ {
+ if (empty($type)) {
+ $type = $this->config->get('system', 'cache_driver', self::DEFAULT_TYPE);
+ }
+
+ switch ($type) {
+ case Cache\Cache::TYPE_MEMCACHE:
+ $cache = new Cache\MemcacheCache($this->hostname, $this->config);
+ break;
+ case Cache\Cache::TYPE_MEMCACHED:
+ $cache = new Cache\MemcachedCache($this->hostname, $this->config, $this->logger);
+ break;
+ case Cache\Cache::TYPE_REDIS:
+ $cache = new Cache\RedisCache($this->hostname, $this->config);
+ break;
+ case Cache\Cache::TYPE_APCU:
+ $cache = new Cache\APCuCache($this->hostname);
+ break;
+ default:
+ $cache = new Cache\DatabaseCache($this->hostname, $this->dba);
+ }
+
+ $profiling = $this->config->get('system', 'profiling', false);
+
+ // In case profiling is enabled, wrap the ProfilerCache around the current cache
+ if (isset($profiling) && $profiling !== false) {
+ return new Cache\ProfilerCache($cache, $this->profiler);
+ } else {
+ return $cache;
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Cache\Cache;
+use Friendica\Core\Cache\IMemoryCache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Lock;
+use Friendica\Database\Database;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class LockFactory
+ *
+ * @package Friendica\Core\Cache
+ *
+ * A basic class to generate a LockDriver
+ */
+class LockFactory
+{
+ /**
+ * @var string The default driver for caching
+ */
+ const DEFAULT_DRIVER = 'default';
+
+ /**
+ * @var Configuration The configuration 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 CacheFactory The memory cache driver in case we use it
+ */
+ private $cacheFactory;
+
+ /**
+ * @var Profiler The optional profiler if the cached should be profiled
+ */
+ private $profiler;
+
+ /**
+ * @var LoggerInterface The Friendica Logger
+ */
+ private $logger;
+
+ public function __construct(CacheFactory $cacheFactory, Configuration $config, Database $dba, Profiler $profiler, LoggerInterface $logger)
+ {
+ $this->cacheFactory = $cacheFactory;
+ $this->config = $config;
+ $this->dba = $dba;
+ $this->logger = $logger;
+ }
+
+ public function create()
+ {
+ $lock_type = $this->config->get('system', 'lock_driver', self::DEFAULT_DRIVER);
+
+ try {
+ switch ($lock_type) {
+ case Cache::TYPE_MEMCACHE:
+ case Cache::TYPE_MEMCACHED:
+ case Cache::TYPE_REDIS:
+ case Cache::TYPE_APCU:
+ $cache = $this->cacheFactory->create($lock_type);
+ if ($cache instanceof IMemoryCache) {
+ return new Lock\CacheLock($cache);
+ } else {
+ throw new \Exception(sprintf('Incompatible cache driver \'%s\' for lock used', $lock_type));
+ }
+ break;
+
+ case 'database':
+ return new Lock\DatabaseLock($this->dba);
+ break;
+
+ case 'semaphore':
+ return new Lock\SemaphoreLock();
+ break;
+
+ default:
+ return self::useAutoDriver();
+ }
+ } catch (\Exception $exception) {
+ $this->logger->alert('Driver \'' . $lock_type . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]);
+ return self::useAutoDriver();
+ }
+ }
+
+ /**
+ * @brief This method tries to find the best - local - locking method for Friendica
+ *
+ * The following sequence will be tried:
+ * 1. Semaphore Locking
+ * 2. Cache Locking
+ * 3. Database Locking
+ *
+ * @return Lock\ILock
+ */
+ private function useAutoDriver()
+ {
+ // 1. Try to use Semaphores for - local - locking
+ if (function_exists('sem_get')) {
+ try {
+ return new Lock\SemaphoreLock();
+ } catch (\Exception $exception) {
+ $this->logger->debug('Using Semaphore driver for locking failed.', ['exception' => $exception]);
+ }
+ }
+
+ // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
+ $cache_type = $this->config->get('system', 'cache_driver', 'database');
+ if ($cache_type != Cache::TYPE_DATABASE) {
+ try {
+ $cache = $this->cacheFactory->create($cache_type);
+ if ($cache instanceof IMemoryCache) {
+ return new Lock\CacheLock($cache);
+ }
+ } catch (\Exception $exception) {
+ $this->logger->debug('Using Cache driver for locking failed.', ['exception' => $exception]);
+ }
+ }
+
+ // 3. Use Database Locking as a Fallback
+ return new Lock\DatabaseLock($this->dba);
+ }
+}
use Dice\Dice;
use Friendica\App;
+use Friendica\Core\Cache;
use Friendica\Core\Config;
+use Friendica\Core\Lock\ILock;
use Friendica\Database\Database;
use Friendica\Factory;
use Friendica\Util;
* $app = $dice->create(App::class, [], ['$channel' => 'index']);
* and is automatically passed as an argument with the same name
*/
- LoggerInterface::class => [
+ LoggerInterface::class => [
'instanceOf' => Factory\LoggerFactory::class,
'call' => [
['create', [], Dice::CHAIN_CALL],
],
],
- '$devLogger' => [
+ '$devLogger' => [
'instanceOf' => Factory\LoggerFactory::class,
'call' => [
['createDev', [], Dice::CHAIN_CALL],
]
],
+ Cache\ICache::class => [
+ 'instanceOf' => Factory\CacheFactory::class,
+ 'call' => [
+ ['create', [], Dice::CHAIN_CALL],
+ ],
+ ],
+ Cache\IMemoryCache::class => [
+ 'instanceOf' => Factory\CacheFactory::class,
+ 'call' => [
+ ['create', [], Dice::CHAIN_CALL],
+ ],
+ ],
+ ILock::class => [
+ 'instanceOf' => Factory\LockFactory::class,
+ 'call' => [
+ ['create', [], Dice::CHAIN_CALL],
+ ],
+ ],
];
namespace Friendica\Test;
-use Friendica\Database\Database;
-use Friendica\Test\Util\Database\StaticDatabase;
-
/**
* Abstract class used by tests that need a database.
*/
abstract class DatabaseTest extends MockedTest
{
- protected function setUp()
- {
- parent::setUp();
-
- StaticDatabase::statConnect($_SERVER);
- // Rollbacks every DB usage (in case the test couldn't call tearDown)
- StaticDatabase::statRollback();
- // Start the first, outer transaction
- StaticDatabase::getGlobConnection()->beginTransaction();
- }
-
- protected function tearDown()
- {
- // Rollbacks every DB usage so we don't commit anything into the DB
- StaticDatabase::statRollback();
-
- parent::tearDown();
- }
-
- /**
- * Loads a given DB fixture for this DB test
- *
- * @param string $fixture The path to the fixture
- * @param Database $dba The DB connection
- *
- * @throws \Exception
- */
- protected function loadFixture(string $fixture, Database $dba)
- {
- $this->assertFileExists($fixture);
-
- $data = include $fixture;
-
- foreach ($data as $tableName => $rows) {
- if (!is_array($rows)) {
- $dba->p('TRUNCATE TABLE `' . $tableName . '``');
- continue;
- }
-
- foreach ($rows as $row) {
- $dba->insert($tableName, $row);
- }
- }
- }
+ use DatabaseTestTrait;
}
--- /dev/null
+<?php
+/**
+ * DatabaseTest class.
+ */
+
+namespace Friendica\Test;
+
+use Friendica\Database\Database;
+use Friendica\Test\Util\Database\StaticDatabase;
+
+/**
+ * Abstract class used by tests that need a database.
+ */
+trait DatabaseTestTrait
+{
+ protected function setUp()
+ {
+ StaticDatabase::statConnect($_SERVER);
+ // Rollbacks every DB usage (in case the test couldn't call tearDown)
+ StaticDatabase::statRollback();
+ // Start the first, outer transaction
+ StaticDatabase::getGlobConnection()->beginTransaction();
+
+ parent::setUp();
+ }
+
+ protected function tearDown()
+ {
+ // Rollbacks every DB usage so we don't commit anything into the DB
+ StaticDatabase::statRollback();
+
+ parent::tearDown();
+ }
+
+ /**
+ * Loads a given DB fixture for this DB test
+ *
+ * @param string $fixture The path to the fixture
+ * @param Database $dba The DB connection
+ *
+ * @throws \Exception
+ */
+ protected function loadFixture(string $fixture, Database $dba)
+ {
+ $data = include $fixture;
+
+ foreach ($data as $tableName => $rows) {
+ if (!is_array($rows)) {
+ $dba->p('TRUNCATE TABLE `' . $tableName . '``');
+ continue;
+ }
+
+ foreach ($rows as $row) {
+ $dba->insert($tableName, $row);
+ }
+ }
+ }
+}
trait DbaCacheMockTrait
{
- use DBAMockTrait;
- use DateTimeFormatMockTrait;
+ /**
+ * @var
+ */
+ protected $dba;
+
+ public function __construct()
+ {
+ }
protected function mockDelete($key, $return = true, $times = null)
{
namespace Friendica\Test\Util;
use Friendica\Core\Cache;
-use Friendica\Core\Lock\DatabaseLockDriver;
+use Friendica\Core\Lock\DatabaseLock;
trait DbaLockMockTrait
{
/**
* Mocking acquireLock with DBA-backend
- * @see DatabaseLockDriver::acquireLock()
*
* @param mixed $key The key to lock
* @param int $ttl The TimeToLive
* @param bool $rowExists True, if a row already exists in the lock table
* @param null $time The current timestamp
* @param null|int $times How often the method will get used
+ *
+ *@see DatabaseLock::acquireLock()
+ *
*/
public function mockAcquireLock($key, $ttl = Cache::FIVE_MINUTES, $locked = false, $pid = null, $rowExists = true, $time = null, $times = null)
{
/**
* Mocking isLocked with DBA-backend
- * @see DatabaseLockDriver::isLocked()
*
* @param mixed $key The key of the lock
* @param null|bool $return True, if the key is already locked
- * @param null $time The current timestamp
+ * @param null $time The current timestamp
* @param null|int $times How often the method will get used
+ *
+ *@see DatabaseLock::isLocked()
+ *
*/
public function mockIsLocked($key, $return = true, $time = null, $times = null)
{
/**
* Mocking releaseAll with DBA-backend
- * @see DatabaseLockDriver::releaseAll()
*
- * @param null $pid The PID which was set
- * @param null|int $times How often the method will get used
+ * @param null $pid The PID which was set
+ * @param null|int $times How often the method will get used
+ *
+ *@see DatabaseLock::releaseAll()
+ *
*/
public function mockReleaseAll($pid = null, $times = null)
{
/**
* Mocking ReleaseLock with DBA-backend
- * @see DatabaseLockDriver::releaseLock()
*
* @param mixed $key The key to release
* @param null|int $pid The PID which was set
* @param null|int $times How often the method will get used
+ *
+ *@see DatabaseLock::releaseLock()
+ *
*/
public function mockReleaseLock($key, $pid = null, $times = null)
{
// create a virtual directory and copy all needed files and folders to it
$this->root = vfsStream::setup('friendica', 0777, $structure);
+ $this->setConfigFile('dbstructure.config.php', true);
$this->setConfigFile('defaults.config.php', true);
$this->setConfigFile('settings.config.php', true);
$this->setConfigFile('local.config.php');
use Dice\Dice;
use Friendica\App;
+use Friendica\Core\Cache\ICache;
+use Friendica\Core\Cache\IMemoryCache;
use Friendica\Core\Config\Cache\ConfigCache;
use Friendica\Core\Config\Configuration;
+use Friendica\Core\Lock\ILock;
use Friendica\Database\Database;
use Friendica\Test\Util\VFSTrait;
use Friendica\Util\BasePath;
$this->setUpVfsDir();
- $this->dice = new Dice();
- $this->dice = $this->dice->addRules(include __DIR__ . '/../../static/dependencies.config.php');
+ $this->dice = (new Dice())
+ ->addRules(include __DIR__ . '/../../static/dependencies.config.php');
}
/**
]);
// create new DI-library because of shared instance rule (so the Profiler wouldn't get created twice)
- $this->dice = new Dice(include __DIR__ . '/../../static/dependencies.config.php');
+ $this->dice = new Dice();
$profiler = $this->dice->create(Profiler::class, [$configCache]);
$this->assertInstanceOf(Profiler::class, $profiler);
/** @var LoggerInterface $logger */
$logger = $this->dice->create('$devLogger', ['dev']);
- self::assertInstanceOf(LoggerInterface::class, $logger);
+ $this->assertInstanceOf(LoggerInterface::class, $logger);
+ }
+
+ public function testCache()
+ {
+ /** @var ICache $cache */
+ $cache = $this->dice->create(ICache::class);
+
+ $this->assertInstanceOf(ICache::class, $cache);
+ }
+
+ public function testMemoryCache()
+ {
+ /** @var IMemoryCache $cache */
+ $cache = $this->dice->create(IMemoryCache::class);
+
+ // We need to check "just" ICache, because the default Cache is DB-Cache, which isn't a memorycache
+ $this->assertInstanceOf(ICache::class, $cache);
+ }
+
+ public function testLock()
+ {
+ /** @var ILock $cache */
+ $lock = $this->dice->create(ILock::class);
+
+ $this->assertInstanceOf(ILock::class, $lock);
}
}
use Dice\Dice;
use Friendica\App;
use Friendica\BaseObject;
-use Friendica\Core\Config;
-use Friendica\Core\PConfig;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Config\PConfiguration;
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Database\Database;
/** @var App */
protected $app;
+ /** @var Configuration */
+ protected $config;
+
+ /** @var Dice */
+ protected $dice;
+
/**
* Create variables used by tests.
*/
{
parent::setUp();
- $dice = new Dice();
- $dice = $dice->addRules(include __DIR__ . '/../../static/dependencies.config.php');
- $dice = $dice->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]);
- BaseObject::setDependencyInjection($dice);
+ $this->dice = (new Dice())
+ ->addRules(include __DIR__ . '/../../static/dependencies.config.php')
+ ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]);
+ BaseObject::setDependencyInjection($this->dice);
/** @var Database $dba */
- $dba = $dice->create(Database::class);
+ $dba = $this->dice->create(Database::class);
+
+ /** @var Configuration $config */
+ $this->config = $this->dice->create(Configuration::class);
+
+ $this->config->set('system', 'url', 'http://localhost');
+ $this->config->set('system', 'hostname', 'localhost');
+ $this->config->set('system', 'worker_dont_fork', true);
+
+ // Default config
+ $this->config->set('config', 'hostname', 'localhost');
+ $this->config->set('system', 'throttle_limit_day', 100);
+ $this->config->set('system', 'throttle_limit_week', 100);
+ $this->config->set('system', 'throttle_limit_month', 100);
+ $this->config->set('system', 'theme', 'system_theme');
// Load the API dataset for the whole API
$this->loadFixture(__DIR__ . '/../datasets/api.fixture.php', $dba);
+ /** @var App app */
$this->app = BaseObject::getApp();
$this->app->argc = 1;
$_POST = [];
$_GET = [];
$_SERVER = [];
-
- Config::set('system', 'url', 'http://localhost');
- Config::set('system', 'hostname', 'localhost');
- Config::set('system', 'worker_dont_fork', true);
-
- // Default config
- Config::set('config', 'hostname', 'localhost');
- Config::set('system', 'throttle_limit_day', 100);
- Config::set('system', 'throttle_limit_week', 100);
- Config::set('system', 'throttle_limit_month', 100);
- Config::set('system', 'theme', 'system_theme');
}
/**
}
];
$_SERVER['REQUEST_METHOD'] = 'method';
- Config::set('system', 'profiler', true);
- Config::set('rendertime', 'callstack', true);
+ $this->config->set('system', 'profiler', true);
+ $this->config->set('rendertime', 'callstack', true);
$this->app->callstack = [
'database' => ['some_function' => 200],
'database_write' => ['some_function' => 200],
*/
public function testApiGetUserWithFrioSchema()
{
- PConfig::set($this->selfUser['id'], 'frio', 'schema', 'red');
+ $pConfig = $this->dice->create(PConfiguration::class);
+ $pConfig->set($this->selfUser['id'], 'frio', 'schema', 'red');
$user = api_get_user($this->app);
$this->assertSelfUser($user);
$this->assertEquals('708fa0', $user['profile_sidebar_fill_color']);
*/
public function testApiGetUserWithCustomFrioSchema()
{
- $ret1 = PConfig::set($this->selfUser['id'], 'frio', 'schema', '---');
- $ret2 = PConfig::set($this->selfUser['id'], 'frio', 'nav_bg', '#123456');
- $ret3 = PConfig::set($this->selfUser['id'], 'frio', 'link_color', '#123456');
- $ret4 = PConfig::set($this->selfUser['id'], 'frio', 'background_color', '#123456');
+ $pConfig = $this->dice->create(PConfiguration::class);
+ $pConfig->set($this->selfUser['id'], 'frio', 'schema', '---');
+ $pConfig->set($this->selfUser['id'], 'frio', 'nav_bg', '#123456');
+ $pConfig->set($this->selfUser['id'], 'frio', 'link_color', '#123456');
+ $pConfig->set($this->selfUser['id'], 'frio', 'background_color', '#123456');
$user = api_get_user($this->app);
$this->assertSelfUser($user);
$this->assertEquals('123456', $user['profile_sidebar_fill_color']);
*/
public function testApiGetUserWithEmptyFrioSchema()
{
- PConfig::set($this->selfUser['id'], 'frio', 'schema', '---');
+ $pConfig = $this->dice->create(PConfiguration::class);
+ $pConfig->set($this->selfUser['id'], 'frio', 'schema', '---');
$user = api_get_user($this->app);
$this->assertSelfUser($user);
$this->assertEquals('708fa0', $user['profile_sidebar_fill_color']);
use Friendica\Test\MockedTest;
use Friendica\Test\Util\AppMockTrait;
use Friendica\Test\Util\VFSTrait;
+use Friendica\Util\BaseURL;
class BBCodeTest extends MockedTest
{
$this->dice->shouldReceive('create')
->with(L10n::class)
->andReturn($l10nMock);
+
+ $baseUrlMock = \Mockery::mock(BaseURL::class);
+ $baseUrlMock->shouldReceive('get')->withAnyArgs()->andReturn('friendica.local');
+ $this->dice->shouldReceive('create')
+ ->with(BaseURL::class)
+ ->andReturn($baseUrlMock);
}
public function dataLinks()
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Cache;
-
-use Friendica\Core\Cache\APCuCache;
-
-class APCuCacheDriverTest extends MemoryCacheTest
-{
- protected function setUp()
- {
- if (!APCuCache::isAvailable()) {
- $this->markTestSkipped('APCu is not available');
- }
-
- parent::setUp();
- }
-
- protected function getInstance()
- {
- $this->cache = new APCuCache();
- return $this->cache;
- }
-
- public function tearDown()
- {
- $this->cache->clear(false);
- parent::tearDown();
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Cache;
+
+use Friendica\Core\Cache\APCuCache;
+
+class APCuCacheTest extends MemoryCacheTest
+{
+ protected function setUp()
+ {
+ if (!APCuCache::isAvailable()) {
+ $this->markTestSkipped('APCu is not available');
+ }
+
+ parent::setUp();
+ }
+
+ protected function getInstance()
+ {
+ $this->cache = new APCuCache('localhost');
+ return $this->cache;
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear(false);
+ parent::tearDown();
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Cache;
-
-use Friendica\Core\Cache\ArrayCache;
-
-class ArrayCacheDriverTest extends MemoryCacheTest
-{
- protected function getInstance()
- {
- $this->cache = new ArrayCache();
- return $this->cache;
- }
-
- public function tearDown()
- {
- $this->cache->clear(false);
- parent::tearDown();
- }
-
- public function testTTL()
- {
- // Array Cache doesn't support TTL
- return true;
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Cache;
+
+use Friendica\Core\Cache\ArrayCache;
+
+class ArrayCacheTest extends MemoryCacheTest
+{
+ protected function getInstance()
+ {
+ $this->cache = new ArrayCache('localhost');
+ return $this->cache;
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear(false);
+ parent::tearDown();
+ }
+
+ public function testTTL()
+ {
+ // Array Cache doesn't support TTL
+ return true;
+ }
+}
namespace Friendica\Test\src\Core\Cache;
-use Friendica\Core\Cache\MemcachedCacheDriver;
+use Friendica\Core\Cache\MemcachedCache;
use Friendica\Test\MockedTest;
-use Friendica\Test\Util\AppMockTrait;
-use Friendica\Test\Util\VFSTrait;
use Friendica\Util\PidFile;
abstract class CacheTest extends MockedTest
{
- use VFSTrait;
- use AppMockTrait;
-
/**
* @var int Start time of the mock (used for time operations)
*/
protected $startTime = 1417011228;
/**
- * @var \Friendica\Core\Cache\ICacheDriver
+ * @var \Friendica\Core\Cache\ICache
*/
protected $instance;
/**
- * @var \Friendica\Core\Cache\IMemoryCacheDriver
+ * @var \Friendica\Core\Cache\IMemoryCache
*/
protected $cache;
/**
* Dataset for test setting different types in the cache
+ *
* @return array
*/
public function dataTypesInCache()
/**
* Dataset for simple value sets/gets
+ *
* @return array
*/
public function dataSimple()
protected function setUp()
{
- $this->setUpVfsDir();
- $this->mockApp($this->root);
- $this->app
- ->shouldReceive('getHostname')
- ->andReturn('friendica.local');
-
parent::setUp();
$this->instance = $this->getInstance();
/**
* @small
* @dataProvider dataSimple
+ *
* @param mixed $value1 a first
* @param mixed $value2 a second
*/
- function testSimple($value1, $value2) {
+ function testSimple($value1, $value2)
+ {
$this->assertNull($this->instance->get('value1'));
$this->instance->set('value1', $value1);
/**
* @small
* @dataProvider dataSimple
+ *
* @param mixed $value1 a first
* @param mixed $value2 a second
* @param mixed $value3 a third
* @param mixed $value4 a fourth
*/
- function testClear($value1, $value2, $value3, $value4) {
+ function testClear($value1, $value2, $value3, $value4)
+ {
$value = 'ipsum lorum';
$this->instance->set('1_value1', $value1);
$this->instance->set('1_value2', $value2);
/**
* @medium
*/
- function testTTL() {
+ function testTTL()
+ {
$this->markTestSkipped('taking too much time without mocking');
$this->assertNull($this->instance->get('value1'));
/**
* @small
+ *
* @param $data mixed the data to store in the cache
+ *
* @dataProvider dataTypesInCache
*/
- function testDifferentTypesInCache($data) {
+ function testDifferentTypesInCache($data)
+ {
$this->instance->set('val', $data);
$received = $this->instance->get('val');
$this->assertEquals($data, $received, 'Value type changed from ' . gettype($data) . ' to ' . gettype($received));
/**
* @small
+ *
* @param mixed $value1 a first
* @param mixed $value2 a second
* @param mixed $value3 a third
+ *
* @dataProvider dataSimple
*/
- public function testGetAllKeys($value1, $value2, $value3) {
- if ($this->cache instanceof MemcachedCacheDriver) {
+ public function testGetAllKeys($value1, $value2, $value3)
+ {
+ if ($this->cache instanceof MemcachedCache) {
$this->markTestSkipped('Memcached doesn\'t support getAllKeys anymore');
}
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Cache;
-
-use Friendica\Core\Cache;
-use Friendica\Factory\CacheDriverFactory;
-use Friendica\Test\Util\DbaCacheMockTrait;
-
-/**
- * @runTestsInSeparateProcesses
- * @preserveGlobalState disabled
- */
-class DatabaseCacheDriverTest extends CacheTest
-{
- use DbaCacheMockTrait;
-
- public function setUp()
- {
- $this->mockUtcNow($this->startTime);
-
- $this->mockConnected();
- $this->mockConnect();
-
- // The first "clear" at setup
- $this->mockClear(false, true, 2);
-
- parent::setUp();
- }
-
- protected function getInstance()
- {
- $this->cache = CacheDriverFactory::create('database');
- return $this->cache;
- }
-
- public function tearDown()
- {
- $this->cache->clear(false);
- parent::tearDown();
- }
-
- /**
- * {@inheritdoc}
- * @dataProvider dataSimple
- */
- public function testSimple($value1, $value2)
- {
- // assertNull
- $this->mockGet('value1', null, $this->startTime, 1);
-
- // assertEquals
- $this->mockSet('value1', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockGet('value1', $value1, $this->startTime, 1);
-
- // assertEquals
- $this->mockSet('value1', $value2, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockGet('value1', $value2, $this->startTime, 1);
-
- // assertEquals
- $this->mockSet('value2', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockGet('value2', $value1, $this->startTime, 1);
-
- // assertNull
- $this->mockGet('not_set', null, $this->startTime, 1);
-
- // assertNull
- $this->mockDelete('value1', true, 1);
- $this->mockGet('value1', null, $this->startTime, 1);
-
- parent::testSimple($value1, $value2);
- }
-
- /**
- * {@inheritdoc}
- * @dataProvider dataSimple
- */
- public function testClear($value1, $value2, $value3, $value4)
- {
- // assert Equals
- $this->mockSet('1_value1', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockSet('1_value2', $value2, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockSet('2_value1', $value3, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockSet('3_value1', $value4, Cache::FIVE_MINUTES, $this->startTime, true, 1);
-
- $this->mockGet('1_value1', $value1, $this->startTime, 2);
- $this->mockGet('1_value2', $value2, $this->startTime, 2);
- $this->mockGet('2_value1', $value3, $this->startTime, 2);
- $this->mockGet('3_value1', $value4, $this->startTime, 2);
-
- // assertTrue
- $this->mockClear(true, true, 1);
- $this->mockClear(false, true, 1);
-
- // assertEquals
- $this->mockGet('1_value1', null, $this->startTime, 1);
- $this->mockGet('1_value2', null, $this->startTime, 1);
- $this->mockGet('2_value3', null, $this->startTime, 1);
- $this->mockGet('3_value4', null, $this->startTime, 1);
-
- parent::testClear($value1, $value2, $value3, $value4);
- }
-
- /**
- * {@inheritdoc}
- * @dataProvider dataTypesInCache
- */
- public function testDifferentTypesInCache($data)
- {
- $this->mockSet('val', $data, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockGet('val', $data, $this->startTime, 1);
-
- parent::testDifferentTypesInCache($data);
- }
-
- /**
- * {@inheritdoc}
- * @dataProvider dataSimple
- */
- public function testGetAllKeys($value1, $value2, $value3)
- {
- $this->mockSet('value1', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockSet('value2', $value2,Cache::FIVE_MINUTES, $this->startTime, true, 1);
- $this->mockSet('test_value3', $value3, Cache::FIVE_MINUTES, $this->startTime, true, 1);
-
- $result = [
- ['k' => 'value1'],
- ['k' => 'value2'],
- ['k' => 'test_value3'],
- ];
-
- $this->mockGetAllKeys(null, $result, $this->startTime, 1);
-
- $result = [
- ['k' => 'test_value3'],
- ];
-
- $this->mockGetAllKeys('test', $result, $this->startTime, 1);
-
- parent::testGetAllKeys($value1, $value2, $value3);
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Cache;
+
+use Friendica\Core\Cache;
+use Friendica\Factory\ConfigFactory;
+use Friendica\Test\DatabaseTestTrait;
+use Friendica\Test\Util\Database\StaticDatabase;
+use Friendica\Test\Util\VFSTrait;
+use Friendica\Util\ConfigFileLoader;
+use Friendica\Util\Profiler;
+use Psr\Log\NullLogger;
+
+class DatabaseCacheTest extends CacheTest
+{
+ use DatabaseTestTrait;
+ use VFSTrait;
+
+ protected function setUp()
+ {
+ $this->setUpVfsDir();
+
+ parent::setUp();
+ }
+
+ protected function getInstance()
+ {
+ $logger = new NullLogger();
+ $profiler = \Mockery::mock(Profiler::class);
+ $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
+
+ // load real config to avoid mocking every config-entry which is related to the Database class
+ $configFactory = new ConfigFactory();
+ $loader = new ConfigFileLoader($this->root->url());
+ $configCache = $configFactory->createCache($loader);
+
+ $dba = new StaticDatabase($configCache, $profiler, $logger);
+
+ $this->cache = new Cache\DatabaseCache('database', $dba);
+ return $this->cache;
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear(false);
+ parent::tearDown();
+ }
+}
+++ /dev/null
-<?php
-
-
-namespace Friendica\Test\src\Core\Cache;
-
-use Friendica\Factory\CacheDriverFactory;
-
-/**
- * @requires extension memcache
- */
-class MemcacheCacheDriverTest extends MemoryCacheTest
-{
- protected function getInstance()
- {
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'memcache_host')
- ->andReturn('localhost');
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'memcache_port')
- ->andReturn(11211);
-
- $this->cache = CacheDriverFactory::create('memcache');
- return $this->cache;
-
- }
-
- public function tearDown()
- {
- $this->cache->clear(false);
- parent::tearDown();
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Cache;
+
+use Friendica\Core\Cache\MemcacheCache;
+use Friendica\Core\Config\Configuration;
+
+/**
+ * @requires extension memcache
+ */
+class MemcacheCacheTest extends MemoryCacheTest
+{
+ protected function getInstance()
+ {
+ $configMock = \Mockery::mock(Configuration::class);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'memcache_host')
+ ->andReturn('localhost');
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'memcache_port')
+ ->andReturn(11211);
+
+ $this->cache = new MemcacheCache('localhost', $configMock);
+ return $this->cache;
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear(false);
+ parent::tearDown();
+ }
+}
+++ /dev/null
-<?php
-
-
-namespace Friendica\Test\src\Core\Cache;
-
-use Friendica\Factory\CacheDriverFactory;
-
-/**
- * @requires extension memcached
- */
-class MemcachedCacheDriverTest extends MemoryCacheTest
-{
- protected function getInstance()
- {
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'memcached_hosts')
- ->andReturn([0 => 'localhost, 11211']);
-
- $this->cache = CacheDriverFactory::create('memcached');
- return $this->cache;
- }
-
- public function tearDown()
- {
- $this->cache->clear(false);
- parent::tearDown();
- }
-}
--- /dev/null
+<?php
+
+
+namespace Friendica\Test\src\Core\Cache;
+
+use Friendica\Core\Cache\MemcachedCache;
+use Friendica\Core\Config\Configuration;
+use Psr\Log\NullLogger;
+
+/**
+ * @requires extension memcached
+ */
+class MemcachedCacheTest extends MemoryCacheTest
+{
+ protected function getInstance()
+ {
+ $configMock = \Mockery::mock(Configuration::class);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'memcached_hosts')
+ ->andReturn([0 => 'localhost, 11211']);
+
+ $logger = new NullLogger();
+
+ $this->cache = new MemcachedCache('localhost', $configMock, $logger);
+ return $this->cache;
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear(false);
+ parent::tearDown();
+ }
+}
namespace Friendica\Test\src\Core\Cache;
-use Friendica\Core\Cache\IMemoryCacheDriver;
-use Psr\Log\LoggerInterface;
-use Psr\Log\NullLogger;
+use Friendica\Core\Cache\IMemoryCache;
abstract class MemoryCacheTest extends CacheTest
{
/**
- * @var \Friendica\Core\Cache\IMemoryCacheDriver
+ * @var \Friendica\Core\Cache\IMemoryCache
*/
protected $instance;
{
parent::setUp();
- $logger = new NullLogger();
- $this->dice->shouldReceive('create')
- ->with(LoggerInterface::class)
- ->andReturn($logger);
-
- if (!($this->instance instanceof IMemoryCacheDriver)) {
+ if (!($this->instance instanceof IMemoryCache)) {
throw new \Exception('MemoryCacheTest unsupported');
}
}
* @small
* @dataProvider dataSimple
*/
- function testCompareSet($value1, $value2) {
+ function testCompareSet($value1, $value2)
+ {
$this->assertNull($this->instance->get('value1'));
$this->instance->add('value1', $value1);
* @small
* @dataProvider dataSimple
*/
- function testNegativeCompareSet($value1, $value2) {
+ function testNegativeCompareSet($value1, $value2)
+ {
$this->assertNull($this->instance->get('value1'));
$this->instance->add('value1', $value1);
* @small
* @dataProvider dataSimple
*/
- function testCompareDelete($data) {
+ function testCompareDelete($data)
+ {
$this->assertNull($this->instance->get('value1'));
$this->instance->add('value1', $data);
* @small
* @dataProvider dataSimple
*/
- function testNegativeCompareDelete($data) {
+ function testNegativeCompareDelete($data)
+ {
$this->assertNull($this->instance->get('value1'));
$this->instance->add('value1', $data);
* @small
* @dataProvider dataSimple
*/
- function testAdd($value1, $value2) {
+ function testAdd($value1, $value2)
+ {
$this->assertNull($this->instance->get('value1'));
$this->instance->add('value1', $value1);
$this->assertEquals($value2, $received, 'Value was not overwritten by add');
$this->assertNotEquals($value1, $received, 'Value was not overwritten by any other value');
}
-}
\ No newline at end of file
+}
+++ /dev/null
-<?php
-
-
-namespace Friendica\Test\src\Core\Cache;
-
-use Friendica\Factory\CacheDriverFactory;
-
-/**
- * @requires extension redis
- */
-class RedisCacheDriverTest extends MemoryCacheTest
-{
- protected function getInstance()
- {
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_host')
- ->andReturn('localhost');
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_port')
- ->andReturn(null);
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_db')
- ->andReturn(3);
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_password')
- ->andReturn(null);
-
- $this->cache = CacheDriverFactory::create('redis');
- return $this->cache;
- }
-
- public function tearDown()
- {
- $this->cache->clear(false);
- parent::tearDown();
- }
-}
--- /dev/null
+<?php
+
+
+namespace Friendica\Test\src\Core\Cache;
+
+use Friendica\Core\Cache\RedisCache;
+use Friendica\Core\Config\Configuration;
+
+/**
+ * @requires extension redis
+ */
+class RedisCacheTest extends MemoryCacheTest
+{
+ protected function getInstance()
+ {
+ $configMock = \Mockery::mock(Configuration::class);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_host')
+ ->andReturn('localhost');
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_port')
+ ->andReturn(null);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_db', 0)
+ ->andReturn(3);
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_password')
+ ->andReturn(null);
+
+ $this->cache = new RedisCache('localhost', $configMock);
+ return $this->cache;
+ }
+
+ public function tearDown()
+ {
+ $this->cache->clear(false);
+ parent::tearDown();
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Lock;
-
-
-use Friendica\Core\Cache\APCuCache;
-use Friendica\Core\Lock\CacheLockDriver;
-
-class APCuCacheLockDriverTest extends LockTest
-{
- protected function setUp()
- {
- if (!APCuCache::isAvailable()) {
- $this->markTestSkipped('APCu is not available');
- }
-
- parent::setUp();
- }
-
- protected function getInstance()
- {
- return new CacheLockDriver(new APCuCache());
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Friendica\Core\Cache\APCuCache;
+use Friendica\Core\Lock\CacheLock;
+
+class APCuCacheLockTest extends LockTest
+{
+ protected function setUp()
+ {
+ if (!APCuCache::isAvailable()) {
+ $this->markTestSkipped('APCu is not available');
+ }
+
+ parent::setUp();
+ }
+
+ protected function getInstance()
+ {
+ return new CacheLock(new APCuCache('localhost'));
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Lock;
-
-
-use Friendica\Core\Cache\ArrayCache;
-use Friendica\Core\Lock\CacheLockDriver;
-
-class ArrayCacheLockDriverTest extends LockTest
-{
- protected function getInstance()
- {
- return new CacheLockDriver(new ArrayCache());
- }
-
- public function testLockTTL()
- {
- // ArrayCache doesn't support TTL
- return true;
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Friendica\Core\Cache\ArrayCache;
+use Friendica\Core\Lock\CacheLock;
+
+class ArrayCacheLockTest extends LockTest
+{
+ protected function getInstance()
+ {
+ return new CacheLock(new ArrayCache('localhost'));
+ }
+
+ public function testLockTTL()
+ {
+ // ArrayCache doesn't support TTL
+ return true;
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Lock;
-
-use Friendica\Core\Cache;
-use Friendica\Core\Lock\DatabaseLockDriver;
-use Friendica\Test\Util\DbaLockMockTrait;
-
-/**
- * @runTestsInSeparateProcesses
- * @preserveGlobalState disabled
- */
-class DatabaseLockDriverTest extends LockTest
-{
- use DbaLockMockTrait;
-
- protected $pid = 123;
-
- protected function setUp()
- {
- $this->mockConnected();
- $this->mockConnect();
-
- $this->mockReleaseAll($this->pid, 2);
-
- parent::setUp();
- }
-
- protected function getInstance()
- {
- return new DatabaseLockDriver($this->pid);
- }
-
- public function testLock()
- {
- $this->mockIsLocked('foo', false, $this->startTime, 1);
- $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
- $this->mockIsLocked('foo', true, $this->startTime, 1);
- $this->mockIsLocked('bar', false, $this->startTime, 1);
-
- parent::testLock();
- }
-
- public function testDoubleLock()
- {
- $this->mockIsLocked('foo', false, $this->startTime, 1);
- $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
- $this->mockIsLocked('foo', true, $this->startTime, 1);
- $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, true, $this->pid, true, $this->startTime, 1);
-
- parent::testDoubleLock();
- }
-
- public function testReleaseLock()
- {
- $this->mockIsLocked('foo', false, $this->startTime, 1);
- $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
- $this->mockIsLocked('foo', true, $this->startTime, 1);
- $this->mockReleaseLock('foo', $this->pid, 1);
- $this->mockIsLocked('foo', false, $this->startTime, 1);
-
- parent::testReleaseLock();
- }
-
- public function testReleaseAll()
- {
- $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
- $this->mockAcquireLock('bar', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
- $this->mockAcquireLock('nice', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
-
- $this->mockIsLocked('foo', true, $this->startTime, 1);
- $this->mockIsLocked('bar', true, $this->startTime, 1);
- $this->mockIsLocked('nice', true, $this->startTime, 1);
-
- $this->mockReleaseAll($this->pid, 1);
-
- $this->mockIsLocked('foo', false, $this->startTime, 1);
- $this->mockIsLocked('bar', false, $this->startTime, 1);
- $this->mockIsLocked('nice', false, $this->startTime, 1);
-
- parent::testReleaseAll();
- }
-
- public function testReleaseAfterUnlock()
- {
- $this->mockIsLocked('foo', false, $this->startTime, 1);
- $this->mockIsLocked('bar', false, $this->startTime, 1);
- $this->mockIsLocked('nice', false, $this->startTime, 1);
-
- $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
- $this->mockAcquireLock('bar', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
- $this->mockAcquireLock('nice', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1);
-
- $this->mockReleaseLock('foo', $this->pid, 1);
-
- $this->mockIsLocked('foo', false, $this->startTime, 1);
- $this->mockIsLocked('bar', true, $this->startTime, 1);
- $this->mockIsLocked('nice', true, $this->startTime, 1);
-
- $this->mockReleaseAll($this->pid, 1);
-
- $this->mockIsLocked('bar', false, $this->startTime, 1);
- $this->mockIsLocked('nice', false, $this->startTime, 1);
-
- parent::testReleaseAfterUnlock();
- }
-
- public function testReleaseWitTTL()
- {
- $this->mockIsLocked('test', false, $this->startTime, 1);
- $this->mockAcquireLock('test', 10, false, $this->pid, false, $this->startTime, 1);
- $this->mockIsLocked('test', true, $this->startTime, 1);
- $this->mockReleaseLock('test', $this->pid, 1);
- $this->mockIsLocked('test', false, $this->startTime, 1);
-
- parent::testReleaseWitTTL();
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Friendica\Core\Lock\DatabaseLock;
+use Friendica\Factory\ConfigFactory;
+use Friendica\Test\DatabaseTestTrait;
+use Friendica\Test\Util\Database\StaticDatabase;
+use Friendica\Test\Util\VFSTrait;
+use Friendica\Util\ConfigFileLoader;
+use Friendica\Util\Profiler;
+use Psr\Log\NullLogger;
+
+class DatabaseLockDriverTest extends LockTest
+{
+ use VFSTrait;
+ use DatabaseTestTrait;
+
+ protected $pid = 123;
+
+ protected function setUp()
+ {
+ $this->setUpVfsDir();
+
+ parent::setUp();
+ }
+
+ protected function getInstance()
+ {
+ $logger = new NullLogger();
+ $profiler = \Mockery::mock(Profiler::class);
+ $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
+
+ // load real config to avoid mocking every config-entry which is related to the Database class
+ $configFactory = new ConfigFactory();
+ $loader = new ConfigFileLoader($this->root->url());
+ $configCache = $configFactory->createCache($loader);
+
+ $dba = new StaticDatabase($configCache, $profiler, $logger);
+
+ return new DatabaseLock($dba, $this->pid);
+ }
+}
namespace Friendica\Test\src\Core\Lock;
use Friendica\Test\MockedTest;
-use Friendica\Test\Util\AppMockTrait;
-use Friendica\Test\Util\VFSTrait;
-use Psr\Log\LoggerInterface;
-use Psr\Log\NullLogger;
abstract class LockTest extends MockedTest
{
- use VFSTrait;
- use AppMockTrait;
-
/**
* @var int Start time of the mock (used for time operations)
*/
protected $startTime = 1417011228;
/**
- * @var \Friendica\Core\Lock\ILockDriver
+ * @var \Friendica\Core\Lock\ILock
*/
protected $instance;
protected function setUp()
{
- // Reusable App object
- $this->setUpVfsDir();
- $this->mockApp($this->root);
- $this->app
- ->shouldReceive('getHostname')
- ->andReturn('friendica.local');
-
- $logger = new NullLogger();
- $this->dice->shouldReceive('create')
- ->with(LoggerInterface::class)
- ->andReturn($logger);
-
parent::setUp();
+
$this->instance = $this->getInstance();
$this->instance->releaseAll();
}
/**
* @small
*/
- public function testLock() {
+ public function testLock()
+ {
$this->assertFalse($this->instance->isLocked('foo'));
$this->assertTrue($this->instance->acquireLock('foo', 1));
$this->assertTrue($this->instance->isLocked('foo'));
/**
* @small
*/
- public function testDoubleLock() {
+ public function testDoubleLock()
+ {
$this->assertFalse($this->instance->isLocked('foo'));
$this->assertTrue($this->instance->acquireLock('foo', 1));
$this->assertTrue($this->instance->isLocked('foo'));
/**
* @small
*/
- public function testReleaseLock() {
+ public function testReleaseLock()
+ {
$this->assertFalse($this->instance->isLocked('foo'));
$this->assertTrue($this->instance->acquireLock('foo', 1));
$this->assertTrue($this->instance->isLocked('foo'));
/**
* @small
*/
- public function testReleaseAll() {
+ public function testReleaseAll()
+ {
$this->assertTrue($this->instance->acquireLock('foo', 1));
$this->assertTrue($this->instance->acquireLock('bar', 1));
$this->assertTrue($this->instance->acquireLock('nice', 1));
/**
* @small
*/
- public function testReleaseAfterUnlock() {
+ public function testReleaseAfterUnlock()
+ {
$this->assertFalse($this->instance->isLocked('foo'));
$this->assertFalse($this->instance->isLocked('bar'));
$this->assertFalse($this->instance->isLocked('nice'));
/**
* @medium
*/
- function testLockTTL() {
+ function testLockTTL()
+ {
$this->markTestSkipped('taking too much time without mocking');
$this->assertFalse($this->instance->isLocked('foo'));
+++ /dev/null
-<?php
-
-
-namespace Friendica\Test\src\Core\Lock;
-
-use Friendica\Factory\CacheDriverFactory;
-use Friendica\Core\Lock\CacheLockDriver;
-
-/**
- * @requires extension Memcache
- */
-class MemcacheCacheLockDriverTest extends LockTest
-{
- protected function getInstance()
- {
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'memcache_host')
- ->andReturn('localhost');
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'memcache_port')
- ->andReturn(11211);
-
- return new CacheLockDriver(CacheDriverFactory::create('memcache'));
- }
-}
--- /dev/null
+<?php
+
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Friendica\Core\Cache\MemcacheCache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Lock\CacheLock;
+
+/**
+ * @requires extension Memcache
+ */
+class MemcacheCacheLockTest extends LockTest
+{
+ protected function getInstance()
+ {
+ $configMock = \Mockery::mock(Configuration::class);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'memcache_host')
+ ->andReturn('localhost');
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'memcache_port')
+ ->andReturn(11211);
+
+ return new CacheLock(new MemcacheCache('localhost', $configMock));
+ }
+}
+++ /dev/null
-<?php
-
-
-namespace Friendica\Test\src\Core\Lock;
-
-use Friendica\Factory\CacheDriverFactory;
-use Friendica\Core\Lock\CacheLockDriver;
-
-/**
- * @requires extension memcached
- */
-class MemcachedCacheLockDriverTest extends LockTest
-{
- protected function getInstance()
- {
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'memcached_hosts')
- ->andReturn([0 => 'localhost, 11211']);
-
- return new CacheLockDriver(CacheDriverFactory::create('memcached'));
- }
-}
--- /dev/null
+<?php
+
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Friendica\Core\Cache\MemcachedCache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Lock\CacheLock;
+use Psr\Log\NullLogger;
+
+/**
+ * @requires extension memcached
+ */
+class MemcachedCacheLockTest extends LockTest
+{
+ protected function getInstance()
+ {
+ $configMock = \Mockery::mock(Configuration::class);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'memcached_hosts')
+ ->andReturn([0 => 'localhost, 11211']);
+
+ $logger = new NullLogger();
+
+ return new CacheLock(new MemcachedCache('localhost', $configMock, $logger));
+ }
+}
+++ /dev/null
-<?php
-
-
-namespace Friendica\Test\src\Core\Lock;
-
-use Friendica\Core\Lock\CacheLockDriver;
-use Friendica\Factory\CacheDriverFactory;
-
-/**
- * @requires extension redis
- */
-class RedisCacheLockDriverTest extends LockTest
-{
- protected function getInstance()
- {
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_host')
- ->andReturn('localhost');
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_port')
- ->andReturn(null);
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_db')
- ->andReturn(3);
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'redis_password')
- ->andReturn(null);
-
- return new CacheLockDriver(CacheDriverFactory::create('redis'));
- }
-}
--- /dev/null
+<?php
+
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Friendica\Core\Cache\RedisCache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Lock\CacheLock;
+
+/**
+ * @requires extension redis
+ */
+class RedisCacheLockTest extends LockTest
+{
+ protected function getInstance()
+ {
+ $configMock = \Mockery::mock(Configuration::class);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_host')
+ ->andReturn('localhost');
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_port')
+ ->andReturn(null);
+
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_db', 0)
+ ->andReturn(3);
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'redis_password')
+ ->andReturn(null);
+
+ return new CacheLock(new RedisCache('localhost', $configMock));
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Lock;
-
-use Friendica\Core\Lock\SemaphoreLockDriver;
-
-class SemaphoreLockDriverTest extends LockTest
-{
- public function setUp()
- {
- parent::setUp();
-
- $this->app->shouldReceive('getHostname')->andReturn('friendica.local');
-
- $this->configMock
- ->shouldReceive('get')
- ->with('system', 'temppath')
- ->andReturn('/tmp/');
- }
-
- protected function getInstance()
- {
- return new SemaphoreLockDriver();
- }
-
- function testLockTTL()
- {
- // Semaphore doesn't work with TTL
- return true;
- }
-}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Core\Lock;
+
+use Dice\Dice;
+use Friendica\App;
+use Friendica\BaseObject;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Lock\SemaphoreLock;
+
+class SemaphoreLockTest extends LockTest
+{
+ public function setUp()
+ {
+ parent::setUp();
+
+ $dice = \Mockery::mock(Dice::class)->makePartial();
+
+ $app = \Mockery::mock(App::class);
+ $app->shouldReceive('getHostname')->andReturn('friendica.local');
+ $dice->shouldReceive('create')->with(App::class)->andReturn($app);
+
+ $configMock = \Mockery::mock(Configuration::class);
+ $configMock
+ ->shouldReceive('get')
+ ->with('system', 'temppath', NULL, false)
+ ->andReturn('/tmp/');
+ $dice->shouldReceive('create')->with(Configuration::class)->andReturn($configMock);
+
+ // @todo Because "get_temppath()" is using static methods, we have to initialize the BaseObject
+ BaseObject::setDependencyInjection($dice);
+ }
+
+ protected function getInstance()
+ {
+ return new SemaphoreLock();
+ }
+
+ function testLockTTL()
+ {
+ // Semaphore doesn't work with TTL
+ return true;
+ }
+}
{
parent::setUp();
- $dice = new Dice();
- $dice = $dice->addRules(include __DIR__ . '/../../../static/dependencies.config.php');
- $dice = $dice->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]);
+ $dice = (new Dice())
+ ->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
+ ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]);
BaseObject::setDependencyInjection($dice);
// Default config
{
parent::setUp();
- $dice = new Dice();
- $dice = $dice->addRules(include __DIR__ . '/../../../static/dependencies.config.php');
- $dice = $dice->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]);
+ $dice = (new Dice())
+ ->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
+ ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]);
BaseObject::setDependencyInjection($dice);
}