Introduce ISetConfigValuesTransactional for transactional config behaviour

This commit is contained in:
Philipp 2023-01-03 14:18:53 +01:00
parent 4d4b4a8858
commit 65d79d4c93
No known key found for this signature in database
GPG Key ID: 24A7501396EB5432
14 changed files with 588 additions and 150 deletions

View File

@ -100,17 +100,19 @@ HELP;
$enabled = intval($this->getArgument(0)); $enabled = intval($this->getArgument(0));
$this->config->set('system', 'maintenance', $enabled, false); $transactionConfig = $this->config->transactional();
$transactionConfig->set('system', 'maintenance', $enabled);
$reason = $this->getArgument(1); $reason = $this->getArgument(1);
if ($enabled && $this->getArgument(1)) { if ($enabled && $this->getArgument(1)) {
$this->config->set('system', 'maintenance_reason', $this->getArgument(1), false); $transactionConfig->set('system', 'maintenance_reason', $this->getArgument(1));
} else { } else {
$this->config->set('system', 'maintenance_reason', '', false); $transactionConfig->delete('system', 'maintenance_reason');
} }
$this->config->save(); $transactionConfig->save();
if ($enabled) { if ($enabled) {
$mode_str = "maintenance mode"; $mode_str = "maintenance mode";

View File

@ -189,9 +189,10 @@ HELP;
return 1; return 1;
} finally { } finally {
$this->out('Leaving maintenance mode'); $this->out('Leaving maintenance mode');
$this->config->set('system', 'maintenance', false, false); $this->config->transactional()
$this->config->set('system', 'maintenance_reason', '', false); ->set('system', 'maintenance', false)
$this->config->save(); ->delete('system', 'maintenance_reason')
->save();
} }
// send relocate // send relocate

View File

@ -22,6 +22,7 @@
namespace Friendica\Core\Config\Capability; namespace Friendica\Core\Config\Capability;
use Friendica\Core\Config\Exception\ConfigPersistenceException; use Friendica\Core\Config\Exception\ConfigPersistenceException;
use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\ValueObject\Cache;
/** /**
@ -57,6 +58,20 @@ interface IManageConfigValues
*/ */
public function get(string $cat, string $key, $default_value = null); public function get(string $cat, string $key, $default_value = null);
/**
* Load all configuration values from a given cache and saves it back in the configuration node store
* @see ConfigFileManager::CONFIG_DATA_FILE
*
* All configuration values of the system are stored in the cache.
*
* @param Cache $cache a new cache
*
* @return void
*
* @throws ConfigPersistenceException In case the persistence layer throws errors
*/
public function load(Cache $cache);
/** /**
* Sets a configuration value for system config * Sets a configuration value for system config
* *
@ -67,20 +82,21 @@ interface IManageConfigValues
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* @param string $key The configuration key to set * @param string $key The configuration key to set
* @param mixed $value The value to store * @param mixed $value The value to store
* @param bool $autosave If true, implicit save the value
* *
* @return bool Operation success * @return bool Operation success
* *
* @throws ConfigPersistenceException In case the persistence layer throws errors * @throws ConfigPersistenceException In case the persistence layer throws errors
*/ */
public function set(string $cat, string $key, $value, bool $autosave = true): bool; public function set(string $cat, string $key, $value): bool;
/** /**
* Save back the overridden values of the config cache * Creates a transactional config value store, which is used to set a bunch of values at once
* *
* @throws ConfigPersistenceException In case the persistence layer throws errors * It relies on the current instance, so after save(), the values of this config class will get altered at once too.
*
* @return ISetConfigValuesTransactional
*/ */
public function save(); public function transactional(): ISetConfigValuesTransactional;
/** /**
* Deletes the given key from the system configuration. * Deletes the given key from the system configuration.
@ -89,14 +105,13 @@ interface IManageConfigValues
* *
* @param string $cat The category of the configuration value * @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
* @param bool $autosave If true, implicit save the value
* *
* @return bool * @return bool
* *
* @throws ConfigPersistenceException In case the persistence layer throws errors * @throws ConfigPersistenceException In case the persistence layer throws errors
* *
*/ */
public function delete(string $cat, string $key, bool $autosave = true): bool; public function delete(string $cat, string $key): bool;
/** /**
* Returns the Config Cache * Returns the Config Cache

View File

@ -0,0 +1,84 @@
<?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\Capability;
use Friendica\Core\Config\Exception\ConfigPersistenceException;
/**
* Interface for transactional saving of config values
* It buffers every set/delete until "save()" is called
*/
interface ISetConfigValuesTransactional
{
/**
* Get a particular user's config variable given the category name
* ($cat) and a $key.
*
* Get a particular config value from the given category ($cat)
*
* @param string $cat The category of the configuration value
* @param string $key The configuration key to query
*
* @return mixed Stored value or null if it does not exist
*
* @throws ConfigPersistenceException In case the persistence layer throws errors
*
*/
public function get(string $cat, string $key);
/**
* Sets a configuration value for system 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
*
* @return static the current instance
*
* @throws ConfigPersistenceException In case the persistence layer throws errors
*/
public function set(string $cat, string $key, $value): self;
/**
* Deletes the given key from the system configuration.
*
* @param string $cat The category of the configuration value
* @param string $key The configuration key to delete
*
* @return static the current instance
*
* @throws ConfigPersistenceException In case the persistence layer throws errors
*
*/
public function delete(string $cat, string $key): self;
/**
* Saves the node specific config values
*
* @throws ConfigPersistenceException In case the persistence layer throws errors
*/
public function save(): void;
}

