]> git.mxchange.org Git - friendica.git/commitdiff
Introduce ConfigFileManager for config files
authorPhilipp <admin@philipp.info>
Sun, 1 Jan 2023 20:10:37 +0000 (21:10 +0100)
committerPhilipp <admin@philipp.info>
Tue, 3 Jan 2023 13:22:02 +0000 (14:22 +0100)
22 files changed:
database.sql
doc/database.md
doc/database/db_config.md [deleted file]
src/App/BaseURL.php
src/Console/Maintenance.php
src/Console/Relocate.php
src/Core/Config/Capability/IManageConfigValues.php
src/Core/Config/Factory/Config.php
src/Core/Config/Repository/Config.php
src/Core/Config/Type/AbstractConfig.php
src/Core/Config/Type/JitConfig.php
src/Core/Config/Type/PreloadConfig.php
src/Core/Config/Util/ConfigFileLoader.php [deleted file]
src/Core/Config/Util/ConfigFileManager.php [new file with mode: 0644]
src/Core/Config/ValueObject/Cache.php
src/Core/KeyValueStorage/Type/DBKeyValueStorage.php
src/Core/Update.php
src/Database/DBStructure.php
src/Module/Admin/Site.php
static/dbstructure.config.php
static/dependencies.config.php
update.php

index 19007e6c03827d36b76ceb5f888a8082dbd4a05b..c413f2c24a03971c6ab6e3ba049c5cdc9ea0b5bc 100644 (file)
@@ -1,6 +1,6 @@
 -- ------------------------------------------
 -- Friendica 2023.03-dev (Giant Rhubarb)
--- DB_UPDATE_VERSION 1507
+-- DB_UPDATE_VERSION 1508
 -- ------------------------------------------
 
 
