diff --git a/src/Drupal/Commands/config/ConfigCommands.php b/src/Drupal/Commands/config/ConfigCommands.php
index 10e1342567..e8c85f86d6 100644
--- a/src/Drupal/Commands/config/ConfigCommands.php
+++ b/src/Drupal/Commands/config/ConfigCommands.php
@@ -126,59 +126,64 @@ public function get($config_name, $key = '', $options = ['format' => 'yaml', 'so
}
/**
- * Set config value directly. Does not perform a config import.
+ * Save a config value directly. Does not perform a config import.
*
* @command config:set
* @validate-config-name
* @todo @interact-config-name deferred until we have interaction for key.
* @param $config_name The config object name, for example system.site.
- * @param $key The config key, for example page.front.
+ * @param $key The config key, for example page.front. Use ? if you are updating multiple keys.
* @param $value The value to assign to the config key. Use - to read from STDIN.
- * @option input-format Format to parse the object. Recognized values: string, yaml
- * @option value The value to assign to the config key (if any).
- * @hidden-options value
+ * @option input-format Format to parse the object. Recognized values: string, yaml. Since JSON is a subset of YAML, $value may be in JSON format.
+ * @usage drush config:set system.site name MySite
+ * Sets a value for the key name of system.site config object.
* @usage drush config:set system.site page.front '/path/to/page'
* Sets the given URL path as value for the config item with key page.front of system.site config object.
* @usage drush config:set system.site '[]'
* Sets the given key to an empty array.
+ * @usage drush config:set --input-format=yaml user.role.authenticated permissions [foo,bar]
+ * Use a sequence as value for the key permissions of user.role.authenticated config object.
+ * @usage drush config:set --input-format=yaml system.site page {403: '403', front: home}
+ * Use a mapping as value for the key page of system.site config object.
+ * @usage drush config:set --input-format=yaml user.role.authenticated ? "{label: 'Auth user', weight: 5}"
+ * Update two top level keys (label, weight) in the system.site config object.
* @aliases cset,config-set
*/
- public function set($config_name, $key, $value = null, $options = ['input-format' => 'string', 'value' => self::REQ])
+ public function set($config_name, $key, $value = null, $options = ['input-format' => 'string'])
{
- // This hidden option is a convenient way to pass a value without passing a key.
- $data = $options['value'] ?: $value;
+ $data = $value;
if (!isset($data)) {
throw new \Exception(dt('No config value specified.'));
}
- $config = $this->getConfigFactory()->getEditable($config_name);
- // Check to see if config key already exists.
- $new_key = $config->get($key) === null;
-
// Special flag indicating that the value has been passed via STDIN.
if ($data === '-') {
$data = $this->stdin()->contents();
}
-
// Special handling for empty array.
if ($data == '[]') {
$data = [];
}
- // Now, we parse the value.
+ // Parse the value if needed.
switch ($options['input-format']) {
case 'yaml':
$parser = new Parser();
$data = $parser->parse($data, true);
}
- if (is_array($data) && !empty($data) && $this->io()->confirm(dt('Do you want to update or set multiple keys on !name config.', ['!name' => $config_name]))) {
- foreach ($data as $data_key => $value) {
- $config->set("$key.$data_key", $value);
+ $config = $this->getConfigFactory()->getEditable($config_name);
+ // Check to see if config key already exists.
+ $new_key = $config->get($key) === null;
+ $simulate = $this->getConfig()->simulate();
+
+ if ($key == '?' && !empty($data) && $this->io()->confirm(dt('Do you want to update or set multiple keys on !name config.', ['!name' => $config_name]))) {
+ foreach ($data as $data_key => $val) {
+ $config->set($data_key, $val);
}
- return $config->save();
+ return $simulate ? self::EXIT_SUCCESS : $config->save();
} else {
$confirmed = false;
if ($config->isNew() && $this->io()->confirm(dt('!name config does not exist. Do you want to create a new config object?', ['!name' => $config_name]))) {
@@ -188,7 +193,7 @@ public function set($config_name, $key, $value = null, $options = ['input-format
} elseif ($this->io()->confirm(dt('Do you want to update !key key in !name config?', ['!key' => $key, '!name' => $config_name]))) {
$confirmed = true;
}
- if ($confirmed && !$this->getConfig()->simulate()) {
+ if ($confirmed && !$simulate) {
return $config->set($key, $data)->save();
}
}
diff --git a/src/Drupal/Commands/core/StateCommands.php b/src/Drupal/Commands/core/StateCommands.php
index a2f01b4943..5c3febc6f5 100644
--- a/src/Drupal/Commands/core/StateCommands.php
+++ b/src/Drupal/Commands/core/StateCommands.php
@@ -51,8 +51,6 @@ public function get(string $key, $options = ['format' => 'string']): PropertyLis
* @param string $key The state key, for example: system.cron_last.
* @param mixed $value The value to assign to the state key. Use - to read from STDIN.
* @option input-format Type for the value. Other recognized values: string, integer, float, boolean, json, yaml.
- * @option value For internal use only.
- * @hidden-options value
* @usage drush sset system.maintenance_mode 1 --input-format=integer
* Put site into Maintenance mode.
* @usage drush state:set system.cron_last 1406682882 --input-format=integer
@@ -61,10 +59,8 @@ public function get(string $key, $options = ['format' => 'string']): PropertyLis
* Set a key to a complex value (e.g. array)
* @aliases sset,state-set
*/
- public function set(string $key, $value, $options = ['input-format' => 'auto', 'value' => self::REQ]): void
+ public function set(string $key, $value, $options = ['input-format' => 'auto']): void
{
- // A convenient way to pass a multiline value within a backend request.
- $value = $options['value'] ?: $value;
if (!isset($value)) {
throw new \Exception(dt('No state value specified.'));
diff --git a/tests/functional/ConfigTest.php b/tests/functional/ConfigTest.php
index 0935d2a4e7..690a9d3dbe 100644
--- a/tests/functional/ConfigTest.php
+++ b/tests/functional/ConfigTest.php
@@ -25,11 +25,38 @@ public function setup(): void
}
}
+ /**
+ * @todo If this becomes an integration test, add test for stdin handling.
+ */
public function testConfigGetSet()
{
+ // Simple value
$this->drush('config:set', ['system.site', 'name', 'config_test']);
$this->drush('config:get', ['system.site', 'name']);
- $this->assertEquals("'system.site:name': config_test", $this->getOutput(), 'Config was successfully set and get.');
+ $this->assertEquals("'system.site:name': config_test", $this->getOutput());
+
+ // Nested value
+ $this->drush('config:set', ['system.site', 'page.front', 'llama']);
+ $this->drush('config:get', ['system.site', 'page.front']);
+ $this->assertEquals("'system.site:page.front': llama", $this->getOutput());
+
+ // Simple sequence value
+ $this->drush('config:set', ['user.role.authenticated', 'permissions', '[foo,bar]'], ['input-format' => 'yaml']);
+ $this->drush('config:get', ['user.role.authenticated', 'permissions'], ['format' => 'json']);
+ $output = $this->getOutputFromJSON('user.role.authenticated:permissions');
+
+ // Mapping value
+ $this->drush('config:set', ['system.site', 'page', "{403: '403', front: home}"], ['input-format' => 'yaml']);
+ $this->drush('config:get', ['system.site', 'page'], ['format' => 'json']);
+ $output = $this->getOutputFromJSON('system.site:page');
+ $this->assertSame(['403' => '403', 'front' => 'home'], $output);
+
+ // Multiple top-level keys
+ $this->drush('config:set', ['user.role.authenticated', '?', "{label: 'Auth user', weight: 5}"], ['input-format' => 'yaml']);
+ $this->drush('config:get', ['user.role.authenticated'], ['format' => 'json']);
+ $output = $this->getOutputFromJSON();
+ $this->assertSame('Auth user', $output['label']);
+ $this->assertSame(5, $output['weight']);
}
public function testConfigExportImportStatusExistingConfig()