View File

@ -22,6 +22,7 @@
namespace Friendica\Core\Config\Model; namespace Friendica\Core\Config\Model;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Config\Capability\ISetConfigValuesTransactional;
use Friendica\Core\Config\Exception\ConfigFileException; use Friendica\Core\Config\Exception\ConfigFileException;
use Friendica\Core\Config\Exception\ConfigPersistenceException; use Friendica\Core\Config\Exception\ConfigPersistenceException;
use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\Util\ConfigFileManager;
@ -62,7 +63,16 @@ class Config implements IManageConfigValues
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
public function save() public function transactional(): ISetConfigValuesTransactional
{
return new TransactionalConfig($this);
}
/**
* Saves the current Configuration back into the data config.
* @see ConfigFileManager::CONFIG_DATA_FILE
*/
protected function save()
{ {
try { try {
$this->configFileManager->saveData($this->configCache); $this->configFileManager->saveData($this->configCache);
@ -84,6 +94,13 @@ class Config implements IManageConfigValues
$this->configCache = $configCache; $this->configCache = $configCache;
} }
/** {@inheritDoc} */
public function load(Cache $cache)
{
$this->configCache = $cache;
$this->save();
}
/** {@inheritDoc} */ /** {@inheritDoc} */
public function get(string $cat, string $key, $default_value = null) public function get(string $cat, string $key, $default_value = null)
{ {
@ -91,26 +108,24 @@ class Config implements IManageConfigValues
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
public function set(string $cat, string $key, $value, bool $autosave = true): bool public function set(string $cat, string $key, $value): bool
{ {
$stored = $this->configCache->set($cat, $key, $value, Cache::SOURCE_DATA); if ($this->configCache->set($cat, $key, $value, Cache::SOURCE_DATA)) {
if ($stored && $autosave) {
$this->save(); $this->save();
return true;
} else {
return false;
} }
return $stored;
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
public function delete(string $cat, string $key, bool $autosave = true): bool public function delete(string $cat, string $key): bool
{ {
$removed = $this->configCache->delete($cat, $key); if ($this->configCache->delete($cat, $key)) {
if ($removed && $autosave) {
$this->save(); $this->save();
return true;
} else {
return false;
} }
return $removed;
} }
} }

View File

@ -0,0 +1,89 @@
<?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\Model;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Config\Capability\ISetConfigValuesTransactional;
use Friendica\Core\Config\Exception\ConfigPersistenceException;
use Friendica\Core\Config\ValueObject\Cache;
/**
* config class, which sets values into a temporary buffer until "save()" is called
*/
class TransactionalConfig implements ISetConfigValuesTransactional
{
/** @var IManageConfigValues */
protected $config;
/** @var Cache */
protected $cache;
/** @var Cache */
protected $delCache;
public function __construct(IManageConfigValues $config)
{
$this->config = $config;
$this->cache = new Cache();
$this->delCache = new Cache();
}
/** {@inheritDoc} */
public function get(string $cat, string $key)
{
return !$this->delCache->get($cat, $key) ?
($this->cache->get($cat, $key) ?? $this->config->get($cat, $key)) :
null;
}
/** {@inheritDoc} */
public function set(string $cat, string $key, $value): ISetConfigValuesTransactional
{
$this->cache->set($cat, $key, $value, Cache::SOURCE_DATA);
return $this;
}
/** {@inheritDoc} */
public function delete(string $cat, string $key): ISetConfigValuesTransactional
{
$this->cache->delete($cat, $key);
$this->delCache->set($cat, $key, 'deleted');
return $this;
}
/** {@inheritDoc} */
public function save(): void
{
try {
$newCache = $this->config->getCache()->merge($this->cache);
$newCache = $newCache->diff($this->delCache);
$this->config->load($newCache);
// flush current cache
$this->cache = new Cache();
$this->delCache = new Cache();
} catch (\Exception $e) {
throw new ConfigPersistenceException('Cannot save config', $e);
}
}
}

View File

@ -279,4 +279,71 @@ class Cache
return $return; return $return;
} }
/**
* Merges a new Cache into the existing one and returns the merged Cache
*
* @param Cache $cache The cache, which should get merged into this Cache
*
* @return Cache The merged Cache
*/
public function merge(Cache $cache): Cache
{
$newConfig = $this->config;
$newSource = $this->source;
$categories = array_keys($cache->config);
foreach ($categories as $category) {
if (is_array($cache->config[$category])) {
$keys = array_keys($cache->config[$category]);
foreach ($keys as $key) {
$newConfig[$category][$key] = $cache->config[$category][$key];
$newSource[$category][$key] = $cache->source[$category][$key];
}
}
}
$newCache = new Cache();
$newCache->config = $newConfig;
$newCache->source = $newSource;
return $newCache;
}
/**
* Diffs a new Cache into the existing one and returns the diffed Cache
*
* @param Cache $cache The cache, which should get deleted for the current Cache
*
* @return Cache The diffed Cache
*/
public function diff(Cache $cache): Cache
{
$newConfig = $this->config;
$newSource = $this->source;
$categories = array_keys($cache->config);
foreach ($categories as $category) {
if (is_array($cache->config[$category])) {
$keys = array_keys($cache->config[$category]);
foreach ($keys as $key) {
if (!is_null($newConfig[$category][$key] ?? null)) {
unset($newConfig[$category][$key]);
unset($newSource[$category][$key]);
}
}
}
}
$newCache = new Cache();
$newCache->config = $newConfig;
$newCache->source = $newSource;
return $newCache;
}
} }

