aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/command/config/system/setconfig.php128
-rw-r--r--tests/core/command/config/system/setconfigtest.php156
2 files changed, 232 insertions, 52 deletions
diff --git a/core/command/config/system/setconfig.php b/core/command/config/system/setconfig.php
index 0100ad2dfb0..83a969fd55d 100644
--- a/core/command/config/system/setconfig.php
+++ b/core/command/config/system/setconfig.php
@@ -48,8 +48,15 @@ class SetConfig extends Base {
->setDescription('Set a system config value')
->addArgument(
'name',
- InputArgument::REQUIRED,
- 'Name of the config to set'
+ InputArgument::REQUIRED | InputArgument::IS_ARRAY,
+ 'Name of the config parameter, specify multiple for array parameter'
+ )
+ ->addOption(
+ 'type',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'Value type [string, integer, double, boolean]',
+ 'string'
)
->addOption(
'value',
@@ -67,16 +74,119 @@ class SetConfig extends Base {
}
protected function execute(InputInterface $input, OutputInterface $output) {
- $configName = $input->getArgument('name');
+ $configNames = $input->getArgument('name');
+ $configName = $configNames[0];
+ $configValue = $this->castValue($input->getOption('value'), $input->getOption('type'));
+ $updateOnly = $input->getOption('update-only');
+
+ if (count($configNames) > 1) {
+ $existingValue = $this->systemConfig->getValue($configName);
+
+ $newValue = $this->mergeArrayValue(
+ array_slice($configNames, 1), $existingValue, $configValue, $updateOnly
+ );
+
+ $this->systemConfig->setValue($configName, $newValue);
+ } else {
+ if ($updateOnly && !in_array($configName, $this->systemConfig->getKeys(), true)) {
+ throw new \UnexpectedValueException('Config parameter does not exist');
+ }
- if (!in_array($configName, $this->systemConfig->getKeys()) && $input->hasParameterOption('--update-only')) {
- $output->writeln('<comment>Config value ' . $configName . ' not updated, as it has not been set before.</comment>');
- return 1;
+ $this->systemConfig->setValue($configName, $configValue);
}
- $configValue = $input->getOption('value');
- $this->systemConfig->setValue($configName, $configValue);
- $output->writeln('<info>System config value ' . $configName . ' set to ' . $configValue . '</info>');
+ $output->writeln('<info>System config value ' . implode(' => ', $configNames) . ' set to ' . $configValue . '</info>');
return 0;
}
+
+ /**
+ * @param string $value
+ * @param string $type
+ * @return mixed
+ * @throws \InvalidArgumentException
+ */
+ protected function castValue($value, $type) {
+ if ($value === null) {
+ return null;
+ }
+
+ $type = strtolower($type);
+ switch ($type) {
+ case 'string':
+ case 'str':
+ case 's':
+ return $value;
+
+ case 'integer':
+ case 'int':
+ case 'i':
+ if (!is_numeric($value)) {
+ throw new \InvalidArgumentException('Non-numeric value specified');
+ }
+ return (int) $value;
+
+ case 'double':
+ case 'd':
+ case 'float':
+ case 'f':
+ if (!is_numeric($value)) {
+ throw new \InvalidArgumentException('Non-numeric value specified');
+ }
+ return (double) $value;
+
+ case 'boolean':
+ case 'bool':
+ case 'b':
+ $value = strtolower($value);
+ switch ($value) {
+ case 'true':
+ case 'yes':
+ case 'y':
+ case '1':
+ return true;
+
+ case 'false':
+ case 'no':
+ case 'n':
+ case '0':
+ return false;
+
+ default:
+ throw new \InvalidArgumentException('Unable to parse value as boolean');
+ }
+
+ default:
+ throw new \InvalidArgumentException('Invalid type');
+ }
+ }
+
+ /**
+ * @param array $configNames
+ * @param mixed $existingValues
+ * @param mixed $value
+ * @param bool $updateOnly
+ * @return array merged value
+ * @throws \UnexpectedValueException
+ */
+ protected function mergeArrayValue(array $configNames, $existingValues, $value, $updateOnly) {
+ $configName = array_shift($configNames);
+ if (!is_array($existingValues)) {
+ $existingValues = [];
+ }
+ if (!empty($configNames)) {
+ if (isset($existingValues[$configName])) {
+ $existingValue = $existingValues[$configName];
+ } else {
+ $existingValue = [];
+ }
+ $existingValues[$configName] = $this->mergeArrayValue($configNames, $existingValue, $value, $updateOnly);
+ } else {
+ if (!isset($existingValues[$configName]) && $updateOnly) {
+ throw new \UnexpectedValueException('Config parameter does not exist');
+ }
+ $existingValues[$configName] = $value;
+ }
+ return $existingValues;
+ }
+
}
diff --git a/tests/core/command/config/system/setconfigtest.php b/tests/core/command/config/system/setconfigtest.php
index bbabee9b18f..14a6a980938 100644
--- a/tests/core/command/config/system/setconfigtest.php
+++ b/tests/core/command/config/system/setconfigtest.php
@@ -53,63 +53,133 @@ class SetConfigTest extends TestCase {
public function setData() {
return [
- [
- 'name',
- 'newvalue',
- true,
- true,
- true,
- 'info',
- ],
- [
- 'name',
- 'newvalue',
- false,
- true,
- false,
- 'comment',
- ],
+ [['name'], 'newvalue', null, 'newvalue'],
+ [['a', 'b', 'c'], 'foobar', null, ['b' => ['c' => 'foobar']]],
+ [['a', 'b', 'c'], 'foobar', ['b' => ['d' => 'barfoo']], ['b' => ['d' => 'barfoo', 'c' => 'foobar']]],
];
}
/**
* @dataProvider setData
*
- * @param string $configName
- * @param mixed $newValue
- * @param bool $configExists
- * @param bool $updateOnly
- * @param bool $updated
- * @param string $expectedMessage
+ * @param array $configNames
+ * @param string $newValue
+ * @param mixed $existingData
+ * @param mixed $expectedValue
*/
- public function testSet($configName, $newValue, $configExists, $updateOnly, $updated, $expectedMessage) {
+ public function testSet($configNames, $newValue, $existingData, $expectedValue) {
$this->systemConfig->expects($this->once())
- ->method('getKeys')
- ->willReturn($configExists ? [$configName] : []);
+ ->method('setValue')
+ ->with($configNames[0], $expectedValue);
+ $this->systemConfig->method('getValue')
+ ->with($configNames[0])
+ ->willReturn($existingData);
- if ($updated) {
- $this->systemConfig->expects($this->once())
- ->method('setValue')
- ->with($configName, $newValue);
- }
+ $this->consoleInput->expects($this->once())
+ ->method('getArgument')
+ ->with('name')
+ ->willReturn($configNames);
+ $this->consoleInput->method('getOption')
+ ->will($this->returnValueMap([
+ ['value', $newValue],
+ ['type', 'string'],
+ ]));
+
+ $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
+ }
+
+ public function setUpdateOnlyProvider() {
+ return [
+ [['name'], null],
+ [['a', 'b', 'c'], null],
+ [['a', 'b', 'c'], ['b' => 'foobar']],
+ [['a', 'b', 'c'], ['b' => ['d' => 'foobar']]],
+ ];
+ }
+
+ /**
+ * @dataProvider setUpdateOnlyProvider
+ * @expectedException \UnexpectedValueException
+ */
+ public function testSetUpdateOnly($configNames, $existingData) {
+ $this->systemConfig->expects($this->never())
+ ->method('setValue');
+ $this->systemConfig->method('getValue')
+ ->with($configNames[0])
+ ->willReturn($existingData);
+ $this->systemConfig->method('getKeys')
+ ->willReturn($existingData ? $configNames[0] : []);
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
- ->willReturn($configName);
- $this->consoleInput->expects($this->any())
- ->method('getOption')
- ->with('value')
- ->willReturn($newValue);
- $this->consoleInput->expects($this->any())
- ->method('hasParameterOption')
- ->with('--update-only')
- ->willReturn($updateOnly);
-
- $this->consoleOutput->expects($this->any())
- ->method('writeln')
- ->with($this->stringContains($expectedMessage));
+ ->willReturn($configNames);
+ $this->consoleInput->method('getOption')
+ ->will($this->returnValueMap([
+ ['value', 'foobar'],
+ ['type', 'string'],
+ ['update-only', true],
+ ]));
$this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
}
+
+ public function castValueProvider() {
+ return [
+ [null, 'integer', null],
+ [null, 'string', null],
+
+ ['abc', 'string', 'abc'],
+ ['dEF', 'str', 'dEF'],
+ ['123', 's', '123'],
+
+ ['123', 'integer', 123],
+ ['456', 'int', 456],
+ ['-666', 'i', -666],
+
+ // only use powers of 2 to avoid precision errors
+ ['2', 'double', 2.0],
+ ['0.25', 'd', 0.25],
+ ['0.5', 'float', 0.5],
+ ['0.125', 'f', 0.125],
+
+ ['true', 'boolean', true],
+ ['false', 'bool', false],
+ ['yes', 'b', true],
+ ['no', 'b', false],
+ ['y', 'b', true],
+ ['n', 'b', false],
+ ['1', 'b', true],
+ ['0', 'b', false],
+ ];
+ }
+
+ /**
+ * @dataProvider castValueProvider
+ */
+ public function testCastValue($value, $type, $expectedValue) {
+ $this->assertSame($expectedValue,
+ $this->invokePrivate($this->command, 'castValue', [$value, $type])
+ );
+ }
+
+ public function castValueInvalidProvider() {
+ return [
+ ['123', 'foobar'],
+
+ ['abc', 'integer'],
+ ['76ggg', 'double'],
+ ['true', 'float'],
+ ['foobar', 'boolean'],
+ ];
+ }
+
+ /**
+ * @dataProvider castValueInvalidProvider
+ * @expectedException \InvalidArgumentException
+ */
+ public function testCastValueInvalid($value, $type) {
+ $this->invokePrivate($this->command, 'castValue', [$value, $type]);
+ }
+
}