mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-02 22:47:01 +00:00
state config
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@
|
||||
/data/config-internal.php
|
||||
/data/config-override.php
|
||||
/data/config-internal-override.php
|
||||
/data/state.php
|
||||
/data/tmp/*
|
||||
/build
|
||||
/node_modules
|
||||
|
||||
@@ -46,6 +46,7 @@ class Config
|
||||
private string $internalConfigPath = 'data/config-internal.php';
|
||||
private string $overrideConfigPath = 'data/config-override.php';
|
||||
private string $internalOverrideConfigPath = 'data/config-internal-override.php';
|
||||
private string $stateConfigPath = 'data/state.php';
|
||||
private string $cacheTimestamp = 'cacheTimestamp';
|
||||
/** @var string[] */
|
||||
protected $associativeArrayAttributeList = [
|
||||
@@ -81,12 +82,22 @@ class Config
|
||||
* A path to the internal config file.
|
||||
*
|
||||
* @todo Move to ConfigData.
|
||||
* @internal
|
||||
*/
|
||||
public function getInternalConfigPath(): string
|
||||
{
|
||||
return $this->internalConfigPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Move to ConfigData.
|
||||
* @internal
|
||||
*/
|
||||
public function getStateConfigPath(): string
|
||||
{
|
||||
return $this->stateConfigPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a parameter value.
|
||||
*
|
||||
@@ -302,13 +313,15 @@ class Config
|
||||
$internalData = $this->readFile($this->internalConfigPath);
|
||||
$overrideData = $this->readFile($this->overrideConfigPath);
|
||||
$internalOverrideData = $this->readFile($this->internalOverrideConfigPath);
|
||||
$stateConfigData = $this->readFile($this->stateConfigPath);
|
||||
|
||||
$this->data = $this->mergeData(
|
||||
$systemData,
|
||||
$data,
|
||||
$internalData,
|
||||
$overrideData,
|
||||
$internalOverrideData
|
||||
systemData: $systemData,
|
||||
data: $data,
|
||||
internalData: $internalData,
|
||||
overrideData: $overrideData,
|
||||
internalOverrideData: $internalOverrideData,
|
||||
stateData: $stateConfigData,
|
||||
);
|
||||
|
||||
$this->internalParamList = array_values(array_merge(
|
||||
@@ -325,6 +338,7 @@ class Config
|
||||
* @param array<string, mixed> $internalData
|
||||
* @param array<string, mixed> $overrideData
|
||||
* @param array<string, mixed> $internalOverrideData
|
||||
* @param array<string, mixed> $stateData
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function mergeData(
|
||||
@@ -332,7 +346,8 @@ class Config
|
||||
array $data,
|
||||
array $internalData,
|
||||
array $overrideData,
|
||||
array $internalOverrideData
|
||||
array $internalOverrideData,
|
||||
array $stateData,
|
||||
): array {
|
||||
|
||||
/** @var array<string, mixed> $mergedData */
|
||||
@@ -344,8 +359,13 @@ class Config
|
||||
/** @var array<string, mixed> $mergedData */
|
||||
$mergedData = Util::merge($mergedData, $overrideData);
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
return Util::merge($mergedData, $internalOverrideData);
|
||||
/** @var array<string, mixed> $mergedData */
|
||||
$mergedData = Util::merge($mergedData, $internalOverrideData);
|
||||
|
||||
/** @var array<string, mixed> $mergedData */
|
||||
$mergedData = Util::merge($mergedData, $stateData);
|
||||
|
||||
return $mergedData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -107,6 +107,7 @@ class ConfigWriter
|
||||
|
||||
$configPath = $this->config->getConfigPath();
|
||||
$internalConfigPath = $this->config->getInternalConfigPath();
|
||||
$stateConfigPath = $this->config->getStateConfigPath();
|
||||
|
||||
if (!$this->fileManager->isFile($configPath)) {
|
||||
throw new RuntimeException("Config file '$configPath' not found.");
|
||||
@@ -117,6 +118,9 @@ class ConfigWriter
|
||||
$dataInternal = $this->fileManager->isFile($internalConfigPath) ?
|
||||
$this->fileManager->getPhpContents($internalConfigPath) : [];
|
||||
|
||||
$dataState = $this->fileManager->isFile($stateConfigPath) ?
|
||||
$this->fileManager->getPhpContents($stateConfigPath) : [];
|
||||
|
||||
if (!is_array($data)) {
|
||||
throw new RuntimeException("Could not read config.");
|
||||
}
|
||||
@@ -125,12 +129,45 @@ class ConfigWriter
|
||||
throw new RuntimeException("Could not read config-internal.");
|
||||
}
|
||||
|
||||
if (!is_array($dataState)) {
|
||||
throw new RuntimeException("Could not read state.");
|
||||
}
|
||||
|
||||
$toSaveInternal = false;
|
||||
$toSaveState = false;
|
||||
$toSaveMain = false;
|
||||
|
||||
foreach (array_merge(array_keys($changedData), $this->removeParamList) as $key) {
|
||||
if (array_key_exists($key, $data)) {
|
||||
$toSaveMain = true;
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $dataInternal)) {
|
||||
$toSaveInternal = true;
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $dataState)) {
|
||||
$toSaveState = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($changedData as $key => $value) {
|
||||
if ($this->internalConfigHelper->isParamForStateConfig($key)) {
|
||||
$dataState[$key] = $value;
|
||||
|
||||
unset($data[$key]);
|
||||
unset($dataInternal[$key]);
|
||||
|
||||
$toSaveState = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->internalConfigHelper->isParamForInternalConfig($key)) {
|
||||
$dataInternal[$key] = $value;
|
||||
|
||||
unset($data[$key]);
|
||||
unset($dataState[$key]);
|
||||
|
||||
$toSaveInternal = true;
|
||||
|
||||
@@ -138,25 +175,38 @@ class ConfigWriter
|
||||
}
|
||||
|
||||
$data[$key] = $value;
|
||||
|
||||
unset($dataState[$key]);
|
||||
unset($dataInternal[$key]);
|
||||
|
||||
$toSaveMain = true;
|
||||
}
|
||||
|
||||
foreach ($this->removeParamList as $key) {
|
||||
if ($this->internalConfigHelper->isParamForInternalConfig($key)) {
|
||||
unset($dataInternal[$key]);
|
||||
|
||||
$toSaveInternal = true;
|
||||
|
||||
continue;
|
||||
if (array_key_exists($key, $data)) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
unset($data[$key]);
|
||||
if (array_key_exists($key, $dataInternal)) {
|
||||
unset($dataInternal[$key]);
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $dataState)) {
|
||||
unset($dataState[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($toSaveInternal) {
|
||||
$this->saveData($internalConfigPath, $dataInternal, 'microtimeInternal');
|
||||
}
|
||||
|
||||
$this->saveData($configPath, $data, 'microtime');
|
||||
if ($toSaveMain) {
|
||||
$this->saveData($configPath, $data, 'microtime');
|
||||
}
|
||||
|
||||
if ($toSaveState) {
|
||||
$this->saveData($stateConfigPath, $dataState, 'microtimeState');
|
||||
}
|
||||
|
||||
$this->changedData = [];
|
||||
$this->removeParamList = [];
|
||||
|
||||
@@ -34,9 +34,23 @@ use Espo\Core\Utils\Metadata;
|
||||
|
||||
class InternalConfigHelper
|
||||
{
|
||||
/** @var string[] */
|
||||
private array $stateParamList = [
|
||||
'appTimestamp',
|
||||
'cacheTimestamp',
|
||||
'version',
|
||||
'latestVersion',
|
||||
'latestExtensionVersions',
|
||||
];
|
||||
|
||||
public function __construct(private Config $config, private Metadata $metadata)
|
||||
{}
|
||||
|
||||
public function isParamForStateConfig(string $name): bool
|
||||
{
|
||||
return in_array($name, $this->stateParamList);
|
||||
}
|
||||
|
||||
public function isParamForInternalConfig(string $name): bool
|
||||
{
|
||||
if ($this->config->isInternal($name)) {
|
||||
|
||||
@@ -46,6 +46,7 @@ class ConfigWriterTest extends TestCase
|
||||
|
||||
private $configPath;
|
||||
private $internalConfigPath;
|
||||
private $stateConfigPath;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@@ -61,8 +62,9 @@ class ConfigWriterTest extends TestCase
|
||||
$this->internalConfigHelper
|
||||
);
|
||||
|
||||
$this->configPath = 'somepath';
|
||||
$this->internalConfigPath = 'internalSomepath';
|
||||
$this->configPath = 'somePath';
|
||||
$this->internalConfigPath = 'internalSomePath';
|
||||
$this->stateConfigPath = 'stateSomePath';
|
||||
|
||||
$this->config
|
||||
->expects($this->any())
|
||||
@@ -73,6 +75,11 @@ class ConfigWriterTest extends TestCase
|
||||
->expects($this->any())
|
||||
->method('getInternalConfigPath')
|
||||
->willReturn($this->internalConfigPath);
|
||||
|
||||
$this->config
|
||||
->expects($this->any())
|
||||
->method('getStateConfigPath')
|
||||
->willReturn($this->stateConfigPath);
|
||||
}
|
||||
|
||||
public function testSave1(): void
|
||||
@@ -121,6 +128,7 @@ class ConfigWriterTest extends TestCase
|
||||
->willReturnMap([
|
||||
[$this->configPath, true],
|
||||
[$this->internalConfigPath, false],
|
||||
[$this->stateConfigPath, false],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
@@ -145,6 +153,7 @@ class ConfigWriterTest extends TestCase
|
||||
$this->configWriter->set('k2', 'v2');
|
||||
|
||||
$this->internalConfigHelper
|
||||
->expects($this->any())
|
||||
->method('isParamForInternalConfig')
|
||||
->willReturnMap(
|
||||
[
|
||||
@@ -154,8 +163,19 @@ class ConfigWriterTest extends TestCase
|
||||
]
|
||||
);
|
||||
|
||||
$this->internalConfigHelper
|
||||
->expects($this->any())
|
||||
->method('isParamForStateConfig')
|
||||
->willReturnMap(
|
||||
[
|
||||
['k1', false],
|
||||
['k2', false],
|
||||
['cacheTimestamp', true],
|
||||
]
|
||||
);
|
||||
|
||||
$this->helper
|
||||
->expects($this->exactly(2))
|
||||
->expects($this->exactly(3))
|
||||
->method('generateMicrotime')
|
||||
->willReturn(1.0);
|
||||
|
||||
@@ -170,16 +190,16 @@ class ConfigWriterTest extends TestCase
|
||||
->willReturnMap([
|
||||
[$this->configPath, true],
|
||||
[$this->internalConfigPath, true],
|
||||
[$this->stateConfigPath, true],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->exactly(4))
|
||||
->expects($this->exactly(6))
|
||||
->method('getPhpContents')
|
||||
->willReturnMap([
|
||||
[$this->configPath, []],
|
||||
[$this->internalConfigPath, []],
|
||||
[$this->internalConfigPath, []],
|
||||
[$this->configPath, []],
|
||||
[$this->stateConfigPath, []],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
@@ -192,7 +212,156 @@ class ConfigWriterTest extends TestCase
|
||||
],
|
||||
[
|
||||
$this->configPath,
|
||||
['k1' => 'v1', 'cacheTimestamp' => 1, 'microtime' => 1.0]
|
||||
['k1' => 'v1', 'microtime' => 1.0]
|
||||
],
|
||||
[
|
||||
$this->stateConfigPath,
|
||||
['cacheTimestamp' => 1, 'microtimeState' => 1.0]
|
||||
],
|
||||
]);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
public function testSave3(): void
|
||||
{
|
||||
$this->configWriter->set('k1', 'v1');
|
||||
$this->configWriter->set('k2', 'v2');
|
||||
|
||||
$this->internalConfigHelper
|
||||
->expects($this->any())
|
||||
->method('isParamForInternalConfig')
|
||||
->willReturnMap(
|
||||
[
|
||||
['k1', false],
|
||||
['k2', true],
|
||||
['cacheTimestamp', false],
|
||||
]
|
||||
);
|
||||
|
||||
$this->internalConfigHelper
|
||||
->expects($this->any())
|
||||
->method('isParamForStateConfig')
|
||||
->willReturnMap(
|
||||
[
|
||||
['k1', false],
|
||||
['k2', false],
|
||||
['cacheTimestamp', true],
|
||||
]
|
||||
);
|
||||
|
||||
$this->helper
|
||||
->expects($this->exactly(3))
|
||||
->method('generateMicrotime')
|
||||
->willReturn(1.0);
|
||||
|
||||
$this->helper
|
||||
->expects($this->once())
|
||||
->method('generateCacheTimestamp')
|
||||
->willReturn(1);
|
||||
|
||||
$this->fileManager
|
||||
->expects(self::any())
|
||||
->method('isFile')
|
||||
->willReturnMap([
|
||||
[$this->configPath, true],
|
||||
[$this->internalConfigPath, true],
|
||||
[$this->stateConfigPath, true],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->exactly(6))
|
||||
->method('getPhpContents')
|
||||
->willReturnMap([
|
||||
[$this->configPath, []],
|
||||
[$this->internalConfigPath, []],
|
||||
[$this->stateConfigPath, []],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
->expects(self::any())
|
||||
->method('putPhpContents')
|
||||
->willReturnMap([
|
||||
[
|
||||
$this->internalConfigPath,
|
||||
['k2' => 'v2', 'microtimeInternal' => 1.0]
|
||||
],
|
||||
[
|
||||
$this->configPath,
|
||||
['k1' => 'v1', 'microtime' => 1.0]
|
||||
],
|
||||
[
|
||||
$this->stateConfigPath,
|
||||
['cacheTimestamp' => 1, 'microtimeState' => 1.0]
|
||||
],
|
||||
]);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
public function testsRemove1(): void
|
||||
{
|
||||
$this->configWriter->remove('k1');
|
||||
|
||||
$this->internalConfigHelper
|
||||
->expects($this->any())
|
||||
->method('isParamForInternalConfig')
|
||||
->willReturnMap(
|
||||
[
|
||||
['k1', false],
|
||||
['cacheTimestamp', false],
|
||||
]
|
||||
);
|
||||
|
||||
$this->internalConfigHelper
|
||||
->expects($this->any())
|
||||
->method('isParamForStateConfig')
|
||||
->willReturnMap(
|
||||
[
|
||||
['k1', false],
|
||||
['cacheTimestamp', false],
|
||||
]
|
||||
);
|
||||
|
||||
$this->helper
|
||||
->expects($this->once())
|
||||
->method('generateCacheTimestamp')
|
||||
->willReturn(1);
|
||||
|
||||
$this->fileManager
|
||||
->expects(self::any())
|
||||
->method('isFile')
|
||||
->willReturnMap([
|
||||
[$this->configPath, true],
|
||||
[$this->internalConfigPath, true],
|
||||
[$this->stateConfigPath, true],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
->expects(self::any())
|
||||
->method('isFile')
|
||||
->willReturnMap([
|
||||
[$this->configPath, true],
|
||||
[$this->internalConfigPath, true],
|
||||
[$this->stateConfigPath, true],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->exactly(4))
|
||||
->method('getPhpContents')
|
||||
->willReturnMap([
|
||||
[$this->configPath, ['k1' => 'v1', 'k2' => 'v2']],
|
||||
[$this->internalConfigPath, []],
|
||||
[$this->stateConfigPath, []],
|
||||
]);
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->exactly(1))
|
||||
->method('putPhpContents')
|
||||
->willReturnMap([
|
||||
[
|
||||
$this->configPath,
|
||||
['k2' => 'v2', 'microtime' => 1.0]
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ class ConfigTest extends TestCase
|
||||
private $configPath = 'tests/unit/testData/cache/config.php';
|
||||
private $systemConfigPath = 'tests/unit/testData/Utils/Config/systemConfig.php';
|
||||
private $internalConfigPath = 'tests/unit/testData/cache/config-internal.php';
|
||||
private $stateConfigPath = 'tests/unit/testData/cache/state.php';
|
||||
|
||||
private $reflection;
|
||||
private $fileManager;
|
||||
@@ -63,11 +64,7 @@ class ConfigTest extends TestCase
|
||||
$this->reflection->setProperty('configPath', $this->configPath);
|
||||
$this->reflection->setProperty('systemConfigPath', $this->systemConfigPath);
|
||||
$this->reflection->setProperty('internalConfigPath', $this->internalConfigPath);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->config = NULL;
|
||||
$this->reflection->setProperty('stateConfigPath', $this->stateConfigPath);
|
||||
}
|
||||
|
||||
public function testLoadConfig()
|
||||
@@ -123,6 +120,7 @@ class ConfigTest extends TestCase
|
||||
['data/config-internal.php', true],
|
||||
['application/Espo/Resources/defaults/systemConfig.php', true],
|
||||
['data/config-override.php', false],
|
||||
['data/state.php', true],
|
||||
['data/config-internal-override.php', false],
|
||||
]
|
||||
);
|
||||
@@ -145,6 +143,7 @@ class ConfigTest extends TestCase
|
||||
[
|
||||
['data/config.php', $data],
|
||||
['data/config-internal.php', $dataInternal],
|
||||
['data/state.php', []],
|
||||
['application/Espo/Resources/defaults/systemConfig.php', $dataSystem],
|
||||
]
|
||||
);
|
||||
@@ -181,6 +180,7 @@ class ConfigTest extends TestCase
|
||||
['data/config-internal.php', true],
|
||||
['application/Espo/Resources/defaults/systemConfig.php', true],
|
||||
['data/config-override.php', false],
|
||||
['data/state.php', true],
|
||||
['data/config-internal-override.php', false],
|
||||
]
|
||||
);
|
||||
@@ -208,6 +208,7 @@ class ConfigTest extends TestCase
|
||||
[
|
||||
['data/config.php', $data],
|
||||
['data/config-internal.php', $dataInternal],
|
||||
['data/state.php', []],
|
||||
['application/Espo/Resources/defaults/systemConfig.php', $dataSystem],
|
||||
]
|
||||
);
|
||||
@@ -239,6 +240,7 @@ class ConfigTest extends TestCase
|
||||
['data/config.php', true],
|
||||
['data/config-internal.php', true],
|
||||
['data/config-override.php', true],
|
||||
['data/state.php', true],
|
||||
['data/config-internal-override.php', true],
|
||||
]
|
||||
);
|
||||
@@ -273,6 +275,7 @@ class ConfigTest extends TestCase
|
||||
['data/config.php', $data],
|
||||
['data/config-internal.php', $dataInternal],
|
||||
['data/config-override.php', $dataOverride],
|
||||
['data/state.php', []],
|
||||
['data/config-internal-override.php', $dataInternalOverride],
|
||||
]
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user