View File

@ -160,9 +160,10 @@ class Update
Logger::warning('Pre update failed', ['version' => $version]); Logger::warning('Pre update failed', ['version' => $version]);
DI::config()->set('system', 'update', Update::FAILED); DI::config()->set('system', 'update', Update::FAILED);
DI::lock()->release('dbupdate'); DI::lock()->release('dbupdate');
DI::config()->set('system', 'maintenance', false, false); DI::config()->transactional()
DI::config()->delete('system', 'maintenance_reason', false); ->set('system', 'maintenance', false)
DI::config()->save(); ->delete('system', 'maintenance_reason')
->save();
return $r; return $r;
} else { } else {
Logger::notice('Pre update executed.', ['version' => $version]); Logger::notice('Pre update executed.', ['version' => $version]);
@ -182,9 +183,10 @@ class Update
Logger::error('Update ERROR.', ['from' => $stored, 'to' => $current, 'retval' => $retval]); Logger::error('Update ERROR.', ['from' => $stored, 'to' => $current, 'retval' => $retval]);
DI::config()->set('system', 'update', Update::FAILED); DI::config()->set('system', 'update', Update::FAILED);
DI::lock()->release('dbupdate'); DI::lock()->release('dbupdate');
DI::config()->set('system', 'maintenance', false, false); DI::config()->transactional()
DI::config()->delete('system', 'maintenance_reason', false); ->set('system', 'maintenance', false)
DI::config()->save(); ->delete('system', 'maintenance_reason')
->save();
return $retval; return $retval;
} else { } else {
Logger::notice('Database structure update finished.', ['from' => $stored, 'to' => $current]); Logger::notice('Database structure update finished.', ['from' => $stored, 'to' => $current]);
@ -200,9 +202,10 @@ class Update
Logger::warning('Post update failed', ['version' => $version]); Logger::warning('Post update failed', ['version' => $version]);
DI::config()->set('system', 'update', Update::FAILED); DI::config()->set('system', 'update', Update::FAILED);
DI::lock()->release('dbupdate'); DI::lock()->release('dbupdate');
DI::config()->set('system', 'maintenance', false, false); DI::config()->transactional()
DI::config()->delete('system', 'maintenance_reason', false); ->set('system', 'maintenance', false)
DI::config()->save(); ->delete('system', 'maintenance_reason')
->save();
return $r; return $r;
} else { } else {
DI::config()->set('system', 'build', $version); DI::config()->set('system', 'build', $version);
@ -213,9 +216,10 @@ class Update
DI::config()->set('system', 'build', $current); DI::config()->set('system', 'build', $current);
DI::config()->set('system', 'update', Update::SUCCESS); DI::config()->set('system', 'update', Update::SUCCESS);
DI::lock()->release('dbupdate'); DI::lock()->release('dbupdate');
DI::config()->set('system', 'maintenance', false, false); DI::config()->transactional()
DI::config()->delete('system', 'maintenance_reason', false); ->set('system', 'maintenance', false)
DI::config()->save(); ->delete('system', 'maintenance_reason')
->save();
Logger::notice('Update success.', ['from' => $stored, 'to' => $current]); Logger::notice('Update success.', ['from' => $stored, 'to' => $current]);
if ($sendMail) { if ($sendMail) {

View File

@ -182,9 +182,10 @@ class DBStructure
$status = self::update($verbose, true); $status = self::update($verbose, true);
if ($enable_maintenance_mode) { if ($enable_maintenance_mode) {
DI::config()->set('system', 'maintenance', false, false); DI::config()->transactional()
DI::config()->delete('system', 'maintenance_reason', false); ->set('system', 'maintenance', false)
DI::config()->save(); ->delete('system', 'maintenance_reason')
->save();
} }
return $status; return $status;

View File

@ -48,8 +48,6 @@ class Site extends BaseAdmin
self::checkFormSecurityTokenRedirectOnError('/admin/site', 'admin_site'); self::checkFormSecurityTokenRedirectOnError('/admin/site', 'admin_site');
$a = DI::app();
if (!empty($_POST['republish_directory'])) { if (!empty($_POST['republish_directory'])) {
Worker::add(Worker::PRIORITY_LOW, 'Directory'); Worker::add(Worker::PRIORITY_LOW, 'Directory');
return; return;
@ -146,9 +144,11 @@ class Site extends BaseAdmin
$relay_user_tags = !empty($_POST['relay_user_tags']); $relay_user_tags = !empty($_POST['relay_user_tags']);
$active_panel = (!empty($_POST['active_panel']) ? "#" . trim($_POST['active_panel']) : ''); $active_panel = (!empty($_POST['active_panel']) ? "#" . trim($_POST['active_panel']) : '');
$transactionConfig = DI::config()->transactional();
// Has the directory url changed? If yes, then resubmit the existing profiles there // Has the directory url changed? If yes, then resubmit the existing profiles there
if ($global_directory != DI::config()->get('system', 'directory') && ($global_directory != '')) { if ($global_directory != DI::config()->get('system', 'directory') && ($global_directory != '')) {
DI::config()->set('system', 'directory', $global_directory, false); $transactionConfig->set('system', 'directory', $global_directory);
Worker::add(Worker::PRIORITY_LOW, 'Directory'); Worker::add(Worker::PRIORITY_LOW, 'Directory');
} }
@ -194,133 +194,133 @@ class Site extends BaseAdmin
); );
} }
} }
DI::config()->set('system', 'ssl_policy' , $ssl_policy, false); $transactionConfig->set('system', 'ssl_policy' , $ssl_policy);
DI::config()->set('system', 'maxloadavg' , $maxloadavg, false); $transactionConfig->set('system', 'maxloadavg' , $maxloadavg);
DI::config()->set('system', 'min_memory' , $min_memory, false); $transactionConfig->set('system', 'min_memory' , $min_memory);
DI::config()->set('system', 'optimize_tables' , $optimize_tables, false); $transactionConfig->set('system', 'optimize_tables' , $optimize_tables);
DI::config()->set('system', 'contact_discovery' , $contact_discovery, false); $transactionConfig->set('system', 'contact_discovery' , $contact_discovery);
DI::config()->set('system', 'synchronize_directory' , $synchronize_directory, false); $transactionConfig->set('system', 'synchronize_directory' , $synchronize_directory);
DI::config()->set('system', 'poco_requery_days' , $poco_requery_days, false); $transactionConfig->set('system', 'poco_requery_days' , $poco_requery_days);
DI::config()->set('system', 'poco_discovery' , $poco_discovery, false); $transactionConfig->set('system', 'poco_discovery' , $poco_discovery);
DI::config()->set('system', 'poco_local_search' , $poco_local_search, false); $transactionConfig->set('system', 'poco_local_search' , $poco_local_search);
DI::config()->set('system', 'nodeinfo' , $nodeinfo, false); $transactionConfig->set('system', 'nodeinfo' , $nodeinfo);
DI::config()->set('config', 'sitename' , $sitename, false); $transactionConfig->set('config', 'sitename' , $sitename);
DI::config()->set('config', 'sender_email' , $sender_email, false); $transactionConfig->set('config', 'sender_email' , $sender_email);
DI::config()->set('system', 'suppress_tags' , $suppress_tags, false); $transactionConfig->set('system', 'suppress_tags' , $suppress_tags);
DI::config()->set('system', 'shortcut_icon' , $shortcut_icon, false); $transactionConfig->set('system', 'shortcut_icon' , $shortcut_icon);
DI::config()->set('system', 'touch_icon' , $touch_icon, false); $transactionConfig->set('system', 'touch_icon' , $touch_icon);
if ($banner == "") { if ($banner == "") {
DI::config()->delete('system', 'banner', false); $transactionConfig->delete('system', 'banner');
} else { } else {
DI::config()->set('system', 'banner', $banner, false); $transactionConfig->set('system', 'banner', $banner);
} }
if (empty($email_banner)) { if (empty($email_banner)) {
DI::config()->delete('system', 'email_banner', false); $transactionConfig->delete('system', 'email_banner');
} else { } else {
DI::config()->set('system', 'email_banner', $email_banner, false); $transactionConfig->set('system', 'email_banner', $email_banner);
} }
if (empty($additional_info)) { if (empty($additional_info)) {
DI::config()->delete('config', 'info', false); $transactionConfig->delete('config', 'info');
} else { } else {
DI::config()->set('config', 'info', $additional_info, false); $transactionConfig->set('config', 'info', $additional_info);
} }
DI::config()->set('system', 'language', $language, false); $transactionConfig->set('system', 'language', $language);
DI::config()->set('system', 'theme', $theme, false); $transactionConfig->set('system', 'theme', $theme);
Theme::install($theme); Theme::install($theme);
if ($theme_mobile == '---') { if ($theme_mobile == '---') {
DI::config()->delete('system', 'mobile-theme', false); $transactionConfig->delete('system', 'mobile-theme');
} else { } else {
DI::config()->set('system', 'mobile-theme', $theme_mobile, false); $transactionConfig->set('system', 'mobile-theme', $theme_mobile);
} }
if ($singleuser == '---') { if ($singleuser == '---') {
DI::config()->delete('system', 'singleuser', false); $transactionConfig->delete('system', 'singleuser');
} else { } else {
DI::config()->set('system', 'singleuser', $singleuser, false); $transactionConfig->set('system', 'singleuser', $singleuser);
} }
if (preg_match('/\d+(?:\s*[kmg])?/i', $maximagesize)) { if (preg_match('/\d+(?:\s*[kmg])?/i', $maximagesize)) {
DI::config()->set('system', 'maximagesize', $maximagesize, false); $transactionConfig->set('system', 'maximagesize', $maximagesize);
} else { } else {
DI::sysmsg()->addNotice(DI::l10n()->t('%s is no valid input for maximum image size', $maximagesize)); DI::sysmsg()->addNotice(DI::l10n()->t('%s is no valid input for maximum image size', $maximagesize));
} }
DI::config()->set('system', 'max_image_length' , $maximagelength, false); $transactionConfig->set('system', 'max_image_length' , $maximagelength);
DI::config()->set('system', 'jpeg_quality' , $jpegimagequality, false); $transactionConfig->set('system', 'jpeg_quality' , $jpegimagequality);
DI::config()->set('config', 'register_policy' , $register_policy, false); $transactionConfig->set('config', 'register_policy' , $register_policy);
DI::config()->set('system', 'max_daily_registrations', $daily_registrations, false); $transactionConfig->set('system', 'max_daily_registrations', $daily_registrations);
DI::config()->set('system', 'account_abandon_days' , $abandon_days, false); $transactionConfig->set('system', 'account_abandon_days' , $abandon_days);
DI::config()->set('config', 'register_text' , $register_text, false); $transactionConfig->set('config', 'register_text' , $register_text);
DI::config()->set('system', 'allowed_sites' , $allowed_sites, false); $transactionConfig->set('system', 'allowed_sites' , $allowed_sites);
DI::config()->set('system', 'allowed_email' , $allowed_email, false); $transactionConfig->set('system', 'allowed_email' , $allowed_email);
DI::config()->set('system', 'forbidden_nicknames' , $forbidden_nicknames, false); $transactionConfig->set('system', 'forbidden_nicknames' , $forbidden_nicknames);
DI::config()->set('system', 'system_actor_name' , $system_actor_name, false); $transactionConfig->set('system', 'system_actor_name' , $system_actor_name);
DI::config()->set('system', 'no_oembed_rich_content' , $no_oembed_rich_content, false); $transactionConfig->set('system', 'no_oembed_rich_content' , $no_oembed_rich_content);
DI::config()->set('system', 'allowed_oembed' , $allowed_oembed, false); $transactionConfig->set('system', 'allowed_oembed' , $allowed_oembed);
DI::config()->set('system', 'block_public' , $block_public, false); $transactionConfig->set('system', 'block_public' , $block_public);
DI::config()->set('system', 'publish_all' , $force_publish, false); $transactionConfig->set('system', 'publish_all' , $force_publish);
DI::config()->set('system', 'newuser_private' , $newuser_private, false); $transactionConfig->set('system', 'newuser_private' , $newuser_private);
DI::config()->set('system', 'enotify_no_content' , $enotify_no_content, false); $transactionConfig->set('system', 'enotify_no_content' , $enotify_no_content);
DI::config()->set('system', 'disable_embedded' , $disable_embedded, false); $transactionConfig->set('system', 'disable_embedded' , $disable_embedded);
DI::config()->set('system', 'allow_users_remote_self', $allow_users_remote_self, false); $transactionConfig->set('system', 'allow_users_remote_self', $allow_users_remote_self);
DI::config()->set('system', 'explicit_content' , $explicit_content, false); $transactionConfig->set('system', 'explicit_content' , $explicit_content);
DI::config()->set('system', 'proxify_content' , $proxify_content, false); $transactionConfig->set('system', 'proxify_content' , $proxify_content);
DI::config()->set('system', 'cache_contact_avatar' , $cache_contact_avatar, false); $transactionConfig->set('system', 'cache_contact_avatar' , $cache_contact_avatar);
DI::config()->set('system', 'check_new_version_url' , $check_new_version_url, false); $transactionConfig->set('system', 'check_new_version_url' , $check_new_version_url);
DI::config()->set('system', 'block_extended_register', !$enable_multi_reg, false); $transactionConfig->set('system', 'block_extended_register', !$enable_multi_reg);
DI::config()->set('system', 'no_openid' , !$enable_openid, false); $transactionConfig->set('system', 'no_openid' , !$enable_openid);
DI::config()->set('system', 'no_regfullname' , !$enable_regfullname, false); $transactionConfig->set('system', 'no_regfullname' , !$enable_regfullname);
DI::config()->set('system', 'register_notification' , $register_notification, false); $transactionConfig->set('system', 'register_notification' , $register_notification);
DI::config()->set('system', 'community_page_style' , $community_page_style, false); $transactionConfig->set('system', 'community_page_style' , $community_page_style);
DI::config()->set('system', 'max_author_posts_community_page', $max_author_posts_community_page, false); $transactionConfig->set('system', 'max_author_posts_community_page', $max_author_posts_community_page);
DI::config()->set('system', 'verifyssl' , $verifyssl, false); $transactionConfig->set('system', 'verifyssl' , $verifyssl);
DI::config()->set('system', 'proxyuser' , $proxyuser, false); $transactionConfig->set('system', 'proxyuser' , $proxyuser);
DI::config()->set('system', 'proxy' , $proxy, false); $transactionConfig->set('system', 'proxy' , $proxy);
DI::config()->set('system', 'curl_timeout' , $timeout, false); $transactionConfig->set('system', 'curl_timeout' , $timeout);
DI::config()->set('system', 'imap_disabled' , !$mail_enabled && function_exists('imap_open'), false); $transactionConfig->set('system', 'imap_disabled' , !$mail_enabled && function_exists('imap_open'));
DI::config()->set('system', 'ostatus_disabled' , !$ostatus_enabled, false); $transactionConfig->set('system', 'ostatus_disabled' , !$ostatus_enabled);
DI::config()->set('system', 'diaspora_enabled' , $diaspora_enabled, false); $transactionConfig->set('system', 'diaspora_enabled' , $diaspora_enabled);
DI::config()->set('config', 'private_addons' , $private_addons, false); $transactionConfig->set('config', 'private_addons' , $private_addons);
DI::config()->set('system', 'force_ssl' , $force_ssl, false); $transactionConfig->set('system', 'force_ssl' , $force_ssl);
DI::config()->set('system', 'hide_help' , !$show_help, false); $transactionConfig->set('system', 'hide_help' , !$show_help);
DI::config()->set('system', 'dbclean' , $dbclean, false); $transactionConfig->set('system', 'dbclean' , $dbclean);
DI::config()->set('system', 'dbclean-expire-days' , $dbclean_expire_days, false); $transactionConfig->set('system', 'dbclean-expire-days' , $dbclean_expire_days);
DI::config()->set('system', 'dbclean_expire_conversation', $dbclean_expire_conv, false); $transactionConfig->set('system', 'dbclean_expire_conversation', $dbclean_expire_conv);
if ($dbclean_unclaimed == 0) { if ($dbclean_unclaimed == 0) {
$dbclean_unclaimed = $dbclean_expire_days; $dbclean_unclaimed = $dbclean_expire_days;
} }
DI::config()->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed, false); $transactionConfig->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed);
DI::config()->set('system', 'max_comments', $max_comments, false); $transactionConfig->set('system', 'max_comments', $max_comments);
DI::config()->set('system', 'max_display_comments', $max_display_comments, false); $transactionConfig->set('system', 'max_display_comments', $max_display_comments);
if ($temppath != '') { if ($temppath != '') {
$temppath = BasePath::getRealPath($temppath); $temppath = BasePath::getRealPath($temppath);
} }
DI::config()->set('system', 'temppath', $temppath, false); $transactionConfig->set('system', 'temppath', $temppath);
DI::config()->set('system', 'only_tag_search' , $only_tag_search, false); $transactionConfig->set('system', 'only_tag_search' , $only_tag_search);
DI::config()->set('system', 'compute_group_counts', $compute_group_counts, false); $transactionConfig->set('system', 'compute_group_counts', $compute_group_counts);
DI::config()->set('system', 'worker_queues' , $worker_queues, false); $transactionConfig->set('system', 'worker_queues' , $worker_queues);
DI::config()->set('system', 'worker_fastlane' , $worker_fastlane, false); $transactionConfig->set('system', 'worker_fastlane' , $worker_fastlane);
DI::config()->set('system', 'relay_directly' , $relay_directly, false); $transactionConfig->set('system', 'relay_directly' , $relay_directly);
DI::config()->set('system', 'relay_scope' , $relay_scope, false); $transactionConfig->set('system', 'relay_scope' , $relay_scope);
DI::config()->set('system', 'relay_server_tags', $relay_server_tags, false); $transactionConfig->set('system', 'relay_server_tags', $relay_server_tags);
DI::config()->set('system', 'relay_deny_tags' , $relay_deny_tags, false); $transactionConfig->set('system', 'relay_deny_tags' , $relay_deny_tags);
DI::config()->set('system', 'relay_user_tags' , $relay_user_tags, false); $transactionConfig->set('system', 'relay_user_tags' , $relay_user_tags);
DI::config()->save(); $transactionConfig->save();
DI::baseUrl()->redirect('admin/site' . $active_panel); DI::baseUrl()->redirect('admin/site' . $active_panel);
} }
@ -334,8 +334,8 @@ class Site extends BaseAdmin
if (DI::config()->get('system', 'directory_submit_url') && if (DI::config()->get('system', 'directory_submit_url') &&
!DI::config()->get('system', 'directory')) { !DI::config()->get('system', 'directory')) {
DI::config()->set('system', 'directory', dirname(DI::config()->get('system', 'directory_submit_url')), false); DI::config()->set('system', 'directory', dirname(DI::config()->get('system', 'directory_submit_url')));
DI::config()->delete('system', 'directory_submit_url', false); DI::config()->delete('system', 'directory_submit_url');
} }
/* Installed themes */ /* Installed themes */

