Skip to content

[DialogHelper] Multiselect : added an option to the "select" function that makes the possibility of multiselect options. #7602

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

Closed
wants to merge 7 commits into from
33 changes: 28 additions & 5 deletions src/Symfony/Component/Console/Helper/DialogHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ class DialogHelper extends Helper
* @param Boolean $default The default answer if the user enters nothing
* @param Boolean|integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
* @param string $errorMessage Message which will be shown if invalid value from choice list would be picked
* @param Boolean $multiselect Select more than one value separated by comma
*
* @return integer|string The selected value (the key of the choices array)
* @return integer|string|array The selected value or values (the key of the choices array)
*
* @throws \InvalidArgumentException
*/
public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid')
public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
{
$width = max(array_map('strlen', array_keys($choices)));

Expand All @@ -50,11 +51,33 @@ public function select(OutputInterface $output, $question, $choices, $default =

$output->writeln($messages);

$result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage) {
if (empty($choices[$picked])) {
throw new \InvalidArgumentException(sprintf($errorMessage, $picked));
$result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) {
// Collapse all spaces.
$selectedChoices = str_replace(" ", "", $picked);

if ($multiselect) {
// Check for a separated comma values
if(!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
throw new \InvalidArgumentException(sprintf($errorMessage, $picked));
}
$selectedChoices = explode(",", $selectedChoices);
} else {
$selectedChoices = array($picked);
}

$multiselectChoices = array();

foreach ($selectedChoices as $value) {
if (empty($choices[$value])) {
throw new \InvalidArgumentException(sprintf($errorMessage, $value));
}
array_push($multiselectChoices, $value);
}

if ($multiselect){
return $multiselectChoices;
}

return $picked;
}, $attempts, $default);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public function testSelect()

$heroes = array('Superman', 'Batman', 'Spiderman');

$dialog->setInputStream($this->getInputStream("\n1\nFabien\n1\nFabien\nFabien\n"));
$dialog->setInputStream($this->getInputStream("\n1\nFabien\n1\nFabien\n1\n0,2\n\n"));
$this->assertEquals('2', $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, '2'));
$this->assertEquals('1', $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes));
$this->assertEquals('1', $dialog->select($output = $this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!'));
$this->assertEquals('1', $dialog->select($output = $this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!', false));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for the multiselect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added 3 new tests for multiselect option

rewind($output->getStream());
$this->assertContains('Input "Fabien" is not a superhero!', stream_get_contents($output->getStream()));
Expand All @@ -41,6 +41,10 @@ public function testSelect()
} catch (\InvalidArgumentException $e) {
$this->assertEquals('Value "Fabien" is invalid', $e->getMessage());
}

$this->assertEquals(array('1'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!', true));
$this->assertEquals(array('0', '2'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!', true));
$this->assertEquals(array('0', '1'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, '0,1', false, 'Input "%s" is not a superhero!', true));
}

public function testAsk()
Expand Down