From 8c3aebc376a496e5f6ac93cda8ba88b1bd1261fa Mon Sep 17 00:00:00 2001
From: Philipp Holzer <admin@philipp.info>
Date: Fri, 22 Feb 2019 23:51:13 +0100
Subject: [PATCH] Bugfixings in Config

- replaced usage of "!<unset>!" with null-returns
- fixed bool settings (0/1)
- fixed overriding config-values
- fixed basepath problems
---
 bin/daemon.php                                |  4 +-
 src/App.php                                   |  6 +-
 src/Core/Config.php                           |  2 -
 .../Adapter/AbstractDbaConfigAdapter.php      | 64 ++++++++++++++++++-
 src/Core/Config/Adapter/IConfigAdapter.php    |  8 ++-
 src/Core/Config/Adapter/IPConfigAdapter.php   |  6 +-
 src/Core/Config/Adapter/JITConfigAdapter.php  | 38 ++++++-----
 src/Core/Config/Adapter/JITPConfigAdapter.php | 29 +++++----
 .../Config/Adapter/PreloadConfigAdapter.php   | 14 ++--
 .../Config/Adapter/PreloadPConfigAdapter.php  | 14 ++--
 src/Core/Config/Cache/ConfigCache.php         | 38 ++---------
 src/Core/Config/Cache/ConfigCacheLoader.php   |  3 -
 src/Core/Config/Cache/IConfigCache.php        | 13 +---
 src/Core/Config/Cache/IPConfigCache.php       | 13 +---
 src/Core/Config/Configuration.php             | 11 ++--
 src/Core/Config/PConfiguration.php            |  9 +--
 src/Core/PConfig.php                          |  2 -
 src/Database/DBA.php                          |  9 ++-
 src/Factory/DBFactory.php                     | 13 ++--
 src/Factory/DependencyFactory.php             |  8 +--
 src/Model/Photo.php                           |  4 +-
 tests/include/ApiTest.php                     |  8 +--
 tests/src/Database/DBATest.php                |  8 +--
 tests/src/Database/DBStructureTest.php        |  8 +--
 24 files changed, 175 insertions(+), 157 deletions(-)

diff --git a/bin/daemon.php b/bin/daemon.php
index 047bf71be7..298cfa2534 100755
--- a/bin/daemon.php
+++ b/bin/daemon.php
@@ -144,7 +144,9 @@ if (!$foreground) {
 	file_put_contents($pidfile, $pid);
 
 	// We lose the database connection upon forking
-	Factory\DBFactory::init($a->getConfigCache(), $a->getProfiler(), $_SERVER);
+	/// @todo refactoring during https://github.com/friendica/friendica/issues/6720
+	$basePath = \Friendica\Util\BasePath::create(dirname(__DIR__), $_SERVER);
+	Factory\DBFactory::init($basePath, $a->getConfigCache(), $a->getProfiler(), $_SERVER);
 }
 
 Config::set('system', 'worker_daemon_mode', true);
diff --git a/src/App.php b/src/App.php
index 3df285cb38..e5ac5dda3c 100644
--- a/src/App.php
+++ b/src/App.php
@@ -205,6 +205,7 @@ class App
 	/**
 	 * @brief App constructor.
 	 *
+	 * @param string           $basePath   The basedir of the app
 	 * @param Configuration    $config    The Configuration
 	 * @param LoggerInterface  $logger    The current app logger
 	 * @param Profiler         $profiler  The profiler of this application
@@ -212,14 +213,15 @@ class App
 	 *
 	 * @throws Exception if the Basepath is not usable
 	 */