View File

@ -358,4 +358,52 @@ class CacheTest extends MockedTest
$this->assertEquals(['system' => ['test_2' => 'with_data']], $configCache->getDataBySource(Cache::SOURCE_DATA)); $this->assertEquals(['system' => ['test_2' => 'with_data']], $configCache->getDataBySource(Cache::SOURCE_DATA));
$this->assertEquals($data, $configCache->getDataBySource(Cache::SOURCE_FILE)); $this->assertEquals($data, $configCache->getDataBySource(Cache::SOURCE_FILE));
} }
/**
* @dataProvider dataTests
*/
public function testMerge($data)
{
$configCache = new Cache();
$configCache->load($data, Cache::SOURCE_FILE);
$configCache->set('system', 'test_2','with_data', Cache::SOURCE_DATA);
$configCache->set('config', 'test_override','with_another_data', Cache::SOURCE_DATA);
$newCache = new Cache();
$newCache->set('config', 'test_override','override it again', Cache::SOURCE_DATA);
$newCache->set('system', 'test_3','new value', Cache::SOURCE_DATA);
$mergedCache = $configCache->merge($newCache);
self::assertEquals('with_data', $mergedCache->get('system', 'test_2'));
self::assertEquals('override it again', $mergedCache->get('config', 'test_override'));
self::assertEquals('new value', $mergedCache->get('system', 'test_3'));
}
/**
* @dataProvider dataTests
*/
public function testDiff($data)
{
$configCache = new Cache();
$configCache->load($data, Cache::SOURCE_FILE);
$configCache->set('system', 'test_2','with_data', Cache::SOURCE_DATA);
$configCache->set('config', 'test_override','with_another_data', Cache::SOURCE_DATA);
$newCache = new Cache();
$newCache->set('config', 'test_override','override it again', Cache::SOURCE_DATA);
$newCache->set('system', 'test_3','new value', Cache::SOURCE_DATA);
$mergedCache = $configCache->diff($newCache);
print_r($mergedCache);
self::assertEquals('with_data', $mergedCache->get('system', 'test_2'));
// existing entry was dropped
self::assertNull($mergedCache->get('config', 'test_override'));
// the newCache entry wasn't set, because we Diff
self::assertNull($mergedCache->get('system', 'test_3'));
}
} }