@@ -494,18 +494,6 @@ CREATE TABLE IF NOT EXISTS `cache` (
         INDEX `k_expires` (`k`,`expires`)
 ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Stores temporary data';
 
---
--- TABLE config
---
-CREATE TABLE IF NOT EXISTS `config` (
-       `id` int unsigned NOT NULL auto_increment COMMENT '',
-       `cat` varbinary(50) NOT NULL DEFAULT '' COMMENT '',
-       `k` varbinary(50) NOT NULL DEFAULT '' COMMENT '',
-       `v` mediumtext COMMENT '',
-        PRIMARY KEY(`id`),
-        UNIQUE INDEX `cat_k` (`cat`,`k`)
-) DEFAULT COLLATE utf8mb4_general_ci COMMENT='main configuration storage';
-
 --
 -- TABLE contact-relation
 --
index edfb7b82267ee0ae1389691b4aff65f2cb1f6495..95e0367afe9ab30f08ff578b55476c5efc72e537 100644 (file)
@@ -18,7 +18,6 @@ Database Tables
 | [arrived-activity](help/database/db_arrived-activity) | Id of arrived activities |
 | [attach](help/database/db_attach) | file attachments |
 | [cache](help/database/db_cache) | Stores temporary data |
-| [config](help/database/db_config) | main configuration storage |
 | [contact](help/database/db_contact) | contact table |
 | [contact-relation](help/database/db_contact-relation) | Contact relations |
 | [conv](help/database/db_conv) | private messages |
diff --git a/doc/database/db_config.md b/doc/database/db_config.md
deleted file mode 100644 (file)
index 7d76187..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Table config
-===========
-
-main configuration storage
-
-Fields
-------
-
-| Field | Description | Type          | Null | Key | Default | Extra          |
-| ----- | ----------- | ------------- | ---- | --- | ------- | -------------- |
-| id    |             | int unsigned  | NO   | PRI | NULL    | auto_increment |
-| cat   |             | varbinary(50) | NO   |     |         |                |
-| k     |             | varbinary(50) | NO   |     |         |                |
-| v     |             | mediumtext    | YES  |     | NULL    |                |
-
-Indexes
-------------
-
-| Name    | Fields         |
-| ------- | -------------- |
-| PRIMARY | id             |
-| cat_k   | UNIQUE, cat, k |
-
-
-Return to [database documentation](help/database)
index 20fd54916de153aa25dc0b29c25db450114a2f46..f79bae38f938394a15208d6ea4b3e7a255d9475e 100644 (file)
@@ -177,7 +177,7 @@ class BaseURL
                $currURLPath   = $this->urlPath;
 
                if (!empty($hostname) && $hostname !== $this->hostname) {
-                       if ($this->config->set('config', 'hostname', $hostname)) {
+                       if ($this->config->set('config', 'hostname', $hostname, false)) {
                                $this->hostname = $hostname;
                        } else {
                                return false;
@@ -185,40 +185,45 @@ class BaseURL
                }
 
                if (isset($sslPolicy) && $sslPolicy !== $this->sslPolicy) {
-                       if ($this->config->set('system', 'ssl_policy', $sslPolicy)) {
+                       if ($this->config->set('system', 'ssl_policy', $sslPolicy, false)) {
                                $this->sslPolicy = $sslPolicy;
                        } else {
                                $this->hostname = $currHostname;
-                               $this->config->set('config', 'hostname', $this->hostname);
+                               $this->config->set('config', 'hostname', $this->hostname, false);
+                               $this->config->save();
                                return false;
                        }
                }
 
                if (isset($urlPath) && $urlPath !== $this->urlPath) {
-                       if ($this->config->set('system', 'urlpath', $urlPath)) {
+                       if ($this->config->set('system', 'urlpath', $urlPath, false)) {
                                $this->urlPath = $urlPath;
                        } else {
                                $this->hostname  = $currHostname;
                                $this->sslPolicy = $currSSLPolicy;
-                               $this->config->set('config', 'hostname', $this->hostname);
-                               $this->config->set('system', 'ssl_policy', $this->sslPolicy);
+                               $this->config->set('config', 'hostname', $this->hostname, false);
+                               $this->config->set('system', 'ssl_policy', $this->sslPolicy, false);
+                               $this->config->save();
                                return false;
                        }
                }
 
                $this->determineBaseUrl();
-               if (!$this->config->set('system', 'url', $this->url)) {
+               if (!$this->config->set('system', 'url', $this->url, false)) {
                        $this->hostname  = $currHostname;
                        $this->sslPolicy = $currSSLPolicy;
                        $this->urlPath   = $currURLPath;
                        $this->determineBaseUrl();
 
-                       $this->config->set('config', 'hostname', $this->hostname);
-                       $this->config->set('system', 'ssl_policy', $this->sslPolicy);
-                       $this->config->set('system', 'urlpath', $this->urlPath);
+                       $this->config->set('config', 'hostname', $this->hostname, false);
+                       $this->config->set('system', 'ssl_policy', $this->sslPolicy, false);
+                       $this->config->set('system', 'urlpath', $this->urlPath, false);
+                       $this->config->save();
                        return false;
                }
 
+               $this->config->save();
+
                return true;
        }
 
@@ -295,17 +300,21 @@ class BaseURL
                $this->sslPolicy = $this->config->get('system', 'ssl_policy');
                $this->url       = $this->config->get('system', 'url');
 
+               $savable = false;
+
                if (empty($this->hostname)) {
                        $this->determineHostname();
 
                        if (!empty($this->hostname)) {
-                               $this->config->set('config', 'hostname', $this->hostname);
+                               $this->config->set('config', 'hostname', $this->hostname, false);
+                               $savable = true;
                        }
                }
 
                if (!isset($this->urlPath)) {
                        $this->determineURLPath();
-                       $this->config->set('system', 'urlpath', $this->urlPath);
+                       $this->config->set('system', 'urlpath', $this->urlPath, false);
+                       $savable = true;
                }
 
                if (!isset($this->sslPolicy)) {
@@ -314,16 +323,22 @@ class BaseURL
                        } else {
                                $this->sslPolicy = self::DEFAULT_SSL_SCHEME;
                        }
-                       $this->config->set('system', 'ssl_policy', $this->sslPolicy);
+                       $this->config->set('system', 'ssl_policy', $this->sslPolicy, false);
+                       $savable = true;
                }
 
                if (empty($this->url)) {
                        $this->determineBaseUrl();
 
                        if (!empty($this->url)) {
-                               $this->config->set('system', 'url', $this->url);
+                               $this->config->set('system', 'url', $this->url, false);
+                               $savable = true;
                        }
                }
+
+               if ($savable) {
+                       $this->config->save();
+               }
        }
 
        /**
index 97ce9c27fa45612ce84c45a9678caaa9d6a1cf3a..bd3aef7c290b7ea425727a555ab8d04a709558b1 100644 (file)
@@ -100,16 +100,18 @@ HELP;
 
                $enabled = intval($this->getArgument(0));
 
-               $this->config->set('system', 'maintenance', $enabled);
+               $this->config->set('system', 'maintenance', $enabled, false);
 
                $reason = $this->getArgument(1);
 
                if ($enabled && $this->getArgument(1)) {
-                       $this->config->set('system', 'maintenance_reason', $this->getArgument(1));
+                       $this->config->set('system', 'maintenance_reason', $this->getArgument(1), false);
                } else {
-                       $this->config->set('system', 'maintenance_reason', '');
+                       $this->config->set('system', 'maintenance_reason', '', false);
                }
 
+               $this->config->save();
+
                if ($enabled) {
                        $mode_str = "maintenance mode";
                } else {
index 3d13e10a0b162cbbba2bbbb36df356dd4aac4e84..8a76c92070777e62c7c1c090008bd9a2a8d4e395 100644 (file)
@@ -101,8 +101,8 @@ HELP;
                $old_host = str_replace('http://', '@', Strings::normaliseLink($old_url));
 
                $this->out('Entering maintenance mode');
-               $this->config->set('system', 'maintenance', true);
-               $this->config->set('system', 'maintenance_reason', 'Relocating node to ' . $new_url);
+               $this->config->set('system', 'maintenance', true, false);
+               $this->config->set('system', 'maintenance_reason', 'Relocating node to ' . $new_url, false);
 
                try {
                        if (!$this->database->transaction()) {
@@ -189,8 +189,9 @@ HELP;
                        return 1;
                } finally {
                        $this->out('Leaving maintenance mode');
-                       $this->config->set('system', 'maintenance', false);
-                       $this->config->set('system', 'maintenance_reason', '');
+                       $this->config->set('system', 'maintenance', false, false);
+                       $this->config->set('system', 'maintenance_reason', '', false);
+                       $this->config->save();
                }
 
                // send relocate
index ecfb2a7aa5c99ff47bb5bba328c20d30a68b506a..27238822aefa9af833d945b3a1e7c336bb9e42f9 100644 (file)
@@ -71,12 +71,18 @@ interface IManageConfigValues
         * @param string $cat The category of the configuration value
         * @param string $key    The configuration key to set
         * @param mixed  $value  The value to store
+        * @param bool   $autosave If true, implicit save the value
         *
         * @return bool Operation success
         *
         * @throws ConfigPersistenceException In case the persistence layer throws errors
         */
-       public function set(string $cat, string $key, $value): bool;
+       public function set(string $cat, string $key, $value, bool $autosave = true): bool;
+
+       /**
+        * Save back the overridden values of the config cache
+        */
+       public function save();
 
        /**
         * Deletes the given key from the system configuration.
@@ -85,13 +91,14 @@ interface IManageConfigValues
         *
         * @param string $cat The category of the configuration value
         * @param string $key    The configuration key to delete
+        * @param bool   $autosave If true, implicit save the value
         *
         * @return bool
         *
         * @throws ConfigPersistenceException In case the persistence layer throws errors
         *
         */
-       public function delete(string $cat, string $key): bool;
+       public function delete(string $cat, string $key, bool $autosave = true): bool;
 
        /**
         * Returns the Config Cache
index 94293dd17303f3dbd8ee8f8f09dc106826e42a84..fac931fac5d69741f2db3b6f48c67e674de5357f 100644 (file)
 
 namespace Friendica\Core\Config\Factory;
 
-use Friendica\Core\Config\Capability;
-use Friendica\Core\Config\Repository;
-use Friendica\Core\Config\Type;
 use Friendica\Core\Config\Util;
 use Friendica\Core\Config\ValueObject\Cache;
 
+/**
+ * The config factory for creating either the cache or the whole model
+ */
 class Config
 {
        /**
@@ -54,9 +54,9 @@ class Config
         * @param string $basePath The basepath of FRIENDICA
         * @param array  $server   The $_SERVER array
         *
-        * @return Util\ConfigFileLoader
+        * @return Util\ConfigFileManager
         */
-       public function createConfigFileLoader(string $basePath, array $server = []): Util\ConfigFileLoader
+       public function createConfigFileLoader(string $basePath, array $server = []): Util\ConfigFileManager
        {
                if (!empty($server[self::CONFIG_DIR_ENV]) && is_dir($server[self::CONFIG_DIR_ENV])) {
                        $configDir = $server[self::CONFIG_DIR_ENV];
@@ -65,19 +65,19 @@ class Config
                }
                $staticDir = $basePath . DIRECTORY_SEPARATOR . self::STATIC_DIR;
 
-               return new Util\ConfigFileLoader($basePath, $configDir, $staticDir);
+               return new Util\ConfigFileManager($basePath, $configDir, $staticDir, new Util\ConfigFileTransformer());
        }
 
        /**
-        * @param Util\ConfigFileLoader $loader The Config Cache loader (INI/config/.htconfig)
-        * @param array                 $server
+        * @param Util\ConfigFileManager $configFileManager The Config Cache manager (INI/config/.htconfig)
+        * @param array                  $server
         *
         * @return Cache
         */
-       public function createCache(Util\ConfigFileLoader $loader, array $server = []): Cache
+       public function createCache(Util\ConfigFileManager $configFileManager, array $server = []): Cache
        {
                $configCache = new Cache();
-               $loader->setupCache($configCache, $server);
+               $configFileManager->setupCache($configCache, $server);
 
                return $configCache;
        }
@@ -88,12 +88,12 @@ class Config
         *
         * @return Capability\IManageConfigValues
         */
-       public function create(Cache $configCache, Repository\Config $configRepo)
+       public function create(Util\ConfigFileManager $loader, Cache $configCache, Repository\Config $configRepo)
        {
                if ($configCache->get('system', 'config_adapter') === 'preload') {
-                       $configuration = new Type\PreloadConfig($configCache, $configRepo);
+                       $configuration = new Type\PreloadConfig($loader, $configCache, $configRepo);
                } else {
-                       $configuration = new Type\JitConfig($configCache, $configRepo);
+                       $configuration = new Type\JitConfig($loader, $configCache, $configRepo);
                }
 
                return $configuration;
index 3bec99f84371ff92b7a8eb33614c95b6842148c9..eabff9e68f1a8e484b97b1c2d7a5f3e294bb1626 100644 (file)
@@ -51,7 +51,7 @@ class Config
         */
        public function isConnected(): bool
        {
-               return $this->db->isConnected() && !$this->mode->isInstall();
+               return true;
        }
 
        /**
@@ -65,31 +65,7 @@ class Config
         */
        public function load(?string $cat = null): array
        {
-               $return = [];
-
-               try {
-                       if (empty($cat)) {
-                               $configs = $this->db->select(static::$table_name, ['cat', 'v', 'k']);
-                       } else {
-                               $configs = $this->db->select(static::$table_name, ['cat', 'v', 'k'], ['cat' => $cat]);
-                       }
-
-                       while ($config = $this->db->fetch($configs)) {
-                               $key   = $config['k'];
-                               $value = ValueConversion::toConfigValue($config['v']);
-
-                               // just save it in case it is set
-                               if (isset($value)) {
-                                       $return[$config['cat']][$key] = $value;
-                               }
-                       }
-               } catch (\Exception $exception) {
-                       throw new ConfigPersistenceException(sprintf('Cannot load config category %s', $cat), $exception);
-               } finally {
-                       $this->db->close($configs);
-               }
-
-               return $return;
+               return [];
        }
 
        /**
@@ -107,24 +83,6 @@ class Config
         */
        public function get(string $cat, string $key)
        {
-               if (!$this->isConnected()) {
-                       return null;
-               }
-
-               try {
-                       $config = $this->db->selectFirst(static::$table_name, ['v'], ['cat' => $cat, 'k' => $key]);
-                       if ($this->db->isResult($config)) {
-                               $value = ValueConversion::toConfigValue($config['v']);
-
-                               // just return it in case it is set
-                               if (isset($value)) {
-                                       return $value;
-                               }
-                       }
-               } catch (\Exception $exception) {
-                       throw new ConfigPersistenceException(sprintf('Cannot get config with category %s and key %s', $cat, $key), $exception);
-               }
-
                return null;
        }
 
@@ -143,27 +101,7 @@ class Config
         */
        public function set(string $cat, string $key, $value): bool
        {
-               if (!$this->isConnected()) {
-                       return false;
-               }
-
-               // 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.
-               $compare_value = (!is_array($value) ? (string)$value : $value);
-               $stored_value  = $this->get($cat, $key);
-
-               if (isset($stored_value) && ($stored_value === $compare_value)) {
-                       return true;
-               }
-
-               $dbValue = ValueConversion::toDbValue($value);
-
-               try {
-                       return $this->db->update(static::$table_name, ['v' => $dbValue], ['cat' => $cat, 'k' => $key], true);
-               } catch (\Exception $exception) {
-                       throw new ConfigPersistenceException(sprintf('Cannot set config with category %s and key %s', $cat, $key), $exception);
-               }
+               return true;
        }
 
        /**
@@ -178,14 +116,6 @@ class Config
         */
        public function delete(string $cat, string $key): bool
        {
-               if (!$this->isConnected()) {
-                       return false;
-               }
-
-               try {
-                       return $this->db->delete(static::$table_name, ['cat' => $cat, 'k' => $key]);
-               } catch (\Exception $exception) {
-                       throw new ConfigPersistenceException(sprintf('Cannot delete config with category %s and key %s', $cat, $key), $exception);
-               }
+               return true;
        }
 }
index 3ab4f2c5e7b37a225f8e3c88fa6d162b75598745..fa98dd709701fe281168b43bf0ee6f037d1b1914 100644 (file)
 namespace Friendica\Core\Config\Type;
 
 use Friendica\Core\Config\Repository\Config;
+use Friendica\Core\Config\Util\ConfigFileManager;
 use Friendica\Core\Config\ValueObject\Cache;
 use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\DI;
 
 /**
  * This class is responsible for all system-wide configuration values in Friendica
@@ -43,14 +45,19 @@ abstract class AbstractConfig implements IManageConfigValues
         */
        protected $configRepo;
 
+       /** @var ConfigFileManager */
+       protected $configFileManager;
+
        /**
+        * @param ConfigFileManager $configFileManager The configuration file manager to save back configs
         * @param Cache  $configCache The configuration cache (based on the config-files)
         * @param Config $configRepo  The configuration repository
         */
-       public function __construct(Cache $configCache, Config $configRepo)
+       public function __construct(ConfigFileManager $configFileManager, Cache $configCache, Config $configRepo)
        {
-               $this->configCache = $configCache;
-               $this->configRepo  = $configRepo;
+               $this->configFileManager = $configFileManager;
+               $this->configCache       = $configCache;
+               $this->configRepo        = $configRepo;
        }
 
        /**
@@ -60,4 +67,9 @@ abstract class AbstractConfig implements IManageConfigValues
        {
                return $this->configCache;
        }
+
+       public function save()
+       {
+               $this->configFileManager->saveData($this->configCache);
+       }
 }
index 68b437b243f4d53dfb7a9798f79211e028f39f97..1ae9abd2ee90f8698b4e5e8623ccfacc5f1a5ff5 100644 (file)
@@ -21,6 +21,7 @@
 
 namespace Friendica\Core\Config\Type;
 
+use Friendica\Core\Config\Util\ConfigFileManager;
 use Friendica\Core\Config\ValueObject\Cache;
 use Friendica\Core\Config\Repository\Config;
 
@@ -39,12 +40,13 @@ class JitConfig extends AbstractConfig
        private $db_loaded;
 
        /**
-        * @param Cache  $configCache The configuration cache (based on the config-files)
-        * @param Config $configRepo  The configuration model
+        * @param ConfigFileManager $configFileManager The configuration file manager to save back configs
+        * @param Cache             $configCache       The configuration cache (based on the config-files)
+        * @param Config            $configRepo        The configuration model
         */
-       public function __construct(Cache $configCache, Config $configRepo)
+       public function __construct(ConfigFileManager $configFileManager, Cache $configCache, Config $configRepo)
        {
-               parent::__construct($configCache, $configRepo);
+               parent::__construct($configFileManager, $configCache, $configRepo);
                $this->db_loaded = [];
 
                $this->load();
@@ -69,7 +71,7 @@ class JitConfig extends AbstractConfig
                }
 
                // load the whole category out of the DB into the cache
-               $this->configCache->load($config, Cache::SOURCE_DB);
+               $this->configCache->load($config, Cache::SOURCE_DATA);
        }
 
        /**
@@ -84,7 +86,7 @@ class JitConfig extends AbstractConfig
                        $dbValue = $this->configRepo->get($cat, $key);
 
                        if (isset($dbValue)) {
-                               $this->configCache->set($cat, $key, $dbValue, Cache::SOURCE_DB);
+                               $this->configCache->set($cat, $key, $dbValue, Cache::SOURCE_DATA);
                                unset($dbValue);
                        }
 
@@ -100,10 +102,10 @@ class JitConfig extends AbstractConfig
        /**
         * {@inheritDoc}
         */
-       public function set(string $cat, string $key, $value): bool
+       public function set(string $cat, string $key, $value, bool $autosave = true): bool
        {
                // set the cache first
-               $cached = $this->configCache->set($cat, $key, $value, Cache::SOURCE_DB);
+               $cached = $this->configCache->set($cat, $key, $value, Cache::SOURCE_DATA);
 
                // If there is no connected adapter, we're finished
                if (!$this->configRepo->isConnected()) {
@@ -114,13 +116,17 @@ class JitConfig extends AbstractConfig
 
                $this->db_loaded[$cat][$key] = $stored;
 
+               if ($autosave) {
+                       $this->save();
+               }
+
                return $cached && $stored;
        }
 
        /**
         * {@inheritDoc}
         */
-       public function delete(string $cat, string $key): bool
+       public function delete(string $cat, string $key, bool $autosave = true): bool
        {
                $cacheRemoved = $this->configCache->delete($cat, $key);
 
@@ -134,6 +140,10 @@ class JitConfig extends AbstractConfig
 
                $storeRemoved = $this->configRepo->delete($cat, $key);
 
+               if ($autosave) {
+                       $this->save();
+               }
+
                return $cacheRemoved || $storeRemoved;
        }
 }
index 57a0d439dfb9aebc00c35ec59ea0332f1db8681f..6eed20af893d47c389bcb485c7ec18727639c0ff 100644 (file)
@@ -21,6 +21,7 @@
 
 namespace Friendica\Core\Config\Type;
 
+use Friendica\Core\Config\Util\ConfigFileManager;
 use Friendica\Core\Config\ValueObject\Cache;
 use Friendica\Core\Config\Repository\Config;
 
@@ -36,12 +37,13 @@ class PreloadConfig extends AbstractConfig
        private $config_loaded;
 
        /**
-        * @param Cache  $configCache The configuration cache (based on the config-files)
-        * @param Config $configRepo  The configuration model
+        * @param ConfigFileManager $configFileManager The configuration file manager to save back configs
+        * @param Cache             $configCache       The configuration cache (based on the config-files)
+        * @param Config            $configRepo        The configuration model
         */
-       public function __construct(Cache $configCache, Config $configRepo)
+       public function __construct(ConfigFileManager $configFileManager, Cache $configCache, Config $configRepo)
        {
-               parent::__construct($configCache, $configRepo);
+               parent::__construct($configFileManager, $configCache, $configRepo);
                $this->config_loaded = false;
 
                $this->load();
@@ -68,7 +70,7 @@ class PreloadConfig extends AbstractConfig
                $this->config_loaded = true;
 
                // load the whole category out of the DB into the cache
-               $this->configCache->load($config, Cache::SOURCE_DB);
+               $this->configCache->load($config, Cache::SOURCE_DATA);
        }
 
        /**
@@ -80,7 +82,7 @@ class PreloadConfig extends AbstractConfig
                        if ($this->configRepo->isConnected()) {
                                $config = $this->configRepo->get($cat, $key);
                                if (isset($config)) {
-                                       $this->configCache->set($cat, $key, $config, Cache::SOURCE_DB);
+                                       $this->configCache->set($cat, $key, $config, Cache::SOURCE_DATA);
                                }
                        }
                }
@@ -94,14 +96,14 @@ class PreloadConfig extends AbstractConfig
        /**
         * {@inheritDoc}
         */
-       public function set(string $cat, string $key, $value): bool
+       public function set(string $cat, string $key, $value, bool $autosave = true): bool
        {
                if (!$this->config_loaded) {
                        $this->load();
                }
 
                // set the cache first
-               $cached = $this->configCache->set($cat, $key, $value, Cache::SOURCE_DB);
+               $cached = $this->configCache->set($cat, $key, $value, Cache::SOURCE_DATA);
 
                // If there is no connected adapter, we're finished
                if (!$this->configRepo->isConnected()) {
@@ -110,13 +112,17 @@ class PreloadConfig extends AbstractConfig
 
                $stored = $this->configRepo->set($cat, $key, $value);
 
+               if ($autosave) {
+                       $this->save();
+               }
+
                return $cached && $stored;
        }
 
        /**
         * {@inheritDoc}
         */
-       public function delete(string $cat, string $key): bool
+       public function delete(string $cat, string $key, bool $autosave = true): bool
        {
                if ($this->config_loaded) {
                        $this->load();
@@ -130,6 +136,10 @@ class PreloadConfig extends AbstractConfig
 
                $storeRemoved = $this->configRepo->delete($cat, $key);
 
+               if ($autosave) {
+                       $this->save();
+               }
+
                return $cacheRemoved || $storeRemoved;
        }
 }
diff --git a/src/Core/Config/Util/ConfigFileLoader.php b/src/Core/Config/Util/ConfigFileLoader.php
deleted file mode 100644 (file)
index acf6efa..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Config\Util;
-
-use Friendica\Core\Addon;
-use Friendica\Core\Config\Exception\ConfigFileException;
-use Friendica\Core\Config\ValueObject\Cache;
-
-/**
- * The ConfigFileLoader loads config-files and stores them in a ConfigCache ( @see Cache )
- *
- * It is capable of loading the following config files:
- * - *.config.php   (current)
- * - *.ini.php      (deprecated)
- * - *.htconfig.php (deprecated)
- */
-class ConfigFileLoader
-{
-       /**
-        * The default name of the user defined ini file
-        *
-        * @var string
-        */
-       const CONFIG_INI = 'local';
-
-       /**
-        * The default name of the user defined legacy config file
-        *
-        * @var string
-        */
-       const CONFIG_HTCONFIG = 'htconfig';
-
-       /**
-        * The sample string inside the configs, which shouldn't get loaded
-        *
-        * @var string
-        */
-       const SAMPLE_END = '-sample';
-
-       /**
-        * @var string
-        */
-       private $baseDir;
-       /**
-        * @var string
-        */
-       private $configDir;
-       /**
-        * @var string
-        */
-       private $staticDir;
-
-       /**
-        * @param string $baseDir   The base
-        * @param string $configDir
-        * @param string $staticDir
-        */
-       public function __construct(string $baseDir, string $configDir, string $staticDir)
-       {
-               $this->baseDir   = $baseDir;
-               $this->configDir = $configDir;
-               $this->staticDir = $staticDir;
-       }
-
-       /**
-        * Load the configuration files into an configuration cache
-        *
-        * First loads the default value for all the configuration keys, then the legacy configuration files, then the
-        * expected local.config.php
-        *
-        * @param Cache $config The config cache to load to
-        * @param array $server The $_SERVER array
-        * @param bool  $raw    Setup the raw config format
-        *
-        * @throws ConfigFileException
-        */
-       public function setupCache(Cache $config, array $server = [], bool $raw = false)
-       {
-               // Load static config files first, the order is important
-               $config->load($this->loadStaticConfig('defaults'), Cache::SOURCE_STATIC);
-               $config->load($this->loadStaticConfig('settings'), Cache::SOURCE_STATIC);
-
-               // try to load the legacy config first
-               $config->load($this->loadLegacyConfig('htpreconfig'), Cache::SOURCE_FILE);
-               $config->load($this->loadLegacyConfig('htconfig'), Cache::SOURCE_FILE);
-
-               // Now load every other config you find inside the 'config/' directory
-               $this->loadCoreConfig($config);
-
-               $config->load($this->loadEnvConfig($server), Cache::SOURCE_ENV);
-
-               // In case of install mode, add the found basepath (because there isn't a basepath set yet
-               if (!$raw && empty($config->get('system', 'basepath'))) {
-                       // Setting at least the basepath we know
-                       $config->set('system', 'basepath', $this->baseDir, Cache::SOURCE_FILE);
-               }
-       }
-
-       /**
-        * Tries to load the static core-configuration and returns the config array.
-        *
-        * @param string $name The name of the configuration
-        *
-        * @return array The config array (empty if no config found)
-        *
-        * @throws ConfigFileException if the configuration file isn't readable
-        */
-       private function loadStaticConfig(string $name): array
-       {
-               $configName = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.config.php';
-               $iniName    = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.ini.php';
-
-               if (file_exists($configName)) {
-                       return $this->loadConfigFile($configName);
-               } elseif (file_exists($iniName)) {
-                       return $this->loadINIConfigFile($iniName);
-               } else {
-                       return [];
-               }
-       }
-
-       /**
-        * Tries to load the specified core-configuration into the config cache.
-        *
-        * @param Cache $config The Config cache
-        *
-        * @throws ConfigFileException if the configuration file isn't readable
-        */
-       private function loadCoreConfig(Cache $config)
-       {
-               // try to load legacy ini-files first
-               foreach ($this->getConfigFiles(true) as $configFile) {
-                       $config->load($this->loadINIConfigFile($configFile), Cache::SOURCE_FILE);
-               }
-
-               // try to load supported config at last to overwrite it
-               foreach ($this->getConfigFiles() as $configFile) {
-                       $config->load($this->loadConfigFile($configFile), Cache::SOURCE_FILE);
-               }
-       }
-
-       /**
-        * Tries to load the specified addon-configuration and returns the config array.
-        *
-        * @param string $name The name of the configuration
-        *
-        * @return array The config array (empty if no config found)
-        *
-        * @throws ConfigFileException if the configuration file isn't readable
-        */
-       public function loadAddonConfig(string $name): array
-       {
-               $filepath = $this->baseDir . DIRECTORY_SEPARATOR .   // /var/www/html/
-                                       Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/
-                                       $name . DIRECTORY_SEPARATOR .            // openstreetmap/
-                                       'config'. DIRECTORY_SEPARATOR .                  // config/
-                                       $name . ".config.php";                   // openstreetmap.config.php
-
-               if (file_exists($filepath)) {
-                       return $this->loadConfigFile($filepath);
-               } else {
-                       return [];
-               }
-       }
-
-       /**
-        * Tries to load environment specific variables, based on the `env.config.php` mapping table
-        *
-        * @param array $server The $_SERVER variable
-        *
-        * @return array The config array (empty if no config was found)
-        *
-        * @throws ConfigFileException if the configuration file isn't readable
-        */
-       public function loadEnvConfig(array $server): array
-       {
-               $filepath = $this->staticDir . DIRECTORY_SEPARATOR .   // /var/www/html/static/
-                                       "env.config.php";                          // env.config.php
-
-               if (!file_exists($filepath)) {
-                       return [];
-               }
-
-               $envConfig = $this->loadConfigFile($filepath);
-
-               $return = [];
-
-               foreach ($envConfig as $envKey => $configStructure) {
-                       if (isset($server[$envKey])) {
-                               $return[$configStructure[0]][$configStructure[1]] = $server[$envKey];
-                       }
-               }
-
-               return $return;
-       }
-
-       /**
-        * Get the config files of the config-directory
-        *
-        * @param bool $ini True, if scan for ini-files instead of config files
-        *
-        * @return array
-        */
-       private function getConfigFiles(bool $ini = false): array
-       {
-               $files = scandir($this->configDir);
-               $found = [];
-
-               $filePattern = ($ini ? '*.ini.php' : '*.config.php');
-
-               // Don't load sample files
-               $sampleEnd = self::SAMPLE_END . ($ini ? '.ini.php' : '.config.php');
-
-               foreach ($files as $filename) {
-                       if (fnmatch($filePattern, $filename) && substr_compare($filename, $sampleEnd, -strlen($sampleEnd))) {
-                               $found[] = $this->configDir . '/' . $filename;
-                       }
-               }
-
-               return $found;
-       }
-
-       /**
-        * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
-        *
-        * @param string $name The name of the config file (default is empty, which means .htconfig.php)
-        *
-        * @return array The configuration array (empty if no config found)
-        *
-        * @deprecated since version 2018.09
-        */
-       private function loadLegacyConfig(string $name = ''): array
-       {
-               $name     = !empty($name) ? $name : self::CONFIG_HTCONFIG;
-               $fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php';
-
-               $config = [];
-               if (file_exists($fullName)) {
-                       $a         = new \stdClass();
-                       $a->config = [];
-                       include $fullName;
-
-                       $htConfigCategories = array_keys($a->config);
-
-                       // map the legacy configuration structure to the current structure
-                       foreach ($htConfigCategories as $htConfigCategory) {
-                               if (is_array($a->config[$htConfigCategory])) {
-                                       $keys = array_keys($a->config[$htConfigCategory]);
-
-                                       foreach ($keys as $key) {
-                                               $config[$htConfigCategory][$key] = $a->config[$htConfigCategory][$key];
-                                       }
-                               } else {
-                                       $config['config'][$htConfigCategory] = $a->config[$htConfigCategory];
-                               }
-                       }
-
-                       unset($a);
-
-                       if (isset($db_host)) {
-                               $config['database']['hostname'] = $db_host;
-                               unset($db_host);
-                       }
-                       if (isset($db_user)) {
-                               $config['database']['username'] = $db_user;
-                               unset($db_user);
-                       }
-                       if (isset($db_pass)) {
-                               $config['database']['password'] = $db_pass;
-                               unset($db_pass);
-                       }
-                       if (isset($db_data)) {
-                               $config['database']['database'] = $db_data;
-                               unset($db_data);
-                       }
-                       if (isset($config['system']['db_charset'])) {
-                               $config['database']['charset'] = $config['system']['db_charset'];
-                       }
-                       if (isset($pidfile)) {
-                               $config['system']['pidfile'] = $pidfile;
-                               unset($pidfile);
-                       }
-                       if (isset($default_timezone)) {
-                               $config['system']['default_timezone'] = $default_timezone;
-                               unset($default_timezone);
-                       }
-                       if (isset($lang)) {
-                               $config['system']['language'] = $lang;
-                               unset($lang);
-                       }
-               }
-
-               return $config;
-       }
-
-       /**
-        * Tries to load the specified legacy configuration file and returns the config array.
-        *
-        * @param string $filepath
-        *
-        * @return array The configuration array
-        * @throws ConfigFileException
-        * @deprecated since version 2018.12
-        */
-       private function loadINIConfigFile(string $filepath): array
-       {
-               $contents = include($filepath);
-
-               $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
-
-               if ($config === false) {
-                       throw new ConfigFileException('Error parsing INI config file ' . $filepath);
-               }
-
-               return $config;
-       }
-
-       /**
-        * Tries to load the specified configuration file and returns the config array.
-        *
-        * The config format is PHP array and the template for configuration files is the following:
-        *
-        * <?php return [
-        *      'section' => [
-        *          'key' => 'value',
-        *      ],
-        * ];
-        *
-        * @param string $filepath The filepath of the
-        *
-        * @return array The config array0
-        *
-        * @throws ConfigFileException if the config cannot get loaded.
-        */
-       private function loadConfigFile(string $filepath): array
-       {
-               $config = include($filepath);
-
-               if (!is_array($config)) {
-                       throw new ConfigFileException('Error loading config file ' . $filepath);
-               }
-
-               return $config;
-       }
-}
diff --git a/src/Core/Config/Util/ConfigFileManager.php b/src/Core/Config/Util/ConfigFileManager.php
new file mode 100644 (file)
index 0000000..82de4a9
--- /dev/null
@@ -0,0 +1,415 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Config\Util;
+
+use Friendica\Core\Addon;
+use Friendica\Core\Config\Exception\ConfigFileException;
+use Friendica\Core\Config\ValueObject\Cache;
+
+/**
+ * The ConfigFileLoader loads and saves config-files and stores them in a ConfigCache ( @see Cache )
+ *
+ * It is capable of loading the following config files:
+ * - *.config.php   (current)
+ * - *.ini.php      (deprecated)
+ * - *.htconfig.php (deprecated)
+ */
+class ConfigFileManager
+{
+       /**
+        * The default name of the user defined legacy config file
+        *
+        * @var string
+        */
+       const CONFIG_HTCONFIG = 'htconfig';
+
+       /**
+        * The config file, where overrides per admin page/console are saved at
+        *
+        * @var string
+        */
+       const CONFIG_DATA_FILE = 'node.config.php';
+
+       /**
+        * The sample string inside the configs, which shouldn't get loaded
+        *
+        * @var string
+        */
+       const SAMPLE_END = '-sample';
+
+       /**
+        * @var string
+        */
+       private $baseDir;
+       /**
+        * @var string
+        */
+       private $configDir;
+       /**
+        * @var string
+        */
+       private $staticDir;
+
+       /**
+        * @param string $baseDir   The base
+        * @param string $configDir
+        * @param string $staticDir
+        */
+       public function __construct(string $baseDir, string $configDir, string $staticDir)
+       {
+               $this->baseDir   = $baseDir;
+               $this->configDir = $configDir;
+               $this->staticDir = $staticDir;
+       }
+
+       /**
+        * Load the configuration files into an configuration cache
+        *
+        * First loads the default value for all the configuration keys, then the legacy configuration files, then the
+        * expected local.config.php
+        *
+        * @param Cache $config The config cache to load to
+        * @param array $server The $_SERVER array
+        * @param bool  $raw    Set up the raw config format
+        *
+        * @throws ConfigFileException
+        */
+       public function setupCache(Cache $config, array $server = [], bool $raw = false)
+       {
+               // Load static config files first, the order is important
+               $config->load($this->loadStaticConfig('defaults'), Cache::SOURCE_STATIC);
+               $config->load($this->loadStaticConfig('settings'), Cache::SOURCE_STATIC);
+
+               // try to load the legacy config first
+               $config->load($this->loadLegacyConfig('htpreconfig'), Cache::SOURCE_FILE);
+               $config->load($this->loadLegacyConfig('htconfig'), Cache::SOURCE_FILE);
+
+               // Now load every other config you find inside the 'config/' directory
+               $this->loadCoreConfig($config);
+
+               // Now load the node.config.php file with the node specific config values (based on admin gui/console actions)
+               $this->loadDataConfig($config);
+
+               $config->load($this->loadEnvConfig($server), Cache::SOURCE_ENV);
+
+               // In case of install mode, add the found basepath (because there isn't a basepath set yet
+               if (!$raw && empty($config->get('system', 'basepath'))) {
+                       // Setting at least the basepath we know
+                       $config->set('system', 'basepath', $this->baseDir, Cache::SOURCE_FILE);
+               }
+       }
+
+       /**
+        * Tries to load the static core-configuration and returns the config array.
+        *
+        * @param string $name The name of the configuration
+        *
+        * @return array The config array (empty if no config found)
+        *
+        * @throws ConfigFileException if the configuration file isn't readable
+        */
+       private function loadStaticConfig(string $name): array
+       {
+               $configName = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.config.php';
+               $iniName    = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.ini.php';
+
+               if (file_exists($configName)) {
+                       return $this->loadConfigFile($configName);
+               } elseif (file_exists($iniName)) {
+                       return $this->loadINIConfigFile($iniName);
+               } else {
+                       return [];
+               }
+       }
+
+       /**
+        * Tries to load the specified core-configuration into the config cache.
+        *
+        * @param Cache $config The Config cache
+        *
+        * @throws ConfigFileException if the configuration file isn't readable
+        */
+       private function loadCoreConfig(Cache $config)
+       {
+               // try to load legacy ini-files first
+               foreach ($this->getConfigFiles(true) as $configFile) {
+                       $config->load($this->loadINIConfigFile($configFile), Cache::SOURCE_FILE);
+               }
+
+               // try to load supported config at last to overwrite it
+               foreach ($this->getConfigFiles() as $configFile) {
+                       $config->load($this->loadConfigFile($configFile), Cache::SOURCE_FILE);
+               }
+       }
+
+       /**
+        * Tries to load the data config file with the overridden data
+        *
+        * @param Cache $config The Config cache
+        *
+        * @throws ConfigFileException In case the config file isn't loadable
+        */
+       private function loadDataConfig(Cache $config)
+       {
+               $filename = $this->configDir . '/' . self::CONFIG_DATA_FILE;
+
+               if (file_exists($filename)) {
+                       $dataArray = include $filename;
+
+                       if (!is_array($dataArray)) {
+                               throw new ConfigFileException(sprintf('Error loading config file %s', $filename));
+                       }
+
+                       $config->load($dataArray, Cache::SOURCE_DATA);
+               }
+       }
+
+       /**
+        * Saves overridden config entries back into the data.config.phpR
+        *
+        * @param Cache $config The config cache
+        *
+        * @throws ConfigFileException In case the config file isn't writeable or the data is invalid
+        */
+       public function saveData(Cache $config)
+       {
+               $data = $config->getDataBySource(Cache::SOURCE_DATA);
+
+               $encodedData = ConfigFileTransformer::encode($data);
+
+               if (!$encodedData) {
+                       throw new ConfigFileException('config source cannot get encoded');
+               }
+
+               if (!file_put_contents($this->configDir . '/' . self::CONFIG_DATA_FILE, $encodedData)) {
+                       throw new ConfigFileException(sprintf('Cannot save data to file %s/%s', $this->configDir, self::CONFIG_DATA_FILE));
+               }
+       }
+
+       /**
+        * Tries to load the specified addon-configuration and returns the config array.
+        *
+        * @param string $name The name of the configuration
+        *
+        * @return array The config array (empty if no config found)
+        *
+        * @throws ConfigFileException if the configuration file isn't readable
+        */
+       public function loadAddonConfig(string $name): array
+       {
+               $filepath = $this->baseDir . DIRECTORY_SEPARATOR .   // /var/www/html/
+                                       Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/
+                                       $name . DIRECTORY_SEPARATOR .            // openstreetmap/
+                                       'config'. DIRECTORY_SEPARATOR .                  // config/
+                                       $name . ".config.php";                   // openstreetmap.config.php
+
+               if (file_exists($filepath)) {
+                       return $this->loadConfigFile($filepath);
+               } else {
+                       return [];
+               }
+       }
+
+       /**
+        * Tries to load environment specific variables, based on the `env.config.php` mapping table
+        *
+        * @param array $server The $_SERVER variable
+        *
+        * @return array The config array (empty if no config was found)
+        *
+        * @throws ConfigFileException if the configuration file isn't readable
+        */
+       public function loadEnvConfig(array $server): array
+       {
+               $filepath = $this->staticDir . DIRECTORY_SEPARATOR .   // /var/www/html/static/
+                                       "env.config.php";                          // env.config.php
+
+               if (!file_exists($filepath)) {
+                       return [];
+               }
+
+               $envConfig = $this->loadConfigFile($filepath);
+
+               $return = [];
+
+               foreach ($envConfig as $envKey => $configStructure) {
+                       if (isset($server[$envKey])) {
+                               $return[$configStructure[0]][$configStructure[1]] = $server[$envKey];
+                       }
+               }
+
+               return $return;
+       }
+
+       /**
+        * Get the config files of the config-directory
+        *
+        * @param bool $ini True, if scan for ini-files instead of config files
+        *
+        * @return array
+        */
+       private function getConfigFiles(bool $ini = false): array
+       {
+               $files = scandir($this->configDir);
+               $found = [];
+
+               $filePattern = ($ini ? '*.ini.php' : '*.config.php');
+
+               // Don't load sample files
+               $sampleEnd = self::SAMPLE_END . ($ini ? '.ini.php' : '.config.php');
+
+               foreach ($files as $filename) {
+                       if (fnmatch($filePattern, $filename) && substr_compare($filename, $sampleEnd, -strlen($sampleEnd))) {
+                               $found[] = $this->configDir . '/' . $filename;
+                       }
+               }
+
+               return $found;
+       }
+
+       /**
+        * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
+        *
+        * @param string $name The name of the config file (default is empty, which means .htconfig.php)
+        *
+        * @return array The configuration array (empty if no config found)
+        *
+        * @deprecated since version 2018.09
+        */
+       private function loadLegacyConfig(string $name = ''): array
+       {
+               $name     = !empty($name) ? $name : self::CONFIG_HTCONFIG;
+               $fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php';
+
+               $config = [];
+               if (file_exists($fullName)) {
+                       $a         = new \stdClass();
+                       $a->config = [];
+                       include $fullName;
+
+                       $htConfigCategories = array_keys($a->config);
+
+                       // map the legacy configuration structure to the current structure
+                       foreach ($htConfigCategories as $htConfigCategory) {
+                               if (is_array($a->config[$htConfigCategory])) {
+                                       $keys = array_keys($a->config[$htConfigCategory]);
+
+                                       foreach ($keys as $key) {
+                                               $config[$htConfigCategory][$key] = $a->config[$htConfigCategory][$key];
+                                       }
+                               } else {
+                                       $config['config'][$htConfigCategory] = $a->config[$htConfigCategory];
+                               }
+                       }
+
+                       unset($a);
+
+                       if (isset($db_host)) {
+                               $config['database']['hostname'] = $db_host;
+                               unset($db_host);
+                       }
+                       if (isset($db_user)) {
+                               $config['database']['username'] = $db_user;
+                               unset($db_user);
+                       }
+                       if (isset($db_pass)) {
+                               $config['database']['password'] = $db_pass;
+                               unset($db_pass);
+                       }
+                       if (isset($db_data)) {
+                               $config['database']['database'] = $db_data;
+                               unset($db_data);
+                       }
+                       if (isset($config['system']['db_charset'])) {
+                               $config['database']['charset'] = $config['system']['db_charset'];
+                       }
+                       if (isset($pidfile)) {
+                               $config['system']['pidfile'] = $pidfile;
+                               unset($pidfile);
+                       }
+                       if (isset($default_timezone)) {
+                               $config['system']['default_timezone'] = $default_timezone;
+                               unset($default_timezone);
+                       }
+                       if (isset($lang)) {
+                               $config['system']['language'] = $lang;
+                               unset($lang);
+                       }
+               }
+
+               return $config;
+       }
+
+       /**
+        * Tries to load the specified legacy configuration file and returns the config array.
+        *
+        * @param string $filepath
+        *
+        * @return array The configuration array
+        * @throws ConfigFileException
+        * @deprecated since version 2018.12
+        */
+       private function loadINIConfigFile(string $filepath): array
+       {
+               $contents = include($filepath);
+
+               $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
+
+               if ($config === false) {
+                       throw new ConfigFileException('Error parsing INI config file ' . $filepath);
+               }
+
+               return $config;
+       }
+
+       /**
+        * Tries to load the specified configuration file and returns the config array.
+        *
+        * The config format is PHP array and the template for configuration files is the following:
+        *
+        * <?php return [
+        *      'section' => [
+        *          'key' => 'value',
+        *      ],
+        * ];
+        *
+        * @param string $filepath The filepath of the
+        *
+        * @return array The config array0
+        *
+        * @throws ConfigFileException if the config cannot get loaded.
+        */
+       private function loadConfigFile(string $filepath): array
+       {
+               if (file_exists($filepath)) {
+                       $config = include($filepath);
+
+                       if (!is_array($config)) {
+                               throw new ConfigFileException('Error loading config file ' . $filepath);
+                       }
+
+                       return $config;
+               } else {
+                       return [];
+               }
+       }
+}
index 00f8ad045d0d6a35541982238ad76fcd6ef09b06..c427996c35bcf7c94618c8ddfcace4d6bcf20691 100644 (file)
 
 namespace Friendica\Core\Config\ValueObject;
 
-use Friendica\Core\Config\Util\ConfigFileLoader;
+use Friendica\Core\Config\Util\ConfigFileManager;
 use ParagonIE\HiddenString\HiddenString;
 
 /**
  * The Friendica config cache for the application
  * Initial, all *.config.php files are loaded into this cache with the
- * ConfigFileLoader ( @see ConfigFileLoader )
+ * ConfigFileManager ( @see ConfigFileManager )
  */
 class Cache
 {
@@ -35,8 +35,8 @@ class Cache
        const SOURCE_STATIC = 0;
        /** @var int Indicates that the cache entry is set by file - Low Priority */
        const SOURCE_FILE = 1;
-       /** @var int Indicates that the cache entry is set by the DB config table - Middle Priority */
-       const SOURCE_DB = 2;
+       /** @var int Indicates that the cache entry is manually set by the application (per admin page/console) - Middle Priority */
+       const SOURCE_DATA = 2;
        /** @var int Indicates that the cache entry is set by a server environment variable - High Priority */
        const SOURCE_ENV = 3;
        /** @var int Indicates that the cache entry is fixed and must not be changed */
@@ -128,6 +128,34 @@ class Cache
                return $this->source[$cat][$key] ?? -1;
        }
 
+       /**
+        * Returns the whole config array based on the given source type
+        *
+        * @param int $source Indicates the source of the config entry
+        *
+        * @return array The config array part of the given source
+        */
+       public function getDataBySource(int $source): array
+       {
+               $data = [];
+
+               $categories = array_keys($this->source);
+
+               foreach ($categories as $category) {
+                       if (is_array($this->source[$category])) {
+                               $keys = array_keys($this->source[$category]);
+
+                               foreach ($keys as $key) {
+                                       if ($this->source[$category][$key] === $source) {
+                                               $data[$category][$key] = $this->config[$category][$key];
+                                       }
+                               }
+                       }
+               }
+
+               return $data;
+       }
+
        /**
         * Sets a value in the config cache. Accepts raw output from the config table
         *
index 35be8b43e29448d254dade73f30fdf8c6959b749..d31f3c1ced27102c71a40651aac7cf169aa83094 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace Friendica\Core\KeyValueStorage\Type;
 
-use Friendica\Core\Config\Util\ValueConversion;
+use Friendica\Core\PConfig\Util\ValueConversion;
 use Friendica\Core\KeyValueStorage\Exceptions\KeyValueStoragePersistenceException;
 use Friendica\Database\Database;
 
index 45043811834a40647a86fb4af25f75aea5519228..8da473839d553ec8e844324a15fb4e9dbab2ce8e 100644 (file)
@@ -160,8 +160,9 @@ class Update
                                                        Logger::warning('Pre update failed', ['version' => $version]);
                                                        DI::config()->set('system', 'update', Update::FAILED);
                                                        DI::lock()->release('dbupdate');
-                                                       DI::config()->set('system', 'maintenance', 0);
-                                                       DI::config()->set('system', 'maintenance_reason', '');
+                                                       DI::config()->set('system', 'maintenance', false, false);
+                                                       DI::config()->delete('system', 'maintenance_reason', false);
+                                                       DI::config()->save();
                                                        return $r;
                                                } else {
                                                        Logger::notice('Pre update executed.', ['version' => $version]);
@@ -181,8 +182,9 @@ class Update
                                                Logger::error('Update ERROR.', ['from' => $stored, 'to' => $current, 'retval' => $retval]);
                                                DI::config()->set('system', 'update', Update::FAILED);
                                                DI::lock()->release('dbupdate');
-                                               DI::config()->set('system', 'maintenance', 0);
-                                               DI::config()->set('system', 'maintenance_reason', '');
+                                               DI::config()->set('system', 'maintenance', false, false);
+                                               DI::config()->delete('system', 'maintenance_reason', false);
+                                               DI::config()->save();
                                                return $retval;
                                        } else {
                                                Logger::notice('Database structure update finished.', ['from' => $stored, 'to' => $current]);
@@ -198,8 +200,9 @@ class Update
                                                        Logger::warning('Post update failed', ['version' => $version]);
                                                        DI::config()->set('system', 'update', Update::FAILED);
                                                        DI::lock()->release('dbupdate');
-                                                       DI::config()->set('system', 'maintenance', 0);
-                                                       DI::config()->set('system', 'maintenance_reason', '');
+                                                       DI::config()->set('system', 'maintenance', false, false);
+                                                       DI::config()->delete('system', 'maintenance_reason', false);
+                                                       DI::config()->save();
                                                        return $r;
                                                } else {
                                                        DI::config()->set('system', 'build', $version);
@@ -210,8 +213,9 @@ class Update
                                        DI::config()->set('system', 'build', $current);
                                        DI::config()->set('system', 'update', Update::SUCCESS);
                                        DI::lock()->release('dbupdate');
-                                       DI::config()->set('system', 'maintenance', 0);
-                                       DI::config()->set('system', 'maintenance_reason', '');
+                                       DI::config()->set('system', 'maintenance', false, false);
+                                       DI::config()->delete('system', 'maintenance_reason',  false);
+                                       DI::config()->save();
 
                                        Logger::notice('Update success.', ['from' => $stored, 'to' => $current]);
                                        if ($sendMail) {
index 645084a96f5cc65a4c81c6c0771c7d2904405502..e3af408b9e4f9991e26e4c9e54dbb4f712004408 100644 (file)
@@ -74,7 +74,7 @@ class DBStructure
                $old_tables = ['fserver', 'gcign', 'gcontact', 'gcontact-relation', 'gfollower' ,'glink', 'item-delivery-data',
                        'item-activity', 'item-content', 'item_id', 'participation', 'poll', 'poll_result', 'queue', 'retriever_rule',
                        'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge',
-                       'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact'];
+                       'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact', 'config'];
 
                $tables = DBA::selectToArray('INFORMATION_SCHEMA.TABLES', ['TABLE_NAME'],
                        ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']);
@@ -176,14 +176,15 @@ class DBStructure
        public static function performUpdate(bool $enable_maintenance_mode = true, bool $verbose = false): string
        {
                if ($enable_maintenance_mode) {
-                       DI::config()->set('system', 'maintenance', 1);
+                       DI::config()->set('system', 'maintenance', true);
                }
 
                $status = self::update($verbose, true);
 
                if ($enable_maintenance_mode) {
-                       DI::config()->set('system', 'maintenance', 0);
-                       DI::config()->set('system', 'maintenance_reason', '');
+                       DI::config()->set('system', 'maintenance', false, false);
+                       DI::config()->delete('system', 'maintenance_reason', false);
+                       DI::config()->save();
                }
 
                return $status;
index 194d2cb2c7129efa1f5c9f801c833cae5257190b..cf2f6c5358d7f99e2e48adeae4b2923b6c478b51 100644 (file)
@@ -148,7 +148,7 @@ class Site extends BaseAdmin
 
                // Has the directory url changed? If yes, then resubmit the existing profiles there
                if ($global_directory != DI::config()->get('system', 'directory') && ($global_directory != '')) {
-                       DI::config()->set('system', 'directory', $global_directory);
+                       DI::config()->set('system', 'directory', $global_directory, false);
                        Worker::add(Worker::PRIORITY_LOW, 'Directory');
                }
 
@@ -194,131 +194,133 @@ class Site extends BaseAdmin
                                );
                        }
                }
-               DI::config()->set('system', 'ssl_policy'            , $ssl_policy);
-               DI::config()->set('system', 'maxloadavg'            , $maxloadavg);
-               DI::config()->set('system', 'min_memory'            , $min_memory);
-               DI::config()->set('system', 'optimize_tables'       , $optimize_tables);
-               DI::config()->set('system', 'contact_discovery'     , $contact_discovery);
-               DI::config()->set('system', 'synchronize_directory' , $synchronize_directory);
-               DI::config()->set('system', 'poco_requery_days'     , $poco_requery_days);
-               DI::config()->set('system', 'poco_discovery'        , $poco_discovery);
-               DI::config()->set('system', 'poco_local_search'     , $poco_local_search);
-               DI::config()->set('system', 'nodeinfo'              , $nodeinfo);
-               DI::config()->set('config', 'sitename'              , $sitename);
-               DI::config()->set('config', 'sender_email'          , $sender_email);
-               DI::config()->set('system', 'suppress_tags'         , $suppress_tags);
-               DI::config()->set('system', 'shortcut_icon'         , $shortcut_icon);
-               DI::config()->set('system', 'touch_icon'            , $touch_icon);
+               DI::config()->set('system', 'ssl_policy'            , $ssl_policy, false);
+               DI::config()->set('system', 'maxloadavg'            , $maxloadavg, false);
+               DI::config()->set('system', 'min_memory'            , $min_memory, false);
+               DI::config()->set('system', 'optimize_tables'       , $optimize_tables, false);
+               DI::config()->set('system', 'contact_discovery'     , $contact_discovery, false);
+               DI::config()->set('system', 'synchronize_directory' , $synchronize_directory, false);
+               DI::config()->set('system', 'poco_requery_days'     , $poco_requery_days, false);
+               DI::config()->set('system', 'poco_discovery'        , $poco_discovery, false);
+               DI::config()->set('system', 'poco_local_search'     , $poco_local_search, false);
+               DI::config()->set('system', 'nodeinfo'              , $nodeinfo, false);
+               DI::config()->set('config', 'sitename'              , $sitename, false);
+               DI::config()->set('config', 'sender_email'          , $sender_email, false);
+               DI::config()->set('system', 'suppress_tags'         , $suppress_tags, false);
+               DI::config()->set('system', 'shortcut_icon'         , $shortcut_icon, false);
+               DI::config()->set('system', 'touch_icon'            , $touch_icon, false);
 
                if ($banner == "") {
-                       DI::config()->delete('system', 'banner');
+                       DI::config()->set('system', 'banner', false);
                } else {
-                       DI::config()->set('system', 'banner', $banner);
+                       DI::config()->set('system', 'banner', $banner, false);
                }
 
                if (empty($email_banner)) {
-                       DI::config()->delete('system', 'email_banner');
+                       DI::config()->set('system', 'email_banner', false);
                } else {
-                       DI::config()->set('system', 'email_banner', $email_banner);
+                       DI::config()->set('system', 'email_banner', $email_banner, false);
                }
 
                if (empty($additional_info)) {
-                       DI::config()->delete('config', 'info');
+                       DI::config()->set('config', 'info', false);
                } else {
-                       DI::config()->set('config', 'info', $additional_info);
+                       DI::config()->set('config', 'info', $additional_info, false);
                }
-               DI::config()->set('system', 'language', $language);
-               DI::config()->set('system', 'theme', $theme);
+               DI::config()->set('system', 'language', $language, false);
+               DI::config()->set('system', 'theme', $theme, false);
                Theme::install($theme);
 
                if ($theme_mobile == '---') {
-                       DI::config()->delete('system', 'mobile-theme');
+                       DI::config()->set('system', 'mobile-theme', false);
                } else {
-                       DI::config()->set('system', 'mobile-theme', $theme_mobile);
+                       DI::config()->set('system', 'mobile-theme', $theme_mobile, false);
                }
                if ($singleuser == '---') {
-                       DI::config()->delete('system', 'singleuser');
+                       DI::config()->set('system', 'singleuser', false);
                } else {
-                       DI::config()->set('system', 'singleuser', $singleuser);
+                       DI::config()->set('system', 'singleuser', $singleuser, false);
                }
                if (preg_match('/\d+(?:\s*[kmg])?/i', $maximagesize)) {
-                       DI::config()->set('system', 'maximagesize', $maximagesize);
+                       DI::config()->set('system', 'maximagesize', $maximagesize, false);
                } else {
                        DI::sysmsg()->addNotice(DI::l10n()->t('%s is no valid input for maximum image size', $maximagesize));
                }
-               DI::config()->set('system', 'max_image_length'       , $maximagelength);
-               DI::config()->set('system', 'jpeg_quality'           , $jpegimagequality);
-
-               DI::config()->set('config', 'register_policy'        , $register_policy);
-               DI::config()->set('system', 'max_daily_registrations', $daily_registrations);
-               DI::config()->set('system', 'account_abandon_days'   , $abandon_days);
-               DI::config()->set('config', 'register_text'          , $register_text);
-               DI::config()->set('system', 'allowed_sites'          , $allowed_sites);
-               DI::config()->set('system', 'allowed_email'          , $allowed_email);
-               DI::config()->set('system', 'forbidden_nicknames'    , $forbidden_nicknames);
-               DI::config()->set('system', 'system_actor_name'      , $system_actor_name);
-               DI::config()->set('system', 'no_oembed_rich_content' , $no_oembed_rich_content);
-               DI::config()->set('system', 'allowed_oembed'         , $allowed_oembed);
-               DI::config()->set('system', 'block_public'           , $block_public);
-               DI::config()->set('system', 'publish_all'            , $force_publish);
-               DI::config()->set('system', 'newuser_private'        , $newuser_private);
-               DI::config()->set('system', 'enotify_no_content'     , $enotify_no_content);
-               DI::config()->set('system', 'disable_embedded'       , $disable_embedded);
-               DI::config()->set('system', 'allow_users_remote_self', $allow_users_remote_self);
-               DI::config()->set('system', 'explicit_content'       , $explicit_content);
-               DI::config()->set('system', 'proxify_content'        , $proxify_content);
-               DI::config()->set('system', 'cache_contact_avatar'   , $cache_contact_avatar);
-               DI::config()->set('system', 'check_new_version_url'  , $check_new_version_url);
-
-               DI::config()->set('system', 'block_extended_register', !$enable_multi_reg);
-               DI::config()->set('system', 'no_openid'              , !$enable_openid);
-               DI::config()->set('system', 'no_regfullname'         , !$enable_regfullname);
-               DI::config()->set('system', 'register_notification'  , $register_notification);
-               DI::config()->set('system', 'community_page_style'   , $community_page_style);
-               DI::config()->set('system', 'max_author_posts_community_page', $max_author_posts_community_page);
-               DI::config()->set('system', 'verifyssl'              , $verifyssl);
-               DI::config()->set('system', 'proxyuser'              , $proxyuser);
-               DI::config()->set('system', 'proxy'                  , $proxy);
-               DI::config()->set('system', 'curl_timeout'           , $timeout);
-               DI::config()->set('system', 'imap_disabled'          , !$mail_enabled && function_exists('imap_open'));
-               DI::config()->set('system', 'ostatus_disabled'       , !$ostatus_enabled);
-               DI::config()->set('system', 'diaspora_enabled'       , $diaspora_enabled);
-
-               DI::config()->set('config', 'private_addons'         , $private_addons);
-
-               DI::config()->set('system', 'force_ssl'              , $force_ssl);
-               DI::config()->set('system', 'hide_help'              , !$show_help);
-
-               DI::config()->set('system', 'dbclean'                , $dbclean);
-               DI::config()->set('system', 'dbclean-expire-days'    , $dbclean_expire_days);
-               DI::config()->set('system', 'dbclean_expire_conversation', $dbclean_expire_conv);
+               DI::config()->set('system', 'max_image_length'       , $maximagelength, false);
+               DI::config()->set('system', 'jpeg_quality'           , $jpegimagequality, false);
+
+               DI::config()->set('config', 'register_policy'        , $register_policy, false);
+               DI::config()->set('system', 'max_daily_registrations', $daily_registrations, false);
+               DI::config()->set('system', 'account_abandon_days'   , $abandon_days, false);
+               DI::config()->set('config', 'register_text'          , $register_text, false);
+               DI::config()->set('system', 'allowed_sites'          , $allowed_sites, false);
+               DI::config()->set('system', 'allowed_email'          , $allowed_email, false);
+               DI::config()->set('system', 'forbidden_nicknames'    , $forbidden_nicknames, false);
+               DI::config()->set('system', 'system_actor_name'      , $system_actor_name, false);
+               DI::config()->set('system', 'no_oembed_rich_content' , $no_oembed_rich_content, false);
+               DI::config()->set('system', 'allowed_oembed'         , $allowed_oembed, false);
+               DI::config()->set('system', 'block_public'           , $block_public, false);
+               DI::config()->set('system', 'publish_all'            , $force_publish, false);
+               DI::config()->set('system', 'newuser_private'        , $newuser_private, false);
+               DI::config()->set('system', 'enotify_no_content'     , $enotify_no_content, false);
+               DI::config()->set('system', 'disable_embedded'       , $disable_embedded, false);
+               DI::config()->set('system', 'allow_users_remote_self', $allow_users_remote_self, false);
+               DI::config()->set('system', 'explicit_content'       , $explicit_content, false);
+               DI::config()->set('system', 'proxify_content'        , $proxify_content, false);
+               DI::config()->set('system', 'cache_contact_avatar'   , $cache_contact_avatar, false);
+               DI::config()->set('system', 'check_new_version_url'  , $check_new_version_url, false);
+
+               DI::config()->set('system', 'block_extended_register', !$enable_multi_reg, false);
+               DI::config()->set('system', 'no_openid'              , !$enable_openid, false);
+               DI::config()->set('system', 'no_regfullname'         , !$enable_regfullname, false);
+               DI::config()->set('system', 'register_notification'  , $register_notification, false);
+               DI::config()->set('system', 'community_page_style'   , $community_page_style, false);
+               DI::config()->set('system', 'max_author_posts_community_page', $max_author_posts_community_page, false);
+               DI::config()->set('system', 'verifyssl'              , $verifyssl, false);
+               DI::config()->set('system', 'proxyuser'              , $proxyuser, false);
+               DI::config()->set('system', 'proxy'                  , $proxy, false);
+               DI::config()->set('system', 'curl_timeout'           , $timeout, false);
+               DI::config()->set('system', 'imap_disabled'          , !$mail_enabled && function_exists('imap_open'), false);
+               DI::config()->set('system', 'ostatus_disabled'       , !$ostatus_enabled, false);
+               DI::config()->set('system', 'diaspora_enabled'       , $diaspora_enabled, false);
+
+               DI::config()->set('config', 'private_addons'         , $private_addons, false);
+
+               DI::config()->set('system', 'force_ssl'              , $force_ssl, false);
+               DI::config()->set('system', 'hide_help'              , !$show_help, false);
+
+               DI::config()->set('system', 'dbclean'                , $dbclean, false);
+               DI::config()->set('system', 'dbclean-expire-days'    , $dbclean_expire_days, false);
+               DI::config()->set('system', 'dbclean_expire_conversation', $dbclean_expire_conv, false);
 
                if ($dbclean_unclaimed == 0) {
                        $dbclean_unclaimed = $dbclean_expire_days;
                }
 
-               DI::config()->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed);
+               DI::config()->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed, false);
 
-               DI::config()->set('system', 'max_comments', $max_comments);
-               DI::config()->set('system', 'max_display_comments', $max_display_comments);
+               DI::config()->set('system', 'max_comments', $max_comments, false);
+               DI::config()->set('system', 'max_display_comments', $max_display_comments, false);
 
                if ($temppath != '') {
                        $temppath = BasePath::getRealPath($temppath);
                }
 
-               DI::config()->set('system', 'temppath', $temppath);
+               DI::config()->set('system', 'temppath', $temppath, false);
 
-               DI::config()->set('system', 'only_tag_search'  , $only_tag_search);
-               DI::config()->set('system', 'compute_group_counts', $compute_group_counts);
+               DI::config()->set('system', 'only_tag_search'  , $only_tag_search, false);
+               DI::config()->set('system', 'compute_group_counts', $compute_group_counts, false);
 
-               DI::config()->set('system', 'worker_queues'    , $worker_queues);
-               DI::config()->set('system', 'worker_fastlane'  , $worker_fastlane);
+               DI::config()->set('system', 'worker_queues'    , $worker_queues, false);
+               DI::config()->set('system', 'worker_fastlane'  , $worker_fastlane, false);
 
-               DI::config()->set('system', 'relay_directly'   , $relay_directly);
-               DI::config()->set('system', 'relay_scope'      , $relay_scope);
-               DI::config()->set('system', 'relay_server_tags', $relay_server_tags);
-               DI::config()->set('system', 'relay_deny_tags'  , $relay_deny_tags);
-               DI::config()->set('system', 'relay_user_tags'  , $relay_user_tags);
+               DI::config()->set('system', 'relay_directly'   , $relay_directly, false);
+               DI::config()->set('system', 'relay_scope'      , $relay_scope, false);
+               DI::config()->set('system', 'relay_server_tags', $relay_server_tags, false);
+               DI::config()->set('system', 'relay_deny_tags'  , $relay_deny_tags, false);
+               DI::config()->set('system', 'relay_user_tags'  , $relay_user_tags, false);
+
+               DI::config()->save();
 
                DI::baseUrl()->redirect('admin/site' . $active_panel);
        }
@@ -332,8 +334,8 @@ class Site extends BaseAdmin
 
                if (DI::config()->get('system', 'directory_submit_url') &&
                        !DI::config()->get('system', 'directory')) {
-                       DI::config()->set('system', 'directory', dirname(DI::config()->get('system', 'directory_submit_url')));
-                       DI::config()->delete('system', 'directory_submit_url');
+                       DI::config()->set('system', 'directory', dirname(DI::config()->get('system', 'directory_submit_url')), false);
+                       DI::config()->delete('system', 'directory_submit_url', false);
                }
 
                /* Installed themes */
index 48e25961c2bc514b0c668aef9a874ff9a409f2e8..018bbf2c317bc3bfe5ec09b241e829df9ec6c336 100644 (file)
@@ -55,7 +55,7 @@
 use Friendica\Database\DBA;
 
 if (!defined('DB_UPDATE_VERSION')) {
-       define('DB_UPDATE_VERSION', 1507);
+       define('DB_UPDATE_VERSION', 1508);
 }
 
 return [
@@ -553,19 +553,6 @@ return [
                        "k_expires" => ["k", "expires"],
                ]
        ],
-       "config" => [
-               "comment" => "main configuration storage",
-               "fields" => [
-                       "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                       "cat" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => ""],
-                       "k" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => ""],
-                       "v" => ["type" => "mediumtext", "comment" => ""],
-               ],
-               "indexes" => [
-                       "PRIMARY" => ["id"],
-                       "cat_k" => ["UNIQUE", "cat", "k"],
-               ]
-       ],
        "contact-relation" => [
                "comment" => "Contact relations",
                "fields" => [
index c59d0478a195d1a4e482359e48001468c4d7bfa6..08867d86d947ba55f6ed6d271724b3f7b7253602 100644 (file)
@@ -76,7 +76,7 @@ return [
                        $_SERVER
                ]
        ],
-       Config\Util\ConfigFileLoader::class => [
+       Config\Util\ConfigFileManager::class => [
                'instanceOf' => Config\Factory\Config::class,
                'call'       => [
                        ['createConfigFileLoader', [
index 356877ff9b0d2c94a0cbd3e425c508cdccd92de5..fda04b6ce4b01881af95741464a0959a2ded10a5 100644 (file)
@@ -1175,3 +1175,22 @@ function update_1505()
 
        return DBA::delete('config', $conditions) ? Update::SUCCESS : Update::FAILED;
 }
+
+function update_1508()
+{
+       $categories = DBA::toArray(DBA::p("SELECT DISTINCT `cat` AS 'cat' FROM `config`"));
+
+       foreach ($categories as $category) {
+               DI::config()->load($category['cat']);
+       }
+
+       $config = DBA::selectToArray('config');
+
+       foreach ($config as $entry) {
+               DI::config()->set($entry['cat'], $entry['k'], $entry['v'], false);
+       }
+
+       DI::config()->save();
+
+       DBA::e("DELETE FROM `config`");
+}