-	public function __construct(Configuration $config, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
+	public function __construct($basePath, Configuration $config, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
 	{
 		BaseObject::setApp($this);
 
 		$this->logger   = $logger;
 		$this->config   = $config;
 		$this->profiler = $profiler;
-		$this->basePath = $this->config->get('system', 'basepath');
+		$cfgBasePath = $this->config->get('system', 'basepath');
+		$this->basePath = (isset($cfgBasePath) && $cfgBasePath !== '') ? $cfgBasePath : $basePath;
 
 		if (!Core\System::isDirectoryUsable($this->basePath, false)) {
 			throw new Exception('Basepath \'' . $this->basePath . '\' isn\'t usable.');
diff --git a/src/Core/Config.php b/src/Core/Config.php
index 4bf9c5b11d..f974e2fff2 100644
--- a/src/Core/Config.php
+++ b/src/Core/Config.php
@@ -65,8 +65,6 @@ class Config
 	 *
 	 * Stores a config value ($value) in the category ($cat) under the key ($key)
 	 *
-	 * Note: Please do not store booleans - convert to 0/1 integer values!
-	 *
 	 * @param string $cat The category of the configuration value
 	 * @param string $key    The configuration key to set
 	 * @param mixed  $value  The value to store
diff --git a/src/Core/Config/Adapter/AbstractDbaConfigAdapter.php b/src/Core/Config/Adapter/AbstractDbaConfigAdapter.php
index 770dfd2c95..38caf35cac 100644
--- a/src/Core/Config/Adapter/AbstractDbaConfigAdapter.php
+++ b/src/Core/Config/Adapter/AbstractDbaConfigAdapter.php
@@ -6,7 +6,11 @@ use Friendica\Database\DBA;
 
 abstract class AbstractDbaConfigAdapter
 {
-	/** @var bool */
+	/**
+	 * The connection state of the adapter
+	 *
+	 * @var bool
+	 */
 	protected $connected = true;
 
 	public function __construct()
@@ -14,8 +18,66 @@ abstract class AbstractDbaConfigAdapter
 		$this->connected = DBA::connected();
 	}
 
+	/**
+	 * Checks if the adapter is currently connected
+	 *
+	 * @return bool
+	 */
 	public function isConnected()
 	{
 		return $this->connected;
 	}
+
+	/**
+	 * Formats a DB value to a config value
+	 * - null   = The db-value isn't set
+	 * - bool   = The db-value is either '0' or '1'
+	 * - array  = The db-value is a serialized array
+	 * - string = The db-value is a string
+	 *
+	 * Keep in mind that there aren't any numeric/integer config values in the database
+	 *
+	 * @param null|string $value
+	 *
+	 * @return null|array|string
+	 */
+	protected function toConfigValue($value)
+	{
+		if (!isset($value)) {
+			return null;
+		}
+
+		switch (true) {
+			// manage array value
+			case preg_match("|^a:[0-9]+:{.*}$|s", $value):
+				return unserialize($value);
+
+			default:
+				return $value;
+		}
+	}
+
+	/**
+	 * Formats a config value to a DB value (string)
+	 *
+	 * @param mixed $value
+	 *
+	 * @return string
+	 */
+	protected function toDbValue($value)
+	{
+		// if not set, save an empty string
+		if (!isset($value)) {
+			return '';
+		}
+
+		switch (true) {
+			// manage arrays
+			case is_array($value):
+				return serialize($value);
+
+			default:
+				return (string)$value;
+		}
+	}
 }
diff --git a/src/Core/Config/Adapter/IConfigAdapter.php b/src/Core/Config/Adapter/IConfigAdapter.php
index 21cd9a4b2a..892c476e7c 100644
--- a/src/Core/Config/Adapter/IConfigAdapter.php
+++ b/src/Core/Config/Adapter/IConfigAdapter.php
@@ -21,10 +21,12 @@ interface IConfigAdapter
 	 * Get a particular system-wide config variable given the category name
 	 * ($family) and a key.
 	 *
+	 * Note: Boolean variables are defined as 0/1 in the database
+	 *
 	 * @param string  $cat The category of the configuration value
 	 * @param string  $key The configuration key to query
 	 *
-	 * @return mixed Stored value or "!<unset>!" if it does not exist
+	 * @return null|mixed Stored value or null if it does not exist
 	 */
 	public function get($cat, $key);
 
@@ -46,9 +48,9 @@ interface IConfigAdapter
 	 * and removes it from the database.
 	 *
 	 * @param string $cat The category of the configuration value
-	 * @param string $key   The configuration key to delete
+	 * @param string $key The configuration key to delete
 	 *
-	 * @return mixed
+	 * @return bool Operation success
 	 */
 	public function delete($cat, $key);
 
diff --git a/src/Core/Config/Adapter/IPConfigAdapter.php b/src/Core/Config/Adapter/IPConfigAdapter.php
index 8e6c050b27..c505532c59 100644
--- a/src/Core/Config/Adapter/IPConfigAdapter.php
+++ b/src/Core/Config/Adapter/IPConfigAdapter.php
@@ -28,11 +28,13 @@ interface IPConfigAdapter
 	 * Get a particular user's config variable given the category name
 	 * ($family) and a key.
 	 *
+	 * Note: Boolean variables are defined as 0/1 in the database
+	 *
 	 * @param string  $uid           The user_id
 	 * @param string  $cat           The category of the configuration value
 	 * @param string  $key           The configuration key to query
 	 *
-	 * @return mixed Stored value or "!<unset>!" if it does not exist
+	 * @return null|mixed Stored value or null if it does not exist
 	 */
 	public function get($uid, $cat, $key);
 
@@ -59,7 +61,7 @@ interface IPConfigAdapter
 	 * @param string $cat The category of the configuration value
 	 * @param string $key The configuration key to delete
 	 *
-	 * @return bool
+	 * @return bool Operation success
 	 */
 	public function delete($uid, $cat, $key);
 
diff --git a/src/Core/Config/Adapter/JITConfigAdapter.php b/src/Core/Config/Adapter/JITConfigAdapter.php
index c0d680d2c9..5a41463036 100644
--- a/src/Core/Config/Adapter/JITConfigAdapter.php
+++ b/src/Core/Config/Adapter/JITConfigAdapter.php
@@ -34,40 +34,49 @@ class JITConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapte
 		$configs = DBA::select('config', ['v', 'k'], ['cat' => $cat]);
 		while ($config = DBA::fetch($configs)) {
 			$key   = $config['k'];
-			$value = $config['v'];
+			$value = $this->toConfigValue($config['v']);
 
-			if (isset($value) && $value !== '') {
+			// The value was in the db, so don't check it again (unless you have to)
+			$this->in_db[$cat][$key] = true;
+
+			// just save it in case it is set
+			if (isset($value)) {
 				$return[$key] = $value;
-				$this->in_db[$cat][$key] = true;
 			}
 		}
 		DBA::close($configs);
 
-		return [$cat => $config];
+		return [$cat => $return];
 	}
 
 	/**
 	 * {@inheritdoc}
+	 *
+	 * @param bool $mark if true, mark the selection of the current cat/key pair
 	 */
-	public function get($cat, $key)
+	public function get($cat, $key, $mark = true)
 	{
 		if (!$this->isConnected()) {
-			return '!<unset>!';
+			return null;
+		}
+
+		// The value got checked, so mark it to avoid checking it over and over again
+		if ($mark) {
+			$this->in_db[$cat][$key] = true;
 		}
 
 		$config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
 		if (DBA::isResult($config)) {
 			// manage array value
-			$value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
+			$value = $this->toConfigValue($config['v']);
 
-			if (isset($value) && $value !== '') {
-				$this->in_db[$cat][$key] = true;
+			// just return it in case it is set
+			if (isset($value)) {
 				return $value;
 			}
 		}
 
-		$this->in_db[$cat][$key] = false;
-		return '!<unset>!';
+		return null;
 	}
 
 	/**
@@ -84,7 +93,7 @@ class JITConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapte
 		// The exception are array values.
 		$dbvalue = (!is_array($value) ? (string)$value : $value);
 
-		$stored = $this->get($cat, $key);
+		$stored = $this->get($cat, $key, false);
 
 		if (!isset($this->in_db[$cat])) {
 			$this->in_db[$cat] = [];
@@ -93,12 +102,11 @@ class JITConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapte
 			$this->in_db[$cat][$key] = false;
 		}
 
-		if (($stored === $dbvalue) && $this->in_db[$cat][$key]) {
+		if (isset($stored) && ($stored === $dbvalue) && $this->in_db[$cat][$key]) {
 			return true;
 		}
 
-		// manage array value
-		$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
+		$dbvalue = $this->toDbValue($dbvalue);
 
 		$result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $key], true);
 
diff --git a/src/Core/Config/Adapter/JITPConfigAdapter.php b/src/Core/Config/Adapter/JITPConfigAdapter.php
index 4485ee5df9..e320104e73 100644
--- a/src/Core/Config/Adapter/JITPConfigAdapter.php
+++ b/src/Core/Config/Adapter/JITPConfigAdapter.php
@@ -29,16 +29,18 @@ class JITPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfigAdap
 		if (DBA::isResult($pconfigs)) {
 			while ($pconfig = DBA::fetch($pconfigs)) {
 				$key = $pconfig['k'];
-				$value = $pconfig['v'];
+				$value = $this->toConfigValue($pconfig['v']);
 
-				if (isset($value) && $value !== '') {
+				// The value was in the db, so don't check it again (unless you have to)
+				$this->in_db[$uid][$cat][$key] = true;
+
+				if (isset($value)) {
 					$return[$key] = $value;
-					$this->in_db[$uid][$cat][$key] = true;
 				}
 			}
 		} else if ($cat != 'config') {
 			// Negative caching
-			$return = "!<unset>!";
+			$return = null;
 		}
 		DBA::close($pconfigs);
 
@@ -51,22 +53,23 @@ class JITPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfigAdap
 	public function get($uid, $cat, $key)
 	{
 		if (!$this->isConnected()) {
-			return '!<unset>!';
+			return null;
 		}
 
+		// The value was in the db, so don't check it again (unless you have to)
+		$this->in_db[$uid][$cat][$key] = true;
+
 		$pconfig = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
 		if (DBA::isResult($pconfig)) {
-			// manage array value
-			$value = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']);
+			$value = $this->toConfigValue($pconfig['v']);
 
-			if (isset($value) && $value !== '') {
-				$this->in_db[$uid][$cat][$key] = true;
+			if (isset($value)) {
 				return $value;
 			}
 		}
 
 		$this->in_db[$uid][$cat][$key] = false;
-		return '!<unset>!';
+		return null;
 	}
 
 	/**
@@ -118,13 +121,11 @@ class JITPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfigAdap
 			return false;
 		}
 
-		if (!empty($this->in_db[$uid][$cat][$key])) {
+		if (isset($this->in_db[$uid][$cat][$key])) {
 			unset($this->in_db[$uid][$cat][$key]);
 		}
 
-		$result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
-
-		return $result;
+		return DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
 	}
 
 	/**
diff --git a/src/Core/Config/Adapter/PreloadConfigAdapter.php b/src/Core/Config/Adapter/PreloadConfigAdapter.php
index 218648cbdb..7ebd1efcf8 100644
--- a/src/Core/Config/Adapter/PreloadConfigAdapter.php
+++ b/src/Core/Config/Adapter/PreloadConfigAdapter.php
@@ -35,8 +35,6 @@ class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAd
 			$value = $config['v'];
 			if (isset($value) && $value !== '') {
 				$return[$config['cat']][$config['k']] = $value;
-			} else {
-				$return[$config['cat']][$config['k']] = '!<unset>!';
 			}
 		}
 		DBA::close($configs);
@@ -52,7 +50,7 @@ class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAd
 	public function get($cat, $key)
 	{
 		if (!$this->isConnected()) {
-			return '!<unset>!';
+			return null;
 		}
 
 		$config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
@@ -65,7 +63,7 @@ class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAd
 			}
 		}
 
-		return '!<unset>!';
+		return null;
 	}
 
 	/**
@@ -89,9 +87,7 @@ class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAd
 		// manage array value
 		$dbvalue = is_array($value) ? serialize($value) : $value;
 
-		$result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $key], true);
-
-		return $result;
+		return DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $key], true);
 	}
 
 	/**
@@ -103,9 +99,7 @@ class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAd
 			return false;
 		}
 
-		$result = DBA::delete('config', ['cat' => $cat, 'k' => $key]);
-
-		return $result;
+		return DBA::delete('config', ['cat' => $cat, 'k' => $key]);
 	}
 
 	/**
diff --git a/src/Core/Config/Adapter/PreloadPConfigAdapter.php b/src/Core/Config/Adapter/PreloadPConfigAdapter.php
index 12e25df9f9..d2ba971ff6 100644
--- a/src/Core/Config/Adapter/PreloadPConfigAdapter.php
+++ b/src/Core/Config/Adapter/PreloadPConfigAdapter.php
@@ -52,8 +52,6 @@ class PreloadPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfig
 			$value = $pconfig['v'];
 			if (isset($value) && $value !== '') {
 				$return[$pconfig['cat']][$pconfig['k']] = $value;
-			} else {
-				$return[$pconfig['cat']][$pconfig['k']] = '!<unset>!';
 			}
 		}
 		DBA::close($pconfigs);
@@ -69,7 +67,7 @@ class PreloadPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfig
 	public function get($uid, $cat, $key)
 	{
 		if (!$this->isConnected()) {
-			return '!<unset>!';
+			return null;
 		}
 
 		if (!$this->isLoaded($uid, $cat, $key)) {
@@ -85,7 +83,7 @@ class PreloadPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfig
 				return $value;
 			}
 		}
-		return '!<unset>!';
+		return null;
 	}
 
 	/**
@@ -112,9 +110,7 @@ class PreloadPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfig
 		// manage array value
 		$dbvalue = is_array($value) ? serialize($value) : $value;
 
-		$result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $key], true);
-
-		return $result;
+		return DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $key], true);
 	}
 
 	/**
@@ -130,9 +126,7 @@ class PreloadPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfig
 			$this->load($uid, $cat);
 		}
 
-		$result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
-
-		return $result;
+		return DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
 	}
 
 	/**
diff --git a/src/Core/Config/Cache/ConfigCache.php b/src/Core/Config/Cache/ConfigCache.php
index 4ebcc87482..cf50b43d4f 100644
--- a/src/Core/Config/Cache/ConfigCache.php
+++ b/src/Core/Config/Cache/ConfigCache.php
@@ -6,8 +6,6 @@ namespace Friendica\Core\Config\Cache;
  * The Friendica config cache for the application
  * Initial, all *.config.php files are loaded into this cache with the
  * ConfigCacheLoader ( @see ConfigCacheLoader )
- *
- * Is used for further caching operations too (depending on the ConfigAdapter )
  */
 class ConfigCache implements IConfigCache, IPConfigCache
 {
@@ -37,7 +35,7 @@ class ConfigCache implements IConfigCache, IPConfigCache
 
 				foreach ($keys as $key) {
 					$value = $config[$category][$key];
-					if (isset($value) && $value !== '!<unset>!') {
+					if (isset($value)) {
 						if ($overwrite) {
 							$this->set($category, $key, $value);
 						} else {
@@ -56,22 +54,13 @@ class ConfigCache implements IConfigCache, IPConfigCache
 	{
 		if (isset($this->config[$cat][$key])) {
 			return $this->config[$cat][$key];
-		} elseif ($key == null && isset($this->config[$cat])) {
+		} elseif (!isset($key) && isset($this->config[$cat])) {
 			return $this->config[$cat];
 		} else {
-			return '!<unset>!';
+			return null;
 		}
 	}
 
-	/**
-	 * {@inheritdoc}
-	 */
-	public function has($cat, $key = null)
-	{
-		return (isset($this->config[$cat][$key]) && $this->config[$cat][$key] !== '!<unset>!') ||
-		($key == null && isset($this->config[$cat]) && $this->config[$cat] !== '!<unset>!' && is_array($this->config[$cat]));
-	}
-
 	/**
 	 * Sets a default value in the config cache. Ignores already existing keys.
 	 *
@@ -91,9 +80,6 @@ class ConfigCache implements IConfigCache, IPConfigCache
 	 */
 	public function set($cat, $key, $value)
 	{
-		// Only arrays are serialized in database, so we have to unserialize sparingly
-		$value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
-
 		if (!isset($this->config[$cat])) {
 			$this->config[$cat] = [];
 		}
@@ -103,15 +89,6 @@ class ConfigCache implements IConfigCache, IPConfigCache
 		return true;
 	}
 
-	/**
-	 * {@inheritdoc}
-	 */
-	public function hasP($uid, $cat, $key = null)
-	{
-		return (isset($this->config[$uid][$cat][$key]) && $this->config[$uid][$cat][$key] !== '!<unset>!') ||
-			($key == null && isset($this->config[$uid][$cat]) && $this->config[$uid][$cat] !== '!<unset>!' && is_array($this->config[$uid][$cat]));
-	}
-
 	/**
 	 * {@inheritdoc}
 	 */
@@ -142,7 +119,7 @@ class ConfigCache implements IConfigCache, IPConfigCache
 
 				foreach ($keys as $key) {
 					$value = $config[$category][$key];
-					if (isset($value) && $value !== '!<unset>!') {
+					if (isset($value)) {
 						$this->setP($uid, $category, $key, $value);
 					}
 				}
@@ -157,10 +134,10 @@ class ConfigCache implements IConfigCache, IPConfigCache
 	{
 		if (isset($this->config[$uid][$cat][$key])) {
 			return $this->config[$uid][$cat][$key];
-		} elseif ($key == null && isset($this->config[$uid][$cat])) {
+		} elseif (!isset($key) && isset($this->config[$uid][$cat])) {
 			return $this->config[$uid][$cat];
 		} else {
-			return '!<unset>!';
+			return null;
 		}
 	}
 
@@ -169,9 +146,6 @@ class ConfigCache implements IConfigCache, IPConfigCache
 	 */
 	public function setP($uid, $cat, $key, $value)
 	{
-		// Only arrays are serialized in database, so we have to unserialize sparingly
-		$value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
-
 		if (!isset($this->config[$uid]) || !is_array($this->config[$uid])) {
 			$this->config[$uid] = [];
 		}
diff --git a/src/Core/Config/Cache/ConfigCacheLoader.php b/src/Core/Config/Cache/ConfigCacheLoader.php
index b728d10821..b043bf27cb 100644
--- a/src/Core/Config/Cache/ConfigCacheLoader.php
+++ b/src/Core/Config/Cache/ConfigCacheLoader.php
@@ -37,9 +37,6 @@ class ConfigCacheLoader
 	 */
 	public function loadConfigFiles(ConfigCache $config)
 	{
-		// Setting at least the basepath we know
-		$config->set('system', 'basepath', $this->baseDir);
-
 		$config->load($this->loadCoreConfig('defaults'));
 		$config->load($this->loadCoreConfig('settings'));
 
diff --git a/src/Core/Config/Cache/IConfigCache.php b/src/Core/Config/Cache/IConfigCache.php
index 9d948527d4..499bd312d0 100644
--- a/src/Core/Config/Cache/IConfigCache.php
+++ b/src/Core/Config/Cache/IConfigCache.php
@@ -20,9 +20,9 @@ interface IConfigCache
 	 * Gets a value from the config cache.
 	 *
 	 * @param string $cat     Config category
-	 * @param string $key       Config key
+	 * @param string $key     Config key
 	 *
-	 * @return mixed Returns the value of the Config entry or '!<unset>!' if not set
+	 * @return null|mixed Returns the value of the Config entry or null if not set
 	 */
 	function get($cat, $key = null);
 
@@ -47,15 +47,6 @@ interface IConfigCache
 	 */
 	function delete($cat, $key);
 
-	/**
-	 * Checks if a value is set in the config cache.
-	 *
-	 * @param string $cat  Config category
-	 * @param string $key  Config key
-	 * @return bool
-	 */
-	function has($cat, $key = null);
-
 	/**
 	 * Returns the whole configuration cache
 	 *
diff --git a/src/Core/Config/Cache/IPConfigCache.php b/src/Core/Config/Cache/IPConfigCache.php
index 4ac21481a1..30076a2a93 100644
--- a/src/Core/Config/Cache/IPConfigCache.php
+++ b/src/Core/Config/Cache/IPConfigCache.php
@@ -23,7 +23,7 @@ interface IPConfigCache
 	 * @param string $cat     Config category
 	 * @param string $key     Config key
 	 *
-	 * @return string The value of the config entry or '!<unset>!' if not set
+	 * @return null|string The value of the config entry or null if not set
 	 */
 	function getP($uid, $cat, $key = null);
 
@@ -50,17 +50,6 @@ interface IPConfigCache
 	 */
 	function deleteP($uid, $cat, $key);
 
-
-	/**
-	 * Checks if a value is set in the user config cache.
-	 *
-	 * @param int    $uid  User Id
-	 * @param string $cat  Config category
-	 * @param string $key  Config key
-	 * @return bool
-	 */
-	function hasP($uid, $cat, $key = null);
-
 	/**
 	 * Returns the whole configuration cache
 	 *
diff --git a/src/Core/Config/Configuration.php b/src/Core/Config/Configuration.php
index 2ac0da0ad1..532ed982a9 100644
--- a/src/Core/Config/Configuration.php
+++ b/src/Core/Config/Configuration.php
@@ -83,20 +83,19 @@ class Configuration
 		if ($this->configAdapter->isConnected() &&
 			(!$this->configAdapter->isLoaded($cat, $key) ||
 			$refresh)) {
+
 			$dbvalue = $this->configAdapter->get($cat, $key);
 
-			if ($dbvalue !== '!<unset>!') {
+			if (isset($dbvalue)) {
 				$this->configCache->set($cat, $key, $dbvalue);
 				return $dbvalue;
 			}
 		}
 
 		// use the config cache for return
-		if ($this->configCache->has($cat, $key)) {
-			return $this->configCache->get($cat, $key);
-		} else {
-			return $default_value;
-		}
+		$result = $this->configCache->get($cat, $key);
+
+		return (isset($result)) ? $result : $default_value;
 	}
 
 	/**
diff --git a/src/Core/Config/PConfiguration.php b/src/Core/Config/PConfiguration.php
index 99b1aa1469..0d3b0c178c 100644
--- a/src/Core/Config/PConfiguration.php
+++ b/src/Core/Config/PConfiguration.php
@@ -77,18 +77,15 @@ class PConfiguration
 				$refresh)) {
 			$dbValue = $this->configAdapter->get($uid, $cat, $key);
 
-			if ($dbValue !== '!<unset>!') {
+			if (isset($dbValue)) {
 				$this->configCache->setP($uid, $cat, $key, $dbValue);
 				return $dbValue;
 			}
 		}
 
 		// use the config cache for return
-		if ($this->configCache->hasP($uid, $cat, $key)) {
-			return $this->configCache->getP($uid, $cat, $key);
-		} else {
-			return $default_value;
-		}
+		$result = $this->configCache->getP($uid, $cat, $key);
+		return (isset($result)) ? $result : $default_value;
 	}
 
 	/**
diff --git a/src/Core/PConfig.php b/src/Core/PConfig.php
index f62b59f476..da4c802937 100644
--- a/src/Core/PConfig.php
+++ b/src/Core/PConfig.php
@@ -65,8 +65,6 @@ class PConfig
 	/**
 	 * @brief Sets a configuration value for a user
 	 *
-	 * @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 $key    The configuration key to set
diff --git a/src/Database/DBA.php b/src/Database/DBA.php
index 1c17d9aca5..97e5c63c80 100644
--- a/src/Database/DBA.php
+++ b/src/Database/DBA.php
@@ -40,6 +40,10 @@ class DBA
 	 * @var Profiler
 	 */
 	private static $profiler;
+	/**
+	 * @var string
+	 */
+	private static $basedir;
 	private static $server_info = '';
 	private static $connection;
 	private static $driver;
@@ -55,13 +59,14 @@ class DBA
 	private static $db_name = '';
 	private static $db_charset = '';
 
-	public static function connect(IConfigCache $configCache, Profiler $profiler, $serveraddr, $user, $pass, $db, $charset = null)
+	public static function connect($basedir, IConfigCache $configCache, Profiler $profiler, $serveraddr, $user, $pass, $db, $charset = null)
 	{
 		if (!is_null(self::$connection) && self::connected()) {
 			return true;
 		}
 
 		// We are storing these values for being able to perform a reconnect
+		self::$basedir = $basedir;
 		self::$configCache = $configCache;
 		self::$profiler = $profiler;
 		self::$db_serveraddr = $serveraddr;
@@ -1034,7 +1039,7 @@ class DBA
 	 * This process must only be started once, since the value is cached.
 	 */
 	private static function buildRelationData() {
-		$definition = DBStructure::definition(self::$configCache->get('system', 'basepath'));
+		$definition = DBStructure::definition(self::$basedir);
 
 		foreach ($definition AS $table => $structure) {
 			foreach ($structure['fields'] AS $field => $field_struct) {
diff --git a/src/Factory/DBFactory.php b/src/Factory/DBFactory.php
index c1a7965013..b4f0c9e3c1 100644
--- a/src/Factory/DBFactory.php
+++ b/src/Factory/DBFactory.php
@@ -11,13 +11,16 @@ class DBFactory
 	/**
 	 * Initialize the DBA connection
 	 *
+	 * @param string             $basePath    The basepath of the application
 	 * @param Cache\IConfigCache $configCache The configuration cache
-	 * @param Profiler          $profiler    The profiler
-	 * @param array             $server      The $_SERVER variables
+	 * @param Profiler           $profiler    The profiler
+	 * @param array              $server      The $_SERVER variables
 	 *
 	 * @throws \Exception if connection went bad
+	 *
+	 * @todo refactor basedir during https://github.com/friendica/friendica/issues/6720
 	 */
-	public static function init(Cache\IConfigCache $configCache, Profiler $profiler, array $server)
+	public static function init($basePath, Cache\IConfigCache $configCache, Profiler $profiler, array $server)
 	{
 		if (Database\DBA::connected()) {
 			return;
@@ -48,9 +51,9 @@ class DBFactory
 			$db_data = $server['MYSQL_DATABASE'];
 		}
 
-		if (Database\DBA::connect($configCache, $profiler, $db_host, $db_user, $db_pass, $db_data, $charset)) {
+		if (Database\DBA::connect($basePath, $configCache, $profiler, $db_host, $db_user, $db_pass, $db_data, $charset)) {
 			// Loads DB_UPDATE_VERSION constant
-			Database\DBStructure::definition($configCache->get('system', 'basepath'), false);
+			Database\DBStructure::definition($basePath, false);
 		}
 
 		unset($db_host, $db_user, $db_pass, $db_data, $charset);
diff --git a/src/Factory/DependencyFactory.php b/src/Factory/DependencyFactory.php
index acbf4bfaf7..52178bb77f 100644
--- a/src/Factory/DependencyFactory.php
+++ b/src/Factory/DependencyFactory.php
@@ -22,16 +22,16 @@ class DependencyFactory
 	 */
 	public static function setUp($channel, $directory, $isBackend = true)
 	{
-		$basedir = BasePath::create($directory, $_SERVER);
-		$configLoader = new Cache\ConfigCacheLoader($basedir);
+		$basePath = BasePath::create($directory, $_SERVER);
+		$configLoader = new Cache\ConfigCacheLoader($basePath);
 		$configCache = Factory\ConfigFactory::createCache($configLoader);
 		$profiler = Factory\ProfilerFactory::create($configCache);
-		Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+		Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
 		$config = Factory\ConfigFactory::createConfig($configCache);
 		// needed to call PConfig::init()
 		Factory\ConfigFactory::createPConfig($configCache);
 		$logger = Factory\LoggerFactory::create($channel, $config);
 
-		return new App($config, $logger, $profiler, $isBackend);
+		return new App($basePath, $config, $logger, $profiler, $isBackend);
 	}
 }
diff --git a/src/Model/Photo.php b/src/Model/Photo.php
index 152e870e85..8ad7f3145f 100644
--- a/src/Model/Photo.php
+++ b/src/Model/Photo.php
@@ -10,8 +10,8 @@ use Friendica\BaseObject;
 use Friendica\Core\Cache;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
-use Friendica\Core\System;
 use Friendica\Core\StorageManager;
+use Friendica\Core\System;
 use Friendica\Database\DBA;
 use Friendica\Database\DBStructure;
 use Friendica\Model\Storage\IStorage;
@@ -203,7 +203,7 @@ class Photo extends BaseObject
 	 */
 	private static function getFields()
 	{
-		$allfields = DBStructure::definition(false);
+		$allfields = DBStructure::definition(self::getApp()->getBasePath(), false);
 		$fields = array_keys($allfields["photo"]["fields"]);
 		array_splice($fields, array_search("data", $fields), 1);
 		return $fields;
diff --git a/tests/include/ApiTest.php b/tests/include/ApiTest.php
index 289b3fcea5..2f8becc18c 100644
--- a/tests/include/ApiTest.php
+++ b/tests/include/ApiTest.php
@@ -36,15 +36,15 @@ class ApiTest extends DatabaseTest
 	 */
 	public function setUp()
 	{
-		$basedir = BasePath::create(dirname(__DIR__) . '/../');
-		$configLoader = new Cache\ConfigCacheLoader($basedir);
+		$basePath = BasePath::create(dirname(__DIR__) . '/../');
+		$configLoader = new Cache\ConfigCacheLoader($basePath);
 		$configCache = Factory\ConfigFactory::createCache($configLoader);
 		$profiler = Factory\ProfilerFactory::create($configCache);
-		Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+		Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
 		$config = Factory\ConfigFactory::createConfig($configCache);
 		Factory\ConfigFactory::createPConfig($configCache);
 		$logger = Factory\LoggerFactory::create('test', $config);
-		$this->app = new App($config, $logger, $profiler, false);
+		$this->app = new App($basePath, $config, $logger, $profiler, false);
 
 		parent::setUp();
 
diff --git a/tests/src/Database/DBATest.php b/tests/src/Database/DBATest.php
index e8b9c68b19..8e102ec632 100644
--- a/tests/src/Database/DBATest.php
+++ b/tests/src/Database/DBATest.php
@@ -13,15 +13,15 @@ class DBATest extends DatabaseTest
 {
 	public function setUp()
 	{
-		$basedir = BasePath::create(dirname(__DIR__) . '/../../');
-		$configLoader = new Cache\ConfigCacheLoader($basedir);
+		$basePath = BasePath::create(dirname(__DIR__) . '/../../');
+		$configLoader = new Cache\ConfigCacheLoader($basePath);
 		$configCache = Factory\ConfigFactory::createCache($configLoader);
 		$profiler = Factory\ProfilerFactory::create($configCache);
-		Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+		Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
 		$config = Factory\ConfigFactory::createConfig($configCache);
 		Factory\ConfigFactory::createPConfig($configCache);
 		$logger = Factory\LoggerFactory::create('test', $config);
-		$this->app = new App($config, $logger, $profiler, false);
+		$this->app = new App($basePath, $config, $logger, $profiler, false);
 
 		parent::setUp();
 
diff --git a/tests/src/Database/DBStructureTest.php b/tests/src/Database/DBStructureTest.php
index 325ad4e5e7..454d6e8a4e 100644
--- a/tests/src/Database/DBStructureTest.php
+++ b/tests/src/Database/DBStructureTest.php
@@ -13,15 +13,15 @@ class DBStructureTest extends DatabaseTest
 {
 	public function setUp()
 	{
-		$basedir = BasePath::create(dirname(__DIR__) . '/../../');
-		$configLoader = new Cache\ConfigCacheLoader($basedir);
+		$basePath = BasePath::create(dirname(__DIR__) . '/../../');
+		$configLoader = new Cache\ConfigCacheLoader($basePath);
 		$configCache = Factory\ConfigFactory::createCache($configLoader);
 		$profiler = Factory\ProfilerFactory::create($configCache);
-		Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+		Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
 		$config = Factory\ConfigFactory::createConfig($configCache);
 		Factory\ConfigFactory::createPConfig($configCache);
 		$logger = Factory\LoggerFactory::create('test', $config);
-		$this->app = new App($config, $logger, $profiler, false);
+		$this->app = new App($basePath, $config, $logger, $profiler, false);
 
 		parent::setUp();
 	}
-- 
2.39.5