diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index a5f1722bae..ee0459e13d 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * added support for colorization on Windows via ConEmu * add a method to Dialog Helper to ask for a question and hide the response + * added support for interactive selections in console (DialogHelper::select()) 2.1.0 ----- diff --git a/src/Symfony/Component/Console/Helper/DialogHelper.php b/src/Symfony/Component/Console/Helper/DialogHelper.php index 232343454e..baeeefc591 100644 --- a/src/Symfony/Component/Console/Helper/DialogHelper.php +++ b/src/Symfony/Component/Console/Helper/DialogHelper.php @@ -24,6 +24,40 @@ class DialogHelper extends Helper private static $shell; private static $stty; + /** + * Asks the user to select a value. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param array $choices List of choices to pick from + * @param Boolean $default The default answer if the user enters nothing + * @param integer|false $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 + * + * @return integer|string The selected value (the key of the choices array) + */ + public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid') + { + $width = max(array_map('strlen', array_keys($choices))); + + $messages = (array) $question; + foreach ($choices as $key => $value) { + $messages[] = sprintf(" [%-${width}s] %s", $key, $value); + } + + $output->writeln($messages); + + $result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage) { + if (empty($choices[$picked])) { + throw new \InvalidArgumentException(sprintf($errorMessage, $picked)); + } + + return $picked; + }, $attempts, $default); + + return $result; + } + /** * Asks a question to the user. * diff --git a/src/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php index 658ab69b4c..d0da968a15 100644 --- a/src/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php @@ -18,6 +18,31 @@ use Symfony\Component\Console\Output\StreamOutput; class DialogHelperTest extends \PHPUnit_Framework_TestCase { + public function testSelect() + { + $dialog = new DialogHelper(); + + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $heroes = array('Superman', 'Batman', 'Spiderman'); + + $dialog->setInputStream($this->getInputStream("\n1\nFabien\n1\nFabien\nFabien\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!')); + + rewind($output->getStream()); + $this->assertContains('Input "Fabien" is not a superhero!', stream_get_contents($output->getStream())); + + try { + $this->assertEquals('1', $dialog->select($output = $this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, 1)); + $this->fail(); + } catch (\InvalidArgumentException $e) { + $this->assertEquals('Value "Fabien" is invalid', $e->getMessage()); + } + } + public function testAsk() { $dialog = new DialogHelper();