View File

@ -21,8 +21,8 @@
namespace Friendica\Test\src\Core\Config\Cache; namespace Friendica\Test\src\Core\Config\Cache;
use Friendica\Core\Config\Cache;
use Friendica\Core\Config\Factory\Config; use Friendica\Core\Config\Factory\Config;
use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Test\Util\VFSTrait; use Friendica\Test\Util\VFSTrait;
use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\Util\ConfigFileManager;
@ -51,7 +51,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -77,7 +77,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
} }
@ -106,7 +106,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -143,7 +143,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -179,7 +179,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -270,7 +270,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -304,7 +304,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -338,7 +338,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -354,7 +354,7 @@ class ConfigFileLoaderTest extends MockedTest
$this->delConfigFile('local.config.php'); $this->delConfigFile('local.config.php');
$configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => '/a/wrong/dir/']); $configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => '/a/wrong/dir/']);
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -380,7 +380,7 @@ class ConfigFileLoaderTest extends MockedTest
->setContent(file_get_contents($fileDir . 'B.config.php')); ->setContent(file_get_contents($fileDir . 'B.config.php'));
$configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()]); $configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()]);
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -403,18 +403,18 @@ class ConfigFileLoaderTest extends MockedTest
->setContent(file_get_contents($fileDir . 'B.config.php')); ->setContent(file_get_contents($fileDir . 'B.config.php'));
$configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()]); $configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()]);
$configCache = new \Friendica\Core\Config\ValueObject\Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
// overwrite some data and save it back to the config file // overwrite some data and save it back to the config file
$configCache->set('system', 'test', 'it', \Friendica\Core\Config\ValueObject\Cache::SOURCE_DATA); $configCache->set('system', 'test', 'it', Cache::SOURCE_DATA);
$configCache->set('config', 'test', 'it', \Friendica\Core\Config\ValueObject\Cache::SOURCE_DATA); $configCache->set('config', 'test', 'it', Cache::SOURCE_DATA);
$configCache->set('system', 'test_2', 2, \Friendica\Core\Config\ValueObject\Cache::SOURCE_DATA); $configCache->set('system', 'test_2', 2, Cache::SOURCE_DATA);
$configFileLoader->saveData($configCache); $configFileLoader->saveData($configCache);
// Reload the configCache with the new values // Reload the configCache with the new values
$configCache2 = new \Friendica\Core\Config\ValueObject\Cache(); $configCache2 = new Cache();
$configFileLoader->setupCache($configCache2); $configFileLoader->setupCache($configCache2);
self::assertEquals($configCache, $configCache2); self::assertEquals($configCache, $configCache2);
@ -425,6 +425,6 @@ class ConfigFileLoaderTest extends MockedTest
], ],
'config' => [ 'config' => [
'test' => 'it' 'test' => 'it'
]], $configCache2->getDataBySource(\Friendica\Core\Config\ValueObject\Cache::SOURCE_DATA)); ]], $configCache2->getDataBySource(Cache::SOURCE_DATA));
} }
} }

