feature #34790 [Console] Remove restriction for choices to be strings (LordZardeck, YaFou, ogizanagi)
This PR was merged into the 5.2-dev branch. Discussion ---------- [Console] Remove restriction for choices to be strings | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #34789 | License | MIT When using choice, selected answers are forced into strings, preventing us from using complex values such as a class with a custom __toString. This is a problem, as I need the ability to present the user with a list of display strings to choose from, but need the ID associated with that display string in order to do anything useful. Commits -------d276cc9ca3
[Console] Cast associative choices questions keys to stringa0223088a0
[Console] Add tests for removing restriction for choices to be strings3349d3ce89
Remove restriction for choices to be strings
This commit is contained in:
commit
d6468a9634
@ -169,7 +169,8 @@ class ChoiceQuestion extends Question
|
||||
throw new InvalidArgumentException(sprintf($errorMessage, $value));
|
||||
}
|
||||
|
||||
$multiselectChoices[] = (string) $result;
|
||||
// For associative choices, consistently return the key as string:
|
||||
$multiselectChoices[] = $isAssoc ? (string) $result : $result;
|
||||
}
|
||||
|
||||
if ($multiselect) {
|
||||
|
@ -607,41 +607,6 @@ EOD;
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider mixedKeysChoiceListAnswerProvider
|
||||
*/
|
||||
public function testChoiceFromChoicelistWithMixedKeys($providedAnswer, $expectedValue)
|
||||
{
|
||||
$possibleChoices = [
|
||||
'0' => 'No environment',
|
||||
'1' => 'My environment 1',
|
||||
'env_2' => 'My environment 2',
|
||||
3 => 'My environment 3',
|
||||
];
|
||||
|
||||
$dialog = new QuestionHelper();
|
||||
$helperSet = new HelperSet([new FormatterHelper()]);
|
||||
$dialog->setHelperSet($helperSet);
|
||||
|
||||
$question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
|
||||
$question->setMaxAttempts(1);
|
||||
$answer = $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream($providedAnswer."\n")), $this->createOutputInterface(), $question);
|
||||
|
||||
$this->assertSame($expectedValue, $answer);
|
||||
}
|
||||
|
||||
public function mixedKeysChoiceListAnswerProvider()
|
||||
{
|
||||
return [
|
||||
['0', '0'],
|
||||
['No environment', '0'],
|
||||
['1', '1'],
|
||||
['env_2', 'env_2'],
|
||||
[3, '3'],
|
||||
['My environment 1', '1'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider answerProvider
|
||||
*/
|
||||
|
@ -59,6 +59,18 @@ class ChoiceQuestionTest extends TestCase
|
||||
['First response', 'Second response'],
|
||||
'When passed multiple answers on MultiSelect, the defaultValidator must return these answers as an array',
|
||||
],
|
||||
[
|
||||
false,
|
||||
[0],
|
||||
'First response',
|
||||
'When passed single answer using choice\'s key, the defaultValidator must return the choice value',
|
||||
],
|
||||
[
|
||||
true,
|
||||
['0, 2'],
|
||||
['First response', 'Third response'],
|
||||
'When passed multiple answers using choices\' key, the defaultValidator must return the choice values in an array',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -77,4 +89,64 @@ class ChoiceQuestionTest extends TestCase
|
||||
|
||||
$this->assertSame(['First response ', ' Second response'], $question->getValidator()('First response , Second response'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider selectAssociativeChoicesProvider
|
||||
*/
|
||||
public function testSelectAssociativeChoices($providedAnswer, $expectedValue)
|
||||
{
|
||||
$question = new ChoiceQuestion('A question', [
|
||||
'0' => 'First choice',
|
||||
'foo' => 'Foo',
|
||||
'99' => 'N°99',
|
||||
'string object' => new StringChoice('String Object'),
|
||||
]);
|
||||
|
||||
$this->assertSame($expectedValue, $question->getValidator()($providedAnswer));
|
||||
}
|
||||
|
||||
public function selectAssociativeChoicesProvider()
|
||||
{
|
||||
return [
|
||||
'select "0" choice by key' => ['0', '0'],
|
||||
'select "0" choice by value' => ['First choice', '0'],
|
||||
'select by key' => ['foo', 'foo'],
|
||||
'select by value' => ['Foo', 'foo'],
|
||||
'select by key, with numeric key' => ['99', '99'],
|
||||
'select by value, with numeric key' => ['N°99', '99'],
|
||||
'select by key, with string object value' => ['string object', 'string object'],
|
||||
'select by value, with string object value' => ['String Object', 'string object'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testSelectWithNonStringChoices()
|
||||
{
|
||||
$question = new ChoiceQuestion('A question', [
|
||||
$result1 = new StringChoice('foo'),
|
||||
$result2 = new StringChoice('bar'),
|
||||
$result3 = new StringChoice('baz'),
|
||||
]);
|
||||
|
||||
$this->assertSame($result1, $question->getValidator()('foo'), 'answer can be selected by its string value');
|
||||
$this->assertSame($result1, $question->getValidator()(0), 'answer can be selected by index');
|
||||
|
||||
$question->setMultiselect(true);
|
||||
|
||||
$this->assertSame([$result3, $result2], $question->getValidator()('baz, bar'));
|
||||
}
|
||||
}
|
||||
|
||||
class StringChoice
|
||||
{
|
||||
private $string;
|
||||
|
||||
public function __construct(string $string)
|
||||
{
|
||||
$this->string = $string;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->string;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user