feature #12862 [Console] Allowing the user answering key or value of the autocompleterValues (saro0h)
This PR was merged into the 2.7 branch.
Discussion
----------
[Console] Allowing the user answering key or value of the autocompleterValues
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #11116
| License | MIT
| Doc PR | ~
**Before**:
![capture d ecran 2014-12-05 a 01 07 54](https://cloud.githubusercontent.com/assets/667519/5308827/ebaec496-7c1b-11e4-8872-5ed1f3642836.png)
**After**:
![capture d ecran 2014-12-07 a 01 56 13](https://cloud.githubusercontent.com/assets/667519/5329554/493e8602-7db4-11e4-9667-ef4c8826317c.png)
NB: As we want the user to be able to type either "env_1" or "Launch this and that", I offered autocompletion too on the values of the autocompletedValues.
Commits
-------
fa03e52
Fixed the issue 11116
This commit is contained in:
commit
6b6fa56c50
@ -36,7 +36,7 @@ class ChoiceQuestion extends Question
|
||||
|
||||
$this->choices = $choices;
|
||||
$this->setValidator($this->getDefaultValidator());
|
||||
$this->setAutocompleterValues(array_keys($choices));
|
||||
$this->setAutocompleterValues($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,17 +134,69 @@ class ChoiceQuestion extends Question
|
||||
|
||||
$multiselectChoices = array();
|
||||
foreach ($selectedChoices as $value) {
|
||||
if (empty($choices[$value])) {
|
||||
$this->checkMultipleResults($choices, $value);
|
||||
$result = $this->getResult($choices, $value);
|
||||
|
||||
if (empty($result)) {
|
||||
throw new \InvalidArgumentException(sprintf($errorMessage, $value));
|
||||
}
|
||||
array_push($multiselectChoices, $choices[$value]);
|
||||
array_push($multiselectChoices, $result);
|
||||
}
|
||||
|
||||
if ($multiselect) {
|
||||
return $multiselectChoices;
|
||||
}
|
||||
|
||||
return $choices[$selected];
|
||||
return current($multiselectChoices);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are multiple keys corresponding to the value supplied
|
||||
* by the user.
|
||||
*
|
||||
* @param array $possibleChoices Possible value(s) that the user can supply
|
||||
* @param string $value Value supplied by the user
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
private function checkMultipleResults(array $possibleChoices, $value)
|
||||
{
|
||||
$results = array();
|
||||
foreach ($possibleChoices as $key => $choice) {
|
||||
if ($choice === $value) {
|
||||
$results[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($results) > 1) {
|
||||
throw new \InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result according to what have been provided by the user and the
|
||||
* possible choices.
|
||||
*
|
||||
* @param array $possibleChoices Possible value(s) that the user can supply
|
||||
* @param string $value Value supplied by the user
|
||||
*
|
||||
* @retun string
|
||||
*/
|
||||
private function getResult(array $possibleChoices, $value)
|
||||
{
|
||||
$result = array_search($value, $possibleChoices);
|
||||
|
||||
if (!$this->isAssoc($possibleChoices)) {
|
||||
if (!empty($result)) {
|
||||
$result = $possibleChoices[$result];
|
||||
} elseif (isset($possibleChoices[$value])) {
|
||||
$result = $possibleChoices[$value];
|
||||
}
|
||||
} elseif (empty($result) && array_key_exists($value, $possibleChoices)) {
|
||||
$result = $value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -135,6 +135,10 @@ class Question
|
||||
*/
|
||||
public function setAutocompleterValues($values)
|
||||
{
|
||||
if (is_array($values) && $this->isAssoc($values)) {
|
||||
$values = array_merge(array_keys($values), array_values($values));
|
||||
}
|
||||
|
||||
if (null !== $values && !is_array($values)) {
|
||||
if (!$values instanceof \Traversable || $values instanceof \Countable) {
|
||||
throw new \InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.');
|
||||
@ -235,4 +239,9 @@ class Question
|
||||
{
|
||||
return $this->normalizer;
|
||||
}
|
||||
|
||||
protected function isAssoc($array)
|
||||
{
|
||||
return (bool) count(array_filter(array_keys($array), 'is_string'));
|
||||
}
|
||||
}
|
||||
|
@ -198,6 +198,60 @@ class QuestionHelperTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider answerProvider
|
||||
*/
|
||||
public function testSelectChoiceFromChoiceList($providedAnswer, $expectedValue)
|
||||
{
|
||||
$possibleChoices = array(
|
||||
'env_1' => 'My environment 1',
|
||||
'env_2' => 'My environment',
|
||||
'env_3' => 'My environment',
|
||||
);
|
||||
|
||||
$dialog = new QuestionHelper();
|
||||
$dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
|
||||
$helperSet = new HelperSet(array(new FormatterHelper()));
|
||||
$dialog->setHelperSet($helperSet);
|
||||
|
||||
$question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
|
||||
$answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
|
||||
|
||||
$this->assertSame($expectedValue, $answer);
|
||||
}
|
||||
|
||||
public function testAmbiguousChoiceFromChoicelist()
|
||||
{
|
||||
$possibleChoices = array(
|
||||
'env_1' => 'My environment 1',
|
||||
'env_2' => 'My environment',
|
||||
'env_3' => 'My environment',
|
||||
);
|
||||
|
||||
$dialog = new QuestionHelper();
|
||||
$dialog->setInputStream($this->getInputStream("My environment\n"));
|
||||
$helperSet = new HelperSet(array(new FormatterHelper()));
|
||||
$dialog->setHelperSet($helperSet);
|
||||
|
||||
$question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
|
||||
|
||||
try {
|
||||
$dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertEquals('The provided answer is ambiguous. Value should be one of env_2 or env_3.', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function answerProvider()
|
||||
{
|
||||
return array(
|
||||
array('env_1', 'env_1'),
|
||||
array('env_2', 'env_2'),
|
||||
array('env_3', 'env_3'),
|
||||
array('My environment 1', 'env_1'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testNoInteraction()
|
||||
{
|
||||
$dialog = new QuestionHelper();
|
||||
|
Reference in New Issue
Block a user