View File

@ -0,0 +1,110 @@
<?php
namespace Friendica\Test\src\Core\Config;
use Friendica\Core\Config\Capability\ISetConfigValuesTransactional;
use Friendica\Core\Config\Model\Config;
use Friendica\Core\Config\Model\TransactionalConfig;
use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Test\MockedTest;
use Friendica\Test\Util\VFSTrait;
class TransactionalConfigTest extends MockedTest
{
use VFSTrait;
/** @var ConfigFileManager */
protected $configFileManager;
protected function setUp(): void
{
parent::setUp();
$this->setUpVfsDir();
$this->configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/');
}
public function dataTests(): array
{
return [
'default' => [
'data' => include dirname(__FILE__, 4) . '/datasets/B.node.config.php',
]
];
}
public function testInstance()
{
$config = new Config($this->configFileManager, new Cache());
$transactionalConfig = new TransactionalConfig($config);
self::assertInstanceOf(ISetConfigValuesTransactional::class, $transactionalConfig);
self::assertInstanceOf(TransactionalConfig::class, $transactionalConfig);
}
public function testTransactionalConfig()
{
$config = new Config($this->configFileManager, new Cache());
$config->set('config', 'key1', 'value1');
$config->set('system', 'key2', 'value2');
$config->set('system', 'keyDel', 'valueDel');
$config->set('delete', 'keyDel', 'catDel');
$transactionalConfig = new TransactionalConfig($config);
self::assertEquals('value1', $transactionalConfig->get('config', 'key1'));
self::assertEquals('value2', $transactionalConfig->get('system', 'key2'));
self::assertEquals('valueDel', $transactionalConfig->get('system', 'keyDel'));
self::assertEquals('catDel', $transactionalConfig->get('delete', 'keyDel'));
// the config file knows it as well immediately
$tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE;
self::assertEquals('value1', $tempData['config']['key1'] ?? null);
self::assertEquals('value2', $tempData['system']['key2'] ?? null);
// new key-value
$transactionalConfig->set('transaction', 'key3', 'value3');
// overwrite key-value
$transactionalConfig->set('config', 'key1', 'changedValue1');
// delete key-value
$transactionalConfig->delete('system', 'keyDel');
// delete last key of category - so the category is gone
$transactionalConfig->delete('delete', 'keyDel');
// The main config still doesn't know about the change
self::assertNull($config->get('transaction', 'key3'));
self::assertEquals('value1', $config->get('config', 'key1'));
self::assertEquals('valueDel', $config->get('system', 'keyDel'));
self::assertEquals('catDel', $config->get('delete', 'keyDel'));
// but the transaction config of course knows it
self::assertEquals('value3', $transactionalConfig->get('transaction', 'key3'));
self::assertEquals('changedValue1', $transactionalConfig->get('config', 'key1'));
self::assertNull($transactionalConfig->get('system', 'keyDel'));
self::assertNull($transactionalConfig->get('delete', 'keyDel'));
// The config file still doesn't know it either
$tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE;
self::assertEquals('value1', $tempData['config']['key1'] ?? null);
self::assertEquals('value2', $tempData['system']['key2'] ?? null);
self::assertEquals('catDel', $tempData['delete']['keyDel'] ?? null);
self::assertNull($tempData['transaction']['key3'] ?? null);
// save it back!
$transactionalConfig->save();
// Now every config and file knows the change
self::assertEquals('changedValue1', $config->get('config', 'key1'));
self::assertEquals('value3', $config->get('transaction', 'key3'));
self::assertNull($config->get('system', 'keyDel'));
self::assertNull($config->get('delete', 'keyDel'));
self::assertEquals('value3', $transactionalConfig->get('transaction', 'key3'));
self::assertEquals('changedValue1', $transactionalConfig->get('config', 'key1'));
self::assertNull($transactionalConfig->get('system', 'keyDel'));
$tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE;
self::assertEquals('changedValue1', $tempData['config']['key1'] ?? null);
self::assertEquals('value2', $tempData['system']['key2'] ?? null);
self::assertEquals('value3', $tempData['transaction']['key3'] ?? null);
self::assertNull($tempData['system']['keyDel'] ?? null);
self::assertNull($tempData['delete']['keyDel'] ?? null);
// the whole category should be gone
self::assertNull($tempData['delete'] ?? null);
}
}

View File

@ -1184,11 +1184,13 @@ function update_1508()
{ {
$config = DBA::selectToArray('config'); $config = DBA::selectToArray('config');
$newConfig = DI::config()->transactional();
foreach ($config as $entry) { foreach ($config as $entry) {
DI::config()->set($entry['cat'], $entry['k'], $entry['v'], false); $newConfig->set($entry['cat'], $entry['k'], $entry['v']);
} }
DI::config()->save(); $newConfig->save();
DBA::e("DELETE FROM `config`"); DBA::e("DELETE FROM `config`");
} }