Dynamic config loading

- Move settings, defaults and dbstructure to directory 'static'
- Dynamic loading of config files (after the static loading)
- Filter out '-sample.config.php' and '-sample.ini.php' files
- Remove unnecessary ConfigFileManager
- Move ConfigFileLoader to Utils
- Add tests for multi-loading for INI, config and sample-filtering
This commit is contained in:
Philipp Holzer 2019-06-23 19:56:21 +02:00
parent 966043712f
commit 92fb0a82ca
No known key found for this signature in database
GPG key ID: D8365C3D36B77D90
25 changed files with 325 additions and 161 deletions

View file

@ -12,7 +12,7 @@
* *
* Then set the following for your MySQL installation * Then set the following for your MySQL installation
* *
* If you're unsure about what any of the config keys below do, please check the config/defaults.config.php file for * If you're unsure about what any of the config keys below do, please check the static/defaults.config.php file for
* detailed documentation of their data type and behavior. * detailed documentation of their data type and behavior.
*/ */

View file

@ -33,15 +33,24 @@ return [
### Configuration location ### Configuration location
The `config` directory holds key configuration files: The `config` directory holds key configuration files and can have different config files.
All of them have to end with `.config.php` and must not include `-sample` in their name.
- `defaults.config.php` holds the default values for all the configuration keys that can only be set in `local.config.php`. Some examples of common known configuration files:
- `settings.config.php` holds the default values for some configuration keys that are set through the admin settings page.
- `local.config.php` holds the current node custom configuration. - `local.config.php` holds the current node custom configuration.
- `addon.config.php` is optional and holds the custom configuration for specific addons. - `addon.config.php` is optional and holds the custom configuration for specific addons.
Addons can define their own default configuration values in `addon/[addon]/config/[addon].config.php` which is loaded when the addon is activated. Addons can define their own default configuration values in `addon/[addon]/config/[addon].config.php` which is loaded when the addon is activated.
### Static Configuration location
The `static` directory holds the codebase default configurations files.
They must not be changed by users, because they can get changed from release to release.
Currently, the following configurations are included:
- `defaults.config.php` holds the default values for all the configuration keys that can only be set in `local.config.php`.
- `settings.config.php` holds the default values for some configuration keys that are set through the admin settings page.
#### Migrating from .htconfig.php to config/local.config.php #### Migrating from .htconfig.php to config/local.config.php
The legacy `.htconfig.php` configuration file is still supported, but is deprecated and will be removed in a subsequent Friendica release. The legacy `.htconfig.php` configuration file is still supported, but is deprecated and will be removed in a subsequent Friendica release.
@ -292,7 +301,7 @@ Or it is for testing purposes only.
**Attention:** Please be warned that you shouldn't use one of these values without the knowledge what it could trigger. **Attention:** Please be warned that you shouldn't use one of these values without the knowledge what it could trigger.
Especially don't do that with undocumented values. Especially don't do that with undocumented values.
These configurations keys and their default value are listed in `config/defaults.config.php` and should be overwritten in `config/local.config.php`. These configurations keys and their default value are listed in `static/defaults.config.php` and should be overwritten in `config/local.config.php`.
## Administrator Options ## Administrator Options

View file

@ -17,7 +17,7 @@ use Friendica\Database\DBA;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\BaseURL; use Friendica\Util\BaseURL;
use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\ConfigFileLoader;
use Friendica\Util\HTTPSignature; use Friendica\Util\HTTPSignature;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Strings; use Friendica\Util\Strings;
@ -360,9 +360,6 @@ class App
$this->getMode()->determine($this->getBasePath()); $this->getMode()->determine($this->getBasePath());
if ($this->getMode()->has(App\Mode::DBAVAILABLE)) { if ($this->getMode()->has(App\Mode::DBAVAILABLE)) {
$loader = new ConfigFileLoader($this->getBasePath(), $this->getMode());
$this->config->getCache()->load($loader->loadCoreConfig('addon'), true);
$this->profiler->update( $this->profiler->update(
$this->config->get('system', 'profiler', false), $this->config->get('system', 'profiler', false),
$this->config->get('rendertime', 'callstack', false)); $this->config->get('rendertime', 'callstack', false));

View file

@ -9,7 +9,7 @@ use Friendica\Core\Installer;
use Friendica\Core\Theme; use Friendica\Core\Theme;
use Friendica\Util\BasePath; use Friendica\Util\BasePath;
use Friendica\Util\BaseURL; use Friendica\Util\BaseURL;
use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\ConfigFileLoader;
use RuntimeException; use RuntimeException;
class AutomaticInstallation extends Console class AutomaticInstallation extends Console

View file

@ -45,7 +45,7 @@ abstract class Configuration
/** /**
* @brief Loads all configuration values of family into a cached storage. * @brief Loads all configuration values of family into a cached storage.
* *
* All configuration values of the system are stored in the cache ( @see IConfigCache ) * All configuration values of the system are stored in the cache ( @see ConfigCache )
* *
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* *
@ -59,7 +59,7 @@ abstract class Configuration
* *
* Get a particular config value from the given category ($cat) * Get a particular config value from the given category ($cat)
* and the $key from a cached storage either from the $this->configAdapter * and the $key from a cached storage either from the $this->configAdapter
* (@see IConfigAdapter ) or from the $this->configCache (@see IConfigCache ). * (@see IConfigAdapter ) or from the $this->configCache (@see ConfigCache ).
* *
* @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 query * @param string $key The configuration key to query

View file

@ -96,7 +96,7 @@ class DBStructure
* Loads the database structure definition from the config/dbstructure.config.php file. * Loads the database structure definition from the config/dbstructure.config.php file.
* On first pass, defines DB_UPDATE_VERSION constant. * On first pass, defines DB_UPDATE_VERSION constant.
* *
* @see config/dbstructure.config.php * @see static/dbstructure.config.php
* @param boolean $with_addons_structure Whether to tack on addons additional tables * @param boolean $with_addons_structure Whether to tack on addons additional tables
* @param string $basePath The base path of this application * @param string $basePath The base path of this application
* @return array * @return array
@ -106,16 +106,16 @@ class DBStructure
{ {
if (!self::$definition) { if (!self::$definition) {
$filename = $basePath . '/config/dbstructure.config.php'; $filename = $basePath . '/static/dbstructure.config.php';
if (!is_readable($filename)) { if (!is_readable($filename)) {
throw new Exception('Missing database structure config file config/dbstructure.config.php'); throw new Exception('Missing database structure config file static/dbstructure.config.php');
} }
$definition = require $filename; $definition = require $filename;
if (!$definition) { if (!$definition) {
throw new Exception('Corrupted database structure config file config/dbstructure.config.php'); throw new Exception('Corrupted database structure config file static/dbstructure.config.php');
} }
self::$definition = $definition; self::$definition = $definition;

View file

@ -5,9 +5,9 @@ namespace Friendica\Factory;
use Friendica\Core; use Friendica\Core;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\Config\Cache; use Friendica\Core\Config\Cache;
use Friendica\Util\ConfigFileLoader;
use Friendica\Model\Config\Config as ConfigModel; use Friendica\Model\Config\Config as ConfigModel;
use Friendica\Model\Config\PConfig as PConfigModel; use Friendica\Model\Config\PConfig as PConfigModel;
use Friendica\Util\Config\ConfigFileLoader;
class ConfigFactory class ConfigFactory
{ {

View file

@ -7,7 +7,7 @@ use Friendica\Core\Config\Cache\PConfigCache;
use Friendica\Factory; use Friendica\Factory;
use Friendica\Util\BasePath; use Friendica\Util\BasePath;
use Friendica\Util\BaseURL; use Friendica\Util\BaseURL;
use Friendica\Util\Config; use Friendica\Util\ConfigFileLoader;
class DependencyFactory class DependencyFactory
{ {
@ -27,7 +27,7 @@ class DependencyFactory
$basePath = BasePath::create($directory, $_SERVER); $basePath = BasePath::create($directory, $_SERVER);
$mode = new App\Mode($basePath); $mode = new App\Mode($basePath);
$router = new App\Router(); $router = new App\Router();
$configLoader = new Config\ConfigFileLoader($basePath, $mode); $configLoader = new ConfigFileLoader($basePath, $mode);
$configCache = Factory\ConfigFactory::createCache($configLoader); $configCache = Factory\ConfigFactory::createCache($configLoader);
$profiler = Factory\ProfilerFactory::create($configCache); $profiler = Factory\ProfilerFactory::create($configCache);
$database = Factory\DBFactory::init($configCache, $profiler, $_SERVER); $database = Factory\DBFactory::init($configCache, $profiler, $_SERVER);

View file

@ -12,7 +12,7 @@ use Friendica\Database\DBA;
use Friendica\Database\DBStructure; use Friendica\Database\DBStructure;
use Friendica\Model\Register; use Friendica\Model\Register;
use Friendica\Module\BaseAdminModule; use Friendica\Module\BaseAdminModule;
use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\ConfigFileLoader;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network; use Friendica\Util\Network;

View file

@ -1,90 +0,0 @@
<?php
namespace Friendica\Util\Config;
/**
* An abstract class in case of handling with config files
*/
abstract class ConfigFileManager
{
/**
* The Sub directory of the config-files
* @var string
*/
const SUBDIRECTORY = 'config';
/**
* The default name of the user defined config file
* @var string
*/
const CONFIG_LOCAL = 'local';
/**
* 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';
protected $baseDir;
protected $configDir;
/**
* @param string $baseDir The base directory of Friendica
*/
public function __construct($baseDir)
{
$this->baseDir = $baseDir;
$this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::SUBDIRECTORY;
}
/**
* Gets the full name (including the path) for a *.config.php (default is local.config.php)
*
* @param string $name The config name (default is empty, which means local.config.php)
*
* @return string The full name or empty if not found
*/
protected function getConfigFullName($name = '')
{
$name = !empty($name) ? $name : self::CONFIG_LOCAL;
$fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php';
return file_exists($fullName) ? $fullName : '';
}
/**
* Gets the full name (including the path) for a *.ini.php (default is local.ini.php)
*
* @param string $name The config name (default is empty, which means local.ini.php)
*
* @return string The full name or empty if not found
*/
protected function getIniFullName($name = '')
{
$name = !empty($name) ? $name : self::CONFIG_INI;
$fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php';
return file_exists($fullName) ? $fullName : '';
}
/**
* Gets the full name (including the path) for a .*.php (default is .htconfig.php)
*
* @param string $name The config name (default is empty, which means .htconfig.php)
*
* @return string The full name or empty if not found
*/
protected function getHtConfigFullName($name = '')
{
$name = !empty($name) ? $name : self::CONFIG_HTCONFIG;
$fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php';
return file_exists($fullName) ? $fullName : '';
}
}

View file

@ -1,7 +1,8 @@
<?php <?php
namespace Friendica\Util\Config; namespace Friendica\Util;
use Exception;
use Friendica\App; use Friendica\App;
use Friendica\Core\Addon; use Friendica\Core\Addon;
use Friendica\Core\Config\Cache\ConfigCache; use Friendica\Core\Config\Cache\ConfigCache;
@ -14,16 +15,65 @@ use Friendica\Core\Config\Cache\ConfigCache;
* - *.ini.php (deprecated) * - *.ini.php (deprecated)
* - *.htconfig.php (deprecated) * - *.htconfig.php (deprecated)
*/ */
class ConfigFileLoader extends ConfigFileManager class ConfigFileLoader
{ {
/**
* The Sub directory of the config-files
*
* @var string
*/
const CONFIG_DIR = 'config';
/**
* The Sub directory of the static config-files
*
* @var string
*/
const STATIC_DIR = 'static';
/**
* 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 App\Mode * @var App\Mode
*/ */
private $appMode; private $appMode;
/**
* @var string
*/
private $baseDir;
/**
* @var string
*/
private $configDir;
/**
* @var string
*/
private $staticDir;
public function __construct($baseDir, App\Mode $mode) public function __construct($baseDir, App\Mode $mode)
{ {
parent::__construct($baseDir); $this->baseDir = $baseDir;
$this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::CONFIG_DIR;
$this->staticDir = $baseDir . DIRECTORY_SEPARATOR . self::STATIC_DIR;
$this->appMode = $mode; $this->appMode = $mode;
} }
@ -36,17 +86,20 @@ class ConfigFileLoader extends ConfigFileManager
* @param ConfigCache $config The config cache to load to * @param ConfigCache $config The config cache to load to
* @param bool $raw Setup the raw config format * @param bool $raw Setup the raw config format
* *
* @throws \Exception * @throws Exception
*/ */
public function setupCache(ConfigCache $config, $raw = false) public function setupCache(ConfigCache $config, $raw = false)
{ {
$config->load($this->loadCoreConfig('defaults')); // Load static config files first, the order is important
$config->load($this->loadCoreConfig('settings')); $config->load($this->loadStaticConfig('defaults'));
$config->load($this->loadStaticConfig('settings'));
// try to load the legacy config first
$config->load($this->loadLegacyConfig('htpreconfig'), true); $config->load($this->loadLegacyConfig('htpreconfig'), true);
$config->load($this->loadLegacyConfig('htconfig'), true); $config->load($this->loadLegacyConfig('htconfig'), true);
$config->load($this->loadCoreConfig('local'), true); // Now load every other config you find inside the 'config/' directory
$this->loadCoreConfig($config);
// In case of install mode, add the found basepath (because there isn't a basepath set yet // In case of install mode, add the found basepath (because there isn't a basepath set yet
if (!$raw && ($this->appMode->isInstall() || empty($config->get('system', 'basepath')))) { if (!$raw && ($this->appMode->isInstall() || empty($config->get('system', 'basepath')))) {
@ -56,25 +109,52 @@ class ConfigFileLoader extends ConfigFileManager
} }
/** /**
* Tries to load the specified core-configuration and returns the config array. * Tries to load the static core-configuration and returns the config array.
* *
* @param string $name The name of the configuration (default is empty, which means 'local') * @param string $name The name of the configuration
* *
* @return array The config array (empty if no config found) * @return array The config array (empty if no config found)
* *
* @throws \Exception if the configuration file isn't readable * @throws Exception if the configuration file isn't readable
*/ */
public function loadCoreConfig($name = '') private function loadStaticConfig($name)
{ {
if (!empty($this->getConfigFullName($name))) { $configName = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.config.php';
return $this->loadConfigFile($this->getConfigFullName($name)); $iniName = $this->staticDir . DIRECTORY_SEPARATOR . $name . '.ini.php';
} elseif (!empty($this->getIniFullName($name))) {
return $this->loadINIConfigFile($this->getIniFullName($name)); if (file_exists($configName)) {
return $this->loadConfigFile($configName);
} elseif (file_exists($iniName)) {
return $this->loadINIConfigFile($iniName);
} else { } else {
return []; return [];
} }
} }
/**
* Tries to load the specified core-configuration into the config cache.
*
* @param ConfigCache $config The Config cache
*
* @return array The config array (empty if no config found)
*
* @throws Exception if the configuration file isn't readable
*/
private function loadCoreConfig(ConfigCache $config)
{
// try to load legacy ini-files first
foreach ($this->getConfigFiles(true) as $configFile) {
$config->load($this->loadINIConfigFile($configFile), true);
}
// try to load supported config at last to overwrite it
foreach ($this->getConfigFiles() as $configFile) {
$config->load($this->loadConfigFile($configFile), true);
}
return [];
}
/** /**
* Tries to load the specified addon-configuration and returns the config array. * Tries to load the specified addon-configuration and returns the config array.
* *
@ -82,14 +162,14 @@ class ConfigFileLoader extends ConfigFileManager
* *
* @return array The config array (empty if no config found) * @return array The config array (empty if no config found)
* *
* @throws \Exception if the configuration file isn't readable * @throws Exception if the configuration file isn't readable
*/ */
public function loadAddonConfig($name) public function loadAddonConfig($name)
{ {
$filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/ $filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/
Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/ Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/
$name . DIRECTORY_SEPARATOR . // openstreetmap/ $name . DIRECTORY_SEPARATOR . // openstreetmap/
self::SUBDIRECTORY . DIRECTORY_SEPARATOR . // config/ self::CONFIG_DIR . DIRECTORY_SEPARATOR . // config/
$name . ".config.php"; // openstreetmap.config.php $name . ".config.php"; // openstreetmap.config.php
if (file_exists($filepath)) { if (file_exists($filepath)) {
@ -99,6 +179,32 @@ class ConfigFileLoader extends ConfigFileManager
} }
} }
/**
* 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)
{
$files = scandir($this->configDir);
$found = array();
$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. * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
* *
@ -110,11 +216,14 @@ class ConfigFileLoader extends ConfigFileManager
*/ */
private function loadLegacyConfig($name = '') private function loadLegacyConfig($name = '')
{ {
$name = !empty($name) ? $name : self::CONFIG_HTCONFIG;
$fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php';
$config = []; $config = [];
if (!empty($this->getHtConfigFullName($name))) { if (file_exists($fullName)) {
$a = new \stdClass(); $a = new \stdClass();
$a->config = []; $a->config = [];
include $this->getHtConfigFullName($name); include $fullName;
$htConfigCategories = array_keys($a->config); $htConfigCategories = array_keys($a->config);
@ -172,11 +281,11 @@ class ConfigFileLoader extends ConfigFileManager
/** /**
* Tries to load the specified legacy configuration file and returns the config array. * Tries to load the specified legacy configuration file and returns the config array.
* *
* @deprecated since version 2018.12
* @param string $filepath * @param string $filepath
* *
* @return array The configuration array * @return array The configuration array
* @throws \Exception * @throws Exception
* @deprecated since version 2018.12
*/ */
private function loadINIConfigFile($filepath) private function loadINIConfigFile($filepath)
{ {
@ -185,7 +294,7 @@ class ConfigFileLoader extends ConfigFileManager
$config = parse_ini_string($contents, true, INI_SCANNER_TYPED); $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
if ($config === false) { if ($config === false) {
throw new \Exception('Error parsing INI config file ' . $filepath); throw new Exception('Error parsing INI config file ' . $filepath);
} }
return $config; return $config;
@ -203,16 +312,17 @@ class ConfigFileLoader extends ConfigFileManager
* ]; * ];
* *
* @param string $filepath The filepath of the * @param string $filepath The filepath of the
*
* @return array The config array0 * @return array The config array0
* *
* @throws \Exception if the config cannot get loaded. * @throws Exception if the config cannot get loaded.
*/ */
private function loadConfigFile($filepath) private function loadConfigFile($filepath)
{ {
$config = include($filepath); $config = include($filepath);
if (!is_array($config)) { if (!is_array($config)) {
throw new \Exception('Error loading config file ' . $filepath); throw new Exception('Error loading config file ' . $filepath);
} }
return $config; return $config;

View file

@ -6,14 +6,13 @@
namespace Friendica\Test; namespace Friendica\Test;
use Friendica\App\Mode; use Friendica\App\Mode;
use Friendica\App\Router;
use Friendica\Core\Config\Cache\ConfigCache; use Friendica\Core\Config\Cache\ConfigCache;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Factory\ConfigFactory; use Friendica\Factory\ConfigFactory;
use Friendica\Factory\DBFactory; use Friendica\Factory\DBFactory;
use Friendica\Factory\ProfilerFactory; use Friendica\Factory\ProfilerFactory;
use Friendica\Util\BasePath; use Friendica\Util\BasePath;
use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\ConfigFileLoader;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use PHPUnit\DbUnit\DataSet\YamlDataSet; use PHPUnit\DbUnit\DataSet\YamlDataSet;
use PHPUnit\DbUnit\TestCaseTrait; use PHPUnit\DbUnit\TestCaseTrait;

View file

@ -21,33 +21,34 @@ trait VFSTrait
$structure = [ $structure = [
'config' => [], 'config' => [],
'bin' => [], 'bin' => [],
'test' => [] 'static' => [],
'test' => [],
]; ];
// create a virtual directory and copy all needed files and folders to it // create a virtual directory and copy all needed files and folders to it
$this->root = vfsStream::setup('friendica', 0777, $structure); $this->root = vfsStream::setup('friendica', 0777, $structure);
$this->setConfigFile('defaults.config.php'); $this->setConfigFile('defaults.config.php', true);
$this->setConfigFile('settings.config.php'); $this->setConfigFile('settings.config.php', true);
$this->setConfigFile('local.config.php'); $this->setConfigFile('local.config.php');
$this->setConfigFile('dbstructure.config.php');
} }
/** /**
* Copying a config file from the file system to the Virtual File System * Copying a config file from the file system to the Virtual File System
* *
* @param string $filename The filename of the config file * @param string $filename The filename of the config file
* @param bool $static True, if the folder `static` instead of `config` should be used
*/ */
protected function setConfigFile($filename) protected function setConfigFile($filename, bool $static = false)
{ {
$file = dirname(__DIR__) . DIRECTORY_SEPARATOR . $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR . ($static ? 'static' : 'config') . DIRECTORY_SEPARATOR .
$filename; $filename;
if (file_exists($file)) { if (file_exists($file)) {
vfsStream::newFile($filename) vfsStream::newFile($filename)
->at($this->root->getChild('config')) ->at($this->root->getChild(($static ? 'static' : 'config')))
->setContent(file_get_contents($file)); ->setContent(file_get_contents($file));
} }
} }
@ -56,11 +57,12 @@ trait VFSTrait
* Delets a config file from the Virtual File System * Delets a config file from the Virtual File System
* *
* @param string $filename The filename of the config file * @param string $filename The filename of the config file
* @param bool $static True, if the folder `static` instead of `config` should be used
*/ */
protected function delConfigFile($filename) protected function delConfigFile($filename, bool $static = false)
{ {
if ($this->root->hasChild('config/' . $filename)) { if ($this->root->hasChild(($static ? 'static' : 'config') . '/' . $filename)) {
$this->root->getChild('config')->removeChild($filename); $this->root->getChild(($static ? 'static' : 'config'))->removeChild($filename);
} }
} }
} }

View file

@ -0,0 +1,29 @@
<?php
/**
* A test file for local configuration
*
*/
return [
'database' => [
'hostname' => 'testhost',
'username' => 'testuser',
'password' => 'testpw',
'database' => 'testdb',
'charset' => 'utf8mb4',
],
'config' => [
'admin_email' => 'admin@overwritten.local',
'sitename' => 'Friendica Social Network',
'register_policy' => \Friendica\Module\Register::OPEN,
'register_text' => '',
],
'system' => [
'default_timezone' => 'UTC',
'language' => 'en',
'theme' => 'frio',
'newKey' => 'newValue',
],
];

View file

@ -0,0 +1,20 @@
<?php
/**
* A test local ini file
*/
return <<<INI
[database]
hostname = testhost
username = testuser
password = testpw
database = testdb
[system]
theme = changed
newKey = newValue
[config]
admin_email = admin@overwritten.local
INI;

View file

@ -14,6 +14,7 @@ use Friendica\Core\System;
use Friendica\Factory; use Friendica\Factory;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\BaseURL; use Friendica\Util\BaseURL;
use Friendica\Util\ConfigFileLoader;
use Monolog\Handler\TestHandler; use Monolog\Handler\TestHandler;
require_once __DIR__ . '/../../include/api.php'; require_once __DIR__ . '/../../include/api.php';

View file

@ -392,7 +392,7 @@ FIN;
// Local configuration // Local configuration
// If you're unsure about what any of the config keys below do, please check the config/defaults.config.php for detailed // If you're unsure about what any of the config keys below do, please check the static/defaults.config.php for detailed
// documentation of their data type and behavior. // documentation of their data type and behavior.
return [ return [

View file

@ -6,7 +6,7 @@ use Friendica\App;
use Friendica\Core\Config\Cache\ConfigCache; use Friendica\Core\Config\Cache\ConfigCache;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Test\Util\VFSTrait; use Friendica\Test\Util\VFSTrait;
use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\ConfigFileLoader;
use Mockery\MockInterface; use Mockery\MockInterface;
use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStream;
@ -73,7 +73,7 @@ class ConfigFileLoaderTest extends MockedTest
'..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR .
'local.config.php'; 'A.config.php';
vfsStream::newFile('local.config.php') vfsStream::newFile('local.config.php')
->at($this->root->getChild('config')) ->at($this->root->getChild('config'))
@ -105,7 +105,7 @@ class ConfigFileLoaderTest extends MockedTest
'..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR .
'local.ini.php'; 'A.ini.php';
vfsStream::newFile('local.ini.php') vfsStream::newFile('local.ini.php')
->at($this->root->getChild('config')) ->at($this->root->getChild('config'))
@ -185,7 +185,7 @@ class ConfigFileLoaderTest extends MockedTest
'..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR .
'local.config.php'; 'A.config.php';
vfsStream::newFile('test.config.php') vfsStream::newFile('test.config.php')
->at($this->root->getChild('addon')->getChild('test')->getChild('config')) ->at($this->root->getChild('addon')->getChild('test')->getChild('config'))
@ -202,4 +202,91 @@ class ConfigFileLoaderTest extends MockedTest
$this->assertEquals('admin@test.it', $conf['config']['admin_email']); $this->assertEquals('admin@test.it', $conf['config']['admin_email']);
} }
/**
* test loading multiple config files - the last config should work
*/
public function testLoadMultipleConfigs()
{
$this->delConfigFile('local.config.php');
$fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR;
vfsStream::newFile('A.config.php')
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'A.config.php'));
vfsStream::newFile('B.config.php')
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'B.config.php'));
$configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
$configCache = new ConfigCache();
$configFileLoader->setupCache($configCache);
$this->assertEquals('admin@overwritten.local', $configCache->get('config', 'admin_email'));
$this->assertEquals('newValue', $configCache->get('system', 'newKey'));
}
/**
* test loading multiple config files - the last config should work (INI-version)
*/
public function testLoadMultipleInis()
{
$this->delConfigFile('local.config.php');
$fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR;
vfsStream::newFile('A.ini.php')
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'A.ini.php'));
vfsStream::newFile('B.ini.php')
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'B.ini.php'));
$configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
$configCache = new ConfigCache();
$configFileLoader->setupCache($configCache);
$this->assertEquals('admin@overwritten.local', $configCache->get('config', 'admin_email'));
$this->assertEquals('newValue', $configCache->get('system', 'newKey'));
}
/**
* Test that sample-files (e.g. local-sample.config.php) is never loaded
*/
public function testNotLoadingSamples()
{
$this->delConfigFile('local.config.php');
$fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR;
vfsStream::newFile('A.ini.php')
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'A.ini.php'));
vfsStream::newFile('B-sample.ini.php')
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'B.ini.php'));
$configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
$configCache = new ConfigCache();
$configFileLoader->setupCache($configCache);
$this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
$this->assertEmpty($configCache->get('system', 'NewKey'));
}
} }

