Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from Jan 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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