Skip to content

Commit

Permalink
Let config:set change multiple top-level keys. Add docs and tests. (#…
Browse files Browse the repository at this point in the history
…4983)

* Let config:set change multiple top-level keys. Add docs and tests.

* Also get rid of unused --value option in state:set
  • Loading branch information
weitzman committed Jan 6, 2022
1 parent 5a666e7 commit a1917ee
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 25 deletions.
43 changes: 24 additions & 19 deletions src/Drupal/Commands/config/ConfigCommands.php
Expand Up @@ -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 <info>system.site</info>.
* @param $key The config key, for example <info>page.front</info>.
* @param $key The config key, for example <info>page.front</info>. Use <info>?</info> if you are updating multiple keys.
* @param $value The value to assign to the config key. Use <info>-</info> to read from STDIN.
* @option input-format Format to parse the object. Recognized values: <info>string</info>, <info>yaml</info>
* @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: <info>string</info>, <info>yaml</info>. 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 <info>name</info> of <info>system.site</info> 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 <info>page.front</info> of <info>system.site</info> 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 <info>permissions</info> of <info>user.role.authenticated</info> config object.
* @usage drush config:set --input-format=yaml system.site page {403: '403', front: home}
* Use a mapping as value for the key <info>page</info> of <info>system.site</info> 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 <info>system.site</info> 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]))) {
Expand All @@ -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();
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/Drupal/Commands/core/StateCommands.php
Expand Up @@ -51,8 +51,6 @@ public function get(string $key, $options = ['format' => 'string']): PropertyLis
* @param string $key The state key, for example: <info>system.cron_last</info>.
* @param mixed $value The value to assign to the state key. Use <info>-</info> 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
Expand All @@ -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.'));
Expand Down
29 changes: 28 additions & 1 deletion tests/functional/ConfigTest.php
Expand Up @@ -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()
Expand Down

0 comments on commit a1917ee

Please sign in to comment.