Browse Source

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
pull/7313/head
Philipp Holzer 2 years ago
parent
commit
92fb0a82ca
No known key found for this signature in database GPG Key ID: D8365C3D36B77D90
25 changed files with 325 additions and 161 deletions
  1. +1
    -1
      config/local-sample.config.php
  2. +13
    -4
      doc/Config.md
  3. +1
    -4
      src/App.php
  4. +1
    -1
      src/Console/AutomaticInstallation.php
  5. +2
    -2
      src/Core/Config/Configuration.php
  6. +4
    -4
      src/Database/DBStructure.php
  7. +1
    -1
      src/Factory/ConfigFactory.php
  8. +2
    -2
      src/Factory/DependencyFactory.php
  9. +1
    -1
      src/Module/Admin/Summary.php
  10. +0
    -90
      src/Util/Config/ConfigFileManager.php
  11. +140
    -30
      src/Util/ConfigFileLoader.php
  12. +0
    -0
      static/dbstructure.config.php
  13. +0
    -0
      static/defaults.config.php
  14. +0
    -0
      static/settings.config.php
  15. +1
    -2
      tests/DatabaseTest.php
  16. +12
    -10
      tests/Util/VFSTrait.php
  17. +0
    -0
      tests/datasets/config/A.config.php
  18. +0
    -0
      tests/datasets/config/A.ini.php
  19. +29
    -0
      tests/datasets/config/B.config.php
  20. +20
    -0
      tests/datasets/config/B.ini.php
  21. +1
    -0
      tests/include/ApiTest.php
  22. +1
    -1
      tests/src/Console/AutomaticInstallationConsoleTest.php
  23. +91
    -4
      tests/src/Util/Config/ConfigFileLoaderTest.php
  24. +3
    -3
      update.php
  25. +1
    -1
      view/templates/local.config.tpl

+ 1
- 1
config/local-sample.config.php View File

@ -12,7 +12,7 @@
*
* 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.
*/


+ 13
- 4
doc/Config.md View File

