diff --git a/boot.php b/boot.php index a069dcafc9..9df5631881 100644 --- a/boot.php +++ b/boot.php @@ -20,6 +20,7 @@ require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; use Friendica\App; +use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Cache; use Friendica\Core\Config; @@ -536,6 +537,7 @@ function get_app() if (empty($a)) { $a = new App(dirname(__DIR__)); + BaseObject::setApp($a); } return $a; diff --git a/doc/htconfig.md b/doc/htconfig.md index bed6f79029..1f1b62bd49 100644 --- a/doc/htconfig.md +++ b/doc/htconfig.md @@ -27,6 +27,7 @@ Example: To set the automatic database cleanup process add this line to your .ht * **always_show_preview** (Boolean) - Only show small preview picures. Default value is false. * **block_local_dir** (Boolean) - Blocks the access to the directory of the local users. * **auth_cookie_lifetime** (Integer) - Number of days that should pass without any activity before a user who chose "Remember me" when logging in is considered logged out. Defaults to 7. +* **config_adapter** (jit|preload) - Allow to switch the configuration adapter to improve performances at the cost of memory consumption. Default value is "jit" * **curl_range_bytes** - Maximum number of bytes that should be fetched. Default is 0, which mean "no limit". * **db_log** - Name of a logfile to log slow database queries * **db_loglimit** - If a database call lasts longer than this value it is logged diff --git a/index.php b/index.php index ef84400990..fba16263ab 100644 --- a/index.php +++ b/index.php @@ -24,9 +24,7 @@ use Friendica\Module\Login; require_once 'boot.php'; -if (empty($a)) { - $a = new App(__DIR__); -} +$a = new App(__DIR__); BaseObject::setApp($a); // We assume that the index.php is called by a frontend process @@ -78,6 +76,7 @@ if (!$install) { exit(); } + Config::init(); Session::init(); Addon::loadHooks(); Addon::callHooks('init_1'); diff --git a/scripts/auth_ejabberd.php b/scripts/auth_ejabberd.php index 5c516f3987..32aa30898c 100755 --- a/scripts/auth_ejabberd.php +++ b/scripts/auth_ejabberd.php @@ -33,6 +33,8 @@ */ use Friendica\App; +use Friendica\BaseObject; +use Friendica\Core\Config; use Friendica\Util\ExAuth; if (sizeof($_SERVER["argv"]) == 0) { @@ -53,6 +55,7 @@ require_once "boot.php"; require_once "include/dba.php"; $a = new App(dirname(__DIR__)); +BaseObject::setApp($a); @include ".htconfig.php"; dba::connect($db_host, $db_user, $db_pass, $db_data); diff --git a/scripts/dbstructure.php b/scripts/dbstructure.php index 3787af2255..ff5b53c622 100755 --- a/scripts/dbstructure.php +++ b/scripts/dbstructure.php @@ -13,6 +13,7 @@ require_once "boot.php"; require_once "include/dba.php"; $a = new App(dirname(__DIR__)); +BaseObject::setApp($a); @include ".htconfig.php"; dba::connect($db_host, $db_user, $db_pass, $db_data); diff --git a/scripts/worker.php b/scripts/worker.php index a821fc1abe..1980a21b15 100755 --- a/scripts/worker.php +++ b/scripts/worker.php @@ -6,6 +6,7 @@ */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\Worker; @@ -26,6 +27,7 @@ require_once "boot.php"; require_once "include/dba.php"; $a = new App(dirname(__DIR__)); +BaseObject::setApp($a); require_once ".htconfig.php"; dba::connect($db_host, $db_user, $db_pass, $db_data); diff --git a/src/App.php b/src/App.php index 0acbfe6f41..2330bc1185 100644 --- a/src/App.php +++ b/src/App.php @@ -944,4 +944,116 @@ class App return true; } + + /** + * @param string $cat Config category + * @param string $k Config key + * @param mixed $default Default value if it isn't set + */ + public function getConfigValue($cat, $k, $default = null) + { + $return = $default; + + if ($cat === 'config') { + if (isset($this->config[$k])) { + $return = $this->config[$k]; + } + } else { + if (isset($this->config[$cat][$k])) { + $return = $this->config[$cat][$k]; + } + } + + return $return; + } + + /** + * Sets a value in the config cache. Accepts raw output from the config table + * + * @param string $cat Config category + * @param string $k Config key + * @param mixed $v Value to set + */ + public function setConfigValue($cat, $k, $v) + { + // Only arrays are serialized in database, so we have to unserialize sparingly + $value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v; + + if ($cat === 'config') { + $this->config[$k] = $value; + } else { + $this->config[$cat][$k] = $value; + } + } + + /** + * Deletes a value from the config cache + * + * @param string $cat Config category + * @param string $k Config key + */ + public function deleteConfigValue($cat, $k) + { + if ($cat === 'config') { + if (isset($this->config[$k])) { + unset($this->config[$k]); + } + } else { + if (isset($this->config[$cat][$k])) { + unset($this->config[$cat][$k]); + } + } + } + + + /** + * Retrieves a value from the user config cache + * + * @param int $uid User Id + * @param string $cat Config category + * @param string $k Config key + * @param mixed $default Default value if key isn't set + */ + public function getPConfigValue($uid, $cat, $k, $default = null) + { + $return = $default; + + if (isset($this->config[$uid][$cat][$k])) { + $return = $this->config[$uid][$cat][$k]; + } + + return $return; + } + + /** + * Sets a value in the user config cache + * + * Accepts raw output from the pconfig table + * + * @param int $uid User Id + * @param string $cat Config category + * @param string $k Config key + * @param mixed $v Value to set + */ + public function setPConfigValue($uid, $cat, $k, $v) + { + // Only arrays are serialized in database, so we have to unserialize sparingly + $value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v; + + $this->config[$uid][$cat][$k] = $value; + } + + /** + * Deletes a value from the user config cache + * + * @param int $uid User Id + * @param string $cat Config category + * @param string $k Config key + */ + public function deletePConfigValue($uid, $cat, $k) + { + if (isset($this->config[$uid][$cat][$k])) { + unset($this->config[$uid][$cat][$k]); + } + } } diff --git a/src/Core/Config.php b/src/Core/Config.php index 5e162a3fa4..3c1d3245fd 100644 --- a/src/Core/Config.php +++ b/src/Core/Config.php @@ -8,26 +8,33 @@ */ namespace Friendica\Core; -use Friendica\Database\DBM; -use dba; +use Friendica\BaseObject; +use Friendica\Core\Config; require_once 'include/dba.php'; /** - * @brief Arbitrary sytem configuration storage + * @brief Arbitrary system configuration storage * * Note: * If we ever would decide to return exactly the variable type as entered, * we will have fun with the additional features. :-) - * - * The config class always returns strings but in the default features - * we use a "false" to determine if the config value isn't set. - * */ -class Config +class Config extends BaseObject { - private static $cache; - private static $in_db; + /** + * @var Friendica\Core\Config\IConfigAdapter + */ + private static $adapter = null; + + public static function init() + { + if (self::getApp()->getConfigValue('system', 'config_adapter') == 'preload') { + self::$adapter = new Config\PreloadConfigAdapter(); + } else { + self::$adapter = new Config\JITConfigAdapter(); + } + } /** * @brief Loads all configuration values of family into a cached storage. @@ -41,26 +48,11 @@ class Config */ public static function load($family = "config") { - // We don't preload "system" anymore. - // This reduces the number of database reads a lot. - if ($family === 'system') { - return; + if (empty(self::$adapter)) { + self::init(); } - $a = get_app(); - - $r = dba::select('config', ['v', 'k'], ['cat' => $family]); - while ($rr = dba::fetch($r)) { - $k = $rr['k']; - if ($family === 'config') { - $a->config[$k] = $rr['v']; - } else { - $a->config[$family][$k] = $rr['v']; - self::$cache[$family][$k] = $rr['v']; - self::$in_db[$family][$k] = true; - } - } - dba::close($r); + self::$adapter->load($family); } /** @@ -84,40 +76,11 @@ class Config */ public static function get($family, $key, $default_value = null, $refresh = false) { - $a = get_app(); - - if (!$refresh) { - // Do we have the cached value? Then return it - if (isset(self::$cache[$family][$key])) { - if (self::$cache[$family][$key] === '!!') { - return $default_value; - } else { - return self::$cache[$family][$key]; - } - } + if (empty(self::$adapter)) { + self::init(); } - $config = dba::selectFirst('config', ['v'], ['cat' => $family, 'k' => $key]); - if (DBM::is_result($config)) { - // manage array value - $val = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']); - - // Assign the value from the database to the cache - self::$cache[$family][$key] = $val; - self::$in_db[$family][$key] = true; - return $val; - } elseif (isset($a->config[$family][$key])) { - // Assign the value (mostly) from the .htconfig.php to the cache - self::$cache[$family][$key] = $a->config[$family][$key]; - self::$in_db[$family][$key] = false; - - return $a->config[$family][$key]; - } - - self::$cache[$family][$key] = '!!'; - self::$in_db[$family][$key] = false; - - return $default_value; + return self::$adapter->get($family, $key, $default_value, $refresh); } /** @@ -136,38 +99,11 @@ class Config */ public static function set($family, $key, $value) { - $a = get_app(); - - // We store our setting values in a string variable. - // So we have to do the conversion here so that the compare below works. - // The exception are array values. - $dbvalue = (!is_array($value) ? (string)$value : $value); - - $stored = self::get($family, $key, null, true); - - if (($stored === $dbvalue) && self::$in_db[$family][$key]) { - return true; + if (empty(self::$adapter)) { + self::init(); } - if ($family === 'config') { - $a->config[$key] = $dbvalue; - } elseif ($family != 'system') { - $a->config[$family][$key] = $dbvalue; - } - - // Assign the just added value to the cache - self::$cache[$family][$key] = $dbvalue; - - // manage array value - $dbvalue = (is_array($value) ? serialize($value) : $dbvalue); - - $ret = dba::update('config', ['v' => $dbvalue], ['cat' => $family, 'k' => $key], true); - - if ($ret) { - self::$in_db[$family][$key] = true; - return $value; - } - return $ret; + return self::$adapter->set($family, $key, $value); } /** @@ -183,13 +119,10 @@ class Config */ public static function delete($family, $key) { - if (isset(self::$cache[$family][$key])) { - unset(self::$cache[$family][$key]); - unset(self::$in_db[$family][$key]); + if (empty(self::$adapter)) { + self::init(); } - $ret = dba::delete('config', ['cat' => $family, 'k' => $key]); - - return $ret; + return self::$adapter->delete($family, $key); } } diff --git a/src/Core/Config/IConfigAdapter.php b/src/Core/Config/IConfigAdapter.php new file mode 100644 index 0000000000..ee5ca3ca54 --- /dev/null +++ b/src/Core/Config/IConfigAdapter.php @@ -0,0 +1,72 @@ + + */ +interface IConfigAdapter +{ + /** + * @brief Loads all configuration values into a cached storage. + * + * All configuration values of the system are stored in global cache + * which is available under the global variable $a->config + * + * @param string $cat The category of the configuration values to load + * + * @return void + */ + public function load($cat = "config"); + + /** + * @brief Get a particular user's config variable given the category name + * ($family) and a key. + * + * Get a particular config value from the given category ($family) + * and the $key from a cached storage in $a->config[$uid]. + * $instore is only used by the set_config function + * to determine if the key already exists in the DB + * If a key is found in the DB but doesn't exist in + * local config cache, pull it into the cache so we don't have + * to hit the DB again for this item. + * + * @param string $cat The category of the configuration value + * @param string $k The configuration key to query + * @param mixed $default_value optional, The value to return if key is not set (default: null) + * @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false) + * + * @return mixed Stored value or null if it does not exist + */ + public function get($cat, $k, $default_value = null, $refresh = false); + + /** + * @brief Sets a configuration value for system config + * + * Stores a config value ($value) in the category ($family) under the key ($key) + * for the user_id $uid. + * + * Note: Please do not store booleans - convert to 0/1 integer values! + * + * @param string $family The category of the configuration value + * @param string $key The configuration key to set + * @param mixed $value The value to store + * + * @return mixed Stored $value or false if the database update failed + */ + public function set($cat, $k, $value); + + /** + * @brief Deletes the given key from the system configuration. + * + * Removes the configured value from the stored cache in $a->config + * and removes it from the database. + * + * @param string $cat The category of the configuration value + * @param string $k The configuration key to delete + * + * @return mixed + */ + public function delete($cat, $k); +} diff --git a/src/Core/Config/IPConfigAdapter.php b/src/Core/Config/IPConfigAdapter.php new file mode 100644 index 0000000000..f78654d39c --- /dev/null +++ b/src/Core/Config/IPConfigAdapter.php @@ -0,0 +1,77 @@ +config[$uid]. + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * + * @return void + */ + public function load($uid, $cat); + + /** + * @brief Get a particular user's config variable given the category name + * ($family) and a key. + * + * Get a particular user's config value from the given category ($family) + * and the $key from a cached storage in $a->config[$uid]. + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * @param string $k The configuration key to query + * @param mixed $default_value optional, The value to return if key is not set (default: null) + * @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false) + * + * @return mixed Stored value or null if it does not exist + */ + public function get($uid, $cat, $k, $default_value = null, $refresh = false); + + /** + * @brief Sets a configuration value for a user + * + * Stores a config value ($value) in the category ($family) under the key ($key) + * for the user_id $uid. + * + * @note Please do not store booleans - convert to 0/1 integer values! + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * @param string $k The configuration key to set + * @param string $value The value to store + * + * @return mixed Stored $value or false + */ + public function set($uid, $cat, $k, $value); + + /** + * @brief Deletes the given key from the users's configuration. + * + * Removes the configured value from the stored cache in $a->config[$uid] + * and removes it from the database. + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * @param string $k The configuration key to delete + * + * @return mixed + */ + public function delete($uid, $cat, $k); +} diff --git a/src/Core/Config/JITConfigAdapter.php b/src/Core/Config/JITConfigAdapter.php new file mode 100644 index 0000000000..0e7731690b --- /dev/null +++ b/src/Core/Config/JITConfigAdapter.php @@ -0,0 +1,126 @@ + + */ +class JITConfigAdapter extends BaseObject implements IConfigAdapter +{ + private $cache; + private $in_db; + + public function load($cat = "config") + { + // We don't preload "system" anymore. + // This reduces the number of database reads a lot. + if ($cat === 'system') { + return; + } + + $configs = dba::select('config', ['v', 'k'], ['cat' => $cat]); + while ($config = dba::fetch($configs)) { + $k = $config['k']; + + self::getApp()->setConfigValue($cat, $k, $config['v']); + + if ($cat !== 'config') { + $this->cache[$cat][$k] = $config['v']; + $this->in_db[$cat][$k] = true; + } + } + dba::close($configs); + } + + public function get($cat, $k, $default_value = null, $refresh = false) + { + $a = self::getApp(); + + if (!$refresh) { + // Do we have the cached value? Then return it + if (isset($this->cache[$cat][$k])) { + if ($this->cache[$cat][$k] === '!!') { + return $default_value; + } else { + return $this->cache[$cat][$k]; + } + } + } + + $config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]); + if (DBM::is_result($config)) { + // manage array value + $value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']); + + // Assign the value from the database to the cache + $this->cache[$cat][$k] = $value; + $this->in_db[$cat][$k] = true; + return $value; + } elseif (isset($a->config[$cat][$k])) { + // Assign the value (mostly) from the .htconfig.php to the cache + $this->cache[$cat][$k] = $a->config[$cat][$k]; + $this->in_db[$cat][$k] = false; + + return $a->config[$cat][$k]; + } + + $this->cache[$cat][$k] = '!!'; + $this->in_db[$cat][$k] = false; + + return $default_value; + } + + public function set($cat, $k, $value) + { + $a = self::getApp(); + + // We store our setting values in a string variable. + // So we have to do the conversion here so that the compare below works. + // The exception are array values. + $dbvalue = (!is_array($value) ? (string)$value : $value); + + $stored = $this->get($cat, $k, null, true); + + if (($stored === $dbvalue) && $this->in_db[$cat][$k]) { + return true; + } + + self::getApp()->setConfigValue($cat, $k, $value); + + // Assign the just added value to the cache + $this->cache[$cat][$k] = $dbvalue; + + // manage array value + $dbvalue = (is_array($value) ? serialize($value) : $dbvalue); + + $result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true); + + if ($result) { + $this->in_db[$cat][$k] = true; + return $value; + } + + return $result; + } + + public function delete($cat, $k) + { + if (isset($this->cache[$cat][$k])) { + unset($this->cache[$cat][$k]); + unset($this->in_db[$cat][$k]); + } + + $result = dba::delete('config', ['cat' => $cat, 'k' => $k]); + + return $result; + } +} diff --git a/src/Core/Config/JITPConfigAdapter.php b/src/Core/Config/JITPConfigAdapter.php new file mode 100644 index 0000000000..ce9c5b6462 --- /dev/null +++ b/src/Core/Config/JITPConfigAdapter.php @@ -0,0 +1,119 @@ + + */ +class JITPConfigAdapter extends BaseObject implements IPConfigAdapter +{ + private $in_db; + + public function load($uid, $cat) + { + $a = self::getApp(); + + $pconfigs = dba::select('pconfig', ['v', 'k'], ['cat' => $cat, 'uid' => $uid]); + if (DBM::is_result($pconfigs)) { + while ($pconfig = dba::fetch($pconfigs)) { + $k = $pconfig['k']; + + self::getApp()->setPConfigValue($uid, $cat, $k, $pconfig['v']); + + $this->in_db[$uid][$cat][$k] = true; + } + } else if ($cat != 'config') { + // Negative caching + $a->config[$uid][$cat] = "!!"; + } + dba::close($pconfigs); + } + + public function get($uid, $cat, $k, $default_value = null, $refresh = false) + { + $a = self::getApp(); + + if (!$refresh) { + // Looking if the whole family isn't set + if (isset($a->config[$uid][$cat])) { + if ($a->config[$uid][$cat] === '!!') { + return $default_value; + } + } + + if (isset($a->config[$uid][$cat][$k])) { + if ($a->config[$uid][$cat][$k] === '!!') { + return $default_value; + } + return $a->config[$uid][$cat][$k]; + } + } + + $pconfig = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]); + if (DBM::is_result($pconfig)) { + $val = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']); + + self::getApp()->setPConfigValue($uid, $cat, $k, $val); + + $this->in_db[$uid][$cat][$k] = true; + + return $val; + } else { + self::getApp()->setPConfigValue($uid, $cat, $k, '!!'); + + $this->in_db[$uid][$cat][$k] = false; + + return $default_value; + } + } + + public function set($uid, $cat, $k, $value) + { + // We store our setting values in a string variable. + // So we have to do the conversion here so that the compare below works. + // The exception are array values. + $dbvalue = (!is_array($value) ? (string)$value : $value); + + $stored = $this->get($uid, $cat, $k, null, true); + + if (($stored === $dbvalue) && $this->in_db[$uid][$cat][$k]) { + return true; + } + + self::getApp()->setPConfigValue($uid, $cat, $k, $value); + + // manage array value + $dbvalue = (is_array($value) ? serialize($value) : $dbvalue); + + $result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true); + + if ($result) { + $this->in_db[$uid][$cat][$k] = true; + return $value; + } + + return $result; + } + + public function delete($uid, $cat, $k) + { + self::getApp()->deletePConfigValue($uid, $cat, $k); + + if (!empty($this->in_db[$uid][$cat][$k])) { + unset($this->in_db[$uid][$cat][$k]); + } + + $result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]); + + return $result; + } +} diff --git a/src/Core/Config/PreloadConfigAdapter.php b/src/Core/Config/PreloadConfigAdapter.php new file mode 100644 index 0000000000..f87b47f16c --- /dev/null +++ b/src/Core/Config/PreloadConfigAdapter.php @@ -0,0 +1,90 @@ + + */ +class PreloadConfigAdapter extends BaseObject implements IConfigAdapter +{ + private $config_loaded = false; + + public function __construct() + { + $this->load(); + } + + public function load($family = 'config') + { + if ($this->config_loaded) { + return; + } + + $configs = dba::select('config', ['cat', 'v', 'k']); + while ($config = dba::fetch($configs)) { + self::getApp()->setConfigValue($config['cat'], $config['k'], $config['v']); + } + dba::close($configs); + + $this->config_loaded = true; + } + + public function get($cat, $k, $default_value = null, $refresh = false) + { + if ($refresh) { + $config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]); + if (DBM::is_result($config)) { + self::getApp()->setConfigValue($cat, $k, $config['v']); + } + } + + $return = self::getApp()->getConfigValue($cat, $k, $default_value); + + return $return; + } + + public function set($cat, $k, $value) + { + // We store our setting values as strings. + // So we have to do the conversion here so that the compare below works. + // The exception are array values. + $compare_value = !is_array($value) ? (string)$value : $value; + + if (self::getApp()->getConfigValue($cat, $k) === $compare_value) { + return true; + } + + self::getApp()->setConfigValue($cat, $k, $value); + + // manage array value + $dbvalue = is_array($value) ? serialize($value) : $value; + + $result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true); + if (!$result) { + throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']'); + } + + return true; + } + + public function delete($cat, $k) + { + self::getApp()->deleteConfigValue($cat, $k); + + $result = dba::delete('config', ['cat' => $cat, 'k' => $k]); + + return $result; + } +} diff --git a/src/Core/Config/PreloadPConfigAdapter.php b/src/Core/Config/PreloadPConfigAdapter.php new file mode 100644 index 0000000000..d235410339 --- /dev/null +++ b/src/Core/Config/PreloadPConfigAdapter.php @@ -0,0 +1,92 @@ + + */ +class PreloadPConfigAdapter extends BaseObject implements IPConfigAdapter +{ + private $config_loaded = false; + + public function __construct($uid) + { + $this->load($uid, 'config'); + } + + public function load($uid, $family) + { + if ($this->config_loaded) { + return; + } + + $pconfigs = dba::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]); + while ($pconfig = dba::fetch($pconfigs)) { + self::getApp()->setPConfigValue($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']); + } + dba::close($pconfigs); + + $this->config_loaded = true; + } + + public function get($uid, $cat, $k, $default_value = null, $refresh = false) + { + if ($refresh) { + $config = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]); + if (DBM::is_result($config)) { + self::getApp()->setPConfigValue($uid, $cat, $k, $config['v']); + } else { + self::getApp()->deletePConfigValue($uid, $cat, $k); + } + } + + $return = self::getApp()->getPConfigValue($uid, $cat, $k, $default_value); + + return $return; + } + + public function set($uid, $cat, $k, $value) + { + // We store our setting values as strings. + // So we have to do the conversion here so that the compare below works. + // The exception are array values. + $compare_value = !is_array($value) ? (string)$value : $value; + + if (self::getApp()->getPConfigValue($uid, $cat, $k) === $compare_value) { + return true; + } + + self::getApp()->setPConfigValue($uid, $cat, $k, $value); + + // manage array value + $dbvalue = is_array($value) ? serialize($value) : $value; + + $result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true); + if (!$result) { + throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']'); + } + + return true; + } + + public function delete($uid, $cat, $k) + { + self::getApp()->deletePConfigValue($uid, $cat, $k); + + $result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]); + + return $result; + } +} diff --git a/src/Core/PConfig.php b/src/Core/PConfig.php index 82d4690838..bfa52f5a36 100644 --- a/src/Core/PConfig.php +++ b/src/Core/PConfig.php @@ -1,20 +1,18 @@ config['system']['config_adapter']) && $a->config['system']['config_adapter'] == 'preload') { + self::$adapter = new Config\PreloadPConfigAdapter($uid); + } else { + self::$adapter = new Config\JITPConfigAdapter($uid); + } + } /** * @brief Loads all configuration values of a user's config family into a cached storage. @@ -39,20 +51,11 @@ class PConfig */ public static function load($uid, $family) { - $a = get_app(); - - $r = dba::select('pconfig', ['v', 'k'], ['cat' => $family, 'uid' => $uid]); - if (DBM::is_result($r)) { - while ($rr = dba::fetch($r)) { - $k = $rr['k']; - $a->config[$uid][$family][$k] = $rr['v']; - self::$in_db[$uid][$family][$k] = true; - } - } else if ($family != 'config') { - // Negative caching - $a->config[$uid][$family] = "!!"; + if (empty(self::$adapter)) { + self::init($uid); } - dba::close($r); + + self::$adapter->load($uid, $family); } /** @@ -72,37 +75,11 @@ class PConfig */ public static function get($uid, $family, $key, $default_value = null, $refresh = false) { - $a = get_app(); - - if (!$refresh) { - // Looking if the whole family isn't set - if (isset($a->config[$uid][$family])) { - if ($a->config[$uid][$family] === '!!') { - return $default_value; - } - } - - if (isset($a->config[$uid][$family][$key])) { - if ($a->config[$uid][$family][$key] === '!!') { - return $default_value; - } - return $a->config[$uid][$family][$key]; - } + if (empty(self::$adapter)) { + self::init($uid); } - $pconfig = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $family, 'k' => $key]); - if (DBM::is_result($pconfig)) { - $val = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']); - $a->config[$uid][$family][$key] = $val; - self::$in_db[$uid][$family][$key] = true; - - return $val; - } else { - $a->config[$uid][$family][$key] = '!!'; - self::$in_db[$uid][$family][$key] = false; - - return $default_value; - } + return self::$adapter->get($uid, $family, $key, $default_value, $refresh); } /** @@ -122,31 +99,11 @@ class PConfig */ public static function set($uid, $family, $key, $value) { - $a = get_app(); - - // We store our setting values in a string variable. - // So we have to do the conversion here so that the compare below works. - // The exception are array values. - $dbvalue = (!is_array($value) ? (string)$value : $value); - - $stored = self::get($uid, $family, $key, null, true); - - if (($stored === $dbvalue) && self::$in_db[$uid][$family][$key]) { - return true; + if (empty(self::$adapter)) { + self::init($uid); } - $a->config[$uid][$family][$key] = $dbvalue; - - // manage array value - $dbvalue = (is_array($value) ? serialize($value) : $dbvalue); - - $ret = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $family, 'k' => $key], true); - - if ($ret) { - self::$in_db[$uid][$family][$key] = true; - return $value; - } - return $ret; + return self::$adapter->set($uid, $family, $key, $value); } /** @@ -163,15 +120,10 @@ class PConfig */ public static function delete($uid, $family, $key) { - $a = get_app(); - - if (x($a->config[$uid][$family], $key)) { - unset($a->config[$uid][$family][$key]); - unset(self::$in_db[$uid][$family][$key]); + if (empty(self::$adapter)) { + self::init($uid); } - $ret = dba::delete('pconfig', ['uid' => $uid, 'cat' => $family, 'k' => $key]); - - return $ret; + return self::$adapter->delete($uid, $family, $key); } } diff --git a/util/maintenance.php b/util/maintenance.php index a697e66d5a..f0d7777765 100644 --- a/util/maintenance.php +++ b/util/maintenance.php @@ -2,16 +2,17 @@ /** * @file util/maintenance.php */ + use Friendica\App; +use Friendica\BaseObject; use Friendica\Core\Config; use Friendica\Core\L10n; require_once 'boot.php'; require_once 'include/dba.php'; -if (empty($a)) { - $a = new App(dirname(__DIR__)); -} +$a = new App(dirname(__DIR__)); +BaseObject::setApp($a); @include(".htconfig.php"); diff --git a/util/typo.php b/util/typo.php index 313033f3e5..fba761e819 100755 --- a/util/typo.php +++ b/util/typo.php @@ -5,7 +5,9 @@ // Run this from cmdline in basedir and quickly see if we've // got any parse errors in our application files. + use Friendica\App; +use Friendica\BaseObject; error_reporting(E_ERROR | E_WARNING | E_PARSE); ini_set('display_errors', '1'); @@ -13,15 +15,12 @@ ini_set('log_errors', '0'); include 'boot.php'; -if (empty($a)) { - $a = new App(dirname(__DIR__)); -} +$a = new App(dirname(__DIR__)); +BaseObject::setApp($a); -if (x($a->config, 'php_path')) { - $phpath = $a->config['php_path']; -} else { - $phpath = 'php'; -} +@include '.htconfig.php'; + +$phpath = $a->getConfigValue('config', 'php_path', 'php'); echo 'Directory: src' . PHP_EOL; $Iterator = new RecursiveDirectoryIterator('src');