View file

@ -22,7 +22,7 @@ use Friendica\Worker\Delivery;
* This function is responsible for doing post update changes to the data * This function is responsible for doing post update changes to the data
* (not the structure) in the database. * (not the structure) in the database.
* *
* Database structure changes are done in config/dbstructure.config.php * Database structure changes are done in static/dbstructure.config.php
* *
* If there is a need for a post process to a structure change, update this file * If there is a need for a post process to a structure change, update this file
* by adding a new function at the end with the number of the new DB_UPDATE_VERSION. * by adding a new function at the end with the number of the new DB_UPDATE_VERSION.
@ -33,8 +33,8 @@ use Friendica\Worker\Delivery;
* You are currently on version 4711 and you are preparing changes that demand an update script. * You are currently on version 4711 and you are preparing changes that demand an update script.
* *
* 1. Create a function "update_4712()" here in the update.php * 1. Create a function "update_4712()" here in the update.php
* 2. Apply the needed structural changes in config/dbStructure.php * 2. Apply the needed structural changes in static/dbStructure.php
* 3. Set DB_UPDATE_VERSION in config/dbstructure.config.php to 4712. * 3. Set DB_UPDATE_VERSION in static/dbstructure.config.php to 4712.
* *
* If you need to run a script before the database update, name the function "pre_update_4712()" * If you need to run a script before the database update, name the function "pre_update_4712()"
*/ */

View file

@ -2,7 +2,7 @@
// Local configuration // Local configuration
// If you're unsure about what any of the config keys below do, please check the config/defaults.config.php for detailed // If you're unsure about what any of the config keys below do, please check the static/defaults.config.php for detailed
// documentation of their data type and behavior. // documentation of their data type and behavior.
return [ return [