@ -33,15 +33,24 @@ return [
### 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`.
- `settings.config.php` holds the default values for some configuration keys that are set through the admin settings page.
Some examples of common known configuration files:
- `local.config.php` holds the current node custom configuration.
- `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.
### 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
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.
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


+ 1
- 4
src/App.php View File

@ -17,7 +17,7 @@ use Friendica\Database\DBA;
use Friendica\Model\Profile;
use Friendica\Network\HTTPException;
use Friendica\Util\BaseURL;
use Friendica\Util\Config\ConfigFileLoader;
use Friendica\Util\ConfigFileLoader;
use Friendica\Util\HTTPSignature;
use Friendica\Util\Profiler;
use Friendica\Util\Strings;
@ -360,9 +360,6 @@ class App
$this->getMode()->determine($this->getBasePath());
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->config->get('system', 'profiler', false),
$this->config->get('rendertime', 'callstack', false));


+ 1
- 1
src/Console/AutomaticInstallation.php View File

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


+ 2
- 2
src/Core/Config/Configuration.php View File

@ -45,7 +45,7 @@ abstract class Configuration
/**
* @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
*
@ -59,7 +59,7 @@ abstract class Configuration
*
* Get a particular config value from the given category ($cat)
* 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 $key The configuration key to query


+ 4
- 4
src/Database/DBStructure.php View File

@ -96,7 +96,7 @@ class DBStructure
* Loads the database structure definition from the config/dbstructure.config.php file.
* 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 string $basePath The base path of this application
* @return array
@ -106,16 +106,16 @@ class DBStructure
{
if (!self::$definition) {
$filename = $basePath . '/config/dbstructure.config.php';
$filename = $basePath . '/static/dbstructure.config.php';
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;
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;


+ 1
- 1
src/Factory/ConfigFactory.php View File

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


+ 2
- 2
src/Factory/DependencyFactory.php View File

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


+ 1
- 1
src/Module/Admin/Summary.php View File

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


+ 0
- 90
src/Util/Config/ConfigFileManager.php 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 : '';
}
}

src/Util/Config/ConfigFileLoader.php → src/Util/ConfigFileLoader.php View File


config/dbstructure.config.php → static/dbstructure.config.php View File


config/defaults.config.php → static/defaults.config.php View File


config/settings.config.php → static/settings.config.php View File


+ 1
- 2
tests/DatabaseTest.php View File

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


+ 12
- 10
tests/Util/VFSTrait.php View File

@ -21,33 +21,34 @@ trait VFSTrait
$structure = [
'config' => [],
'bin' => [],
'test' => []
'static' => [],
'test' => [],
];
// create a virtual directory and copy all needed files and folders to it
$this->root = vfsStream::setup('friendica', 0777, $structure);
$this->setConfigFile('defaults.config.php');
$this->setConfigFile('settings.config.php');
$this->setConfigFile('defaults.config.php', true);
$this->setConfigFile('settings.config.php', true);
$this->setConfigFile('local.config.php');
$this->setConfigFile('dbstructure.config.php');
}
/**
* Copying a config file from the file system to the Virtual File System
*
* @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 .
'..' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR .
($static ? 'static' : 'config') . DIRECTORY_SEPARATOR .
$filename;
if (file_exists($file)) {
vfsStream::newFile($filename)
->at($this->root->getChild('config'))
->at($this->root->getChild(($static ? 'static' : 'config')))
->setContent(file_get_contents($file));
}
}
@ -56,11 +57,12 @@ trait VFSTrait
* Delets a config file from the Virtual File System
*
* @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)) {
$this->root->getChild('config')->removeChild($filename);
if ($this->root->hasChild(($static ? 'static' : 'config') . '/' . $filename)) {
$this->root->getChild(($static ? 'static' : 'config'))->removeChild($filename);
}
}
}

tests/datasets/config/local.config.php → tests/datasets/config/A.config.php View File


tests/datasets/config/local.ini.php → tests/datasets/config/A.ini.php View File


+ 29
- 0
tests/datasets/config/B.config.php 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',
],
];

+ 20
- 0
tests/datasets/config/B.ini.php 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;

+ 1
- 0
tests/include/ApiTest.php View File

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


+ 1
- 1
tests/src/Console/AutomaticInstallationConsoleTest.php View File

@ -392,7 +392,7 @@ FIN;
// 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.
return [


+ 91
- 4
tests/src/Util/Config/ConfigFileLoaderTest.php View File

@ -6,7 +6,7 @@ use Friendica\App;
use Friendica\Core\Config\Cache\ConfigCache;
use Friendica\Test\MockedTest;
use Friendica\Test\Util\VFSTrait;
use Friendica\Util\Config\ConfigFileLoader;
use Friendica\Util\ConfigFileLoader;
use Mockery\MockInterface;
use org\bovigo\vfs\vfsStream;
@ -73,7 +73,7 @@ class ConfigFileLoaderTest extends MockedTest
'..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR .
'local.config.php';
'A.config.php';
vfsStream::newFile('local.config.php')
->at($this->root->getChild('config'))
@ -105,7 +105,7 @@ class ConfigFileLoaderTest extends MockedTest
'..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR .
'local.ini.php';
'A.ini.php';
vfsStream::newFile('local.ini.php')
->at($this->root->getChild('config'))
@ -185,7 +185,7 @@ class ConfigFileLoaderTest extends MockedTest
'..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR .
'local.config.php';
'A.config.php';
vfsStream::newFile('test.config.php')
->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']);
}
/**
* 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'));
}
}

+ 3
- 3
update.php View File

@ -22,7 +22,7 @@ use Friendica\Worker\Delivery;
* This function is responsible for doing post update changes to the data
* (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
* 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.
*
* 1. Create a function "update_4712()" here in the update.php
* 2. Apply the needed structural changes in config/dbStructure.php
* 3. Set DB_UPDATE_VERSION in config/dbstructure.config.php to 4712.
* 2. Apply the needed structural changes in static/dbStructure.php
* 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()"
*/


+ 1
- 1
view/templates/local.config.tpl View File

@ -2,7 +2,7 @@
// 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.
return [


Loading…
Cancel
Save