Skip to content

Commit c1c9633

Browse files
Allow selection of a choice by the data of a choice
1 parent 47a4658 commit c1c9633

File tree

3 files changed

+90
-26
lines changed

3 files changed

+90
-26
lines changed

features/interactive.feature

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,22 @@ Feature: It is possible to interactively fill in a form from the CLI
7272
[color] => blue
7373
)
7474
"""
75+
76+
@symfony27
77+
Scenario: Select a value by its underlying data
78+
When I run the command "form:color_with_choices_as_values" and I provide as input
79+
"""
80+
red[enter]
81+
"""
82+
Then the command has finished successfully
83+
And the output should be
84+
"""
85+
Select color [red]:
86+
[0] Red
87+
[1] Blue
88+
[2] Yellow
89+
> Array
90+
(
91+
[color] => red
92+
)
93+
"""

src/Bridge/Transformer/ChoiceTransformer.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,7 @@ public function transform(Form $form)
1111
{
1212
$formView = $form->createView();
1313

14-
$choices = [];
15-
foreach ($formView->vars['choices'] as $choiceView) {
16-
$choices[$choiceView->value] = $choiceView->label;
17-
}
18-
19-
$question = new AlwaysReturnKeyOfChoiceQuestion($this->questionFrom($form), $choices, $this->defaultValueFrom($form));
14+
$question = new AlwaysReturnKeyOfChoiceQuestion($this->questionFrom($form), $formView->vars['choices'], $this->defaultValueFrom($form));
2015

2116
if ($form->getConfig()->getOption('multiple')) {
2217
$question->setMultiselect(true);

src/Console/Helper/Question/AlwaysReturnKeyOfChoiceQuestion.php

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,34 @@
33
namespace Matthias\SymfonyConsoleForm\Console\Helper\Question;
44

55
use Symfony\Component\Console\Question\ChoiceQuestion;
6+
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
67

78
class AlwaysReturnKeyOfChoiceQuestion extends ChoiceQuestion
89
{
10+
/**
11+
* @var ChoiceView[]
12+
*/
13+
private $choiceViews;
914
private $_multiselect = false;
1015

1116
private $_errorMessage = 'Value "%s" is invalid';
1217

18+
public function __construct($question, array $choiceViews, $default = null)
19+
{
20+
\Assert\that($choiceViews)
21+
->all()
22+
->isInstanceOf(
23+
'Symfony\Component\Form\Extension\Core\View\ChoiceView',
24+
'Only a flat choice hierarchy is supported'
25+
);
26+
27+
$this->choiceViews = $choiceViews;
28+
29+
parent::__construct($question, $this->prepareChoices(), $default);
30+
31+
$this->setAutocompleterValues($this->prepareAutocompleteValues());
32+
}
33+
1334
public function setMultiselect($multiselect)
1435
{
1536
$this->_multiselect = $multiselect;
@@ -26,18 +47,14 @@ public function setErrorMessage($errorMessage)
2647

2748
public function getValidator()
2849
{
29-
$choices = $this->getChoices();
30-
$errorMessage = $this->_errorMessage;
31-
$multiselect = $this->_multiselect;
32-
33-
return function ($selected) use ($choices, $errorMessage, $multiselect) {
50+
return function ($selected) {
3451
// Collapse all spaces.
3552
$selectedChoices = str_replace(' ', '', $selected);
3653

37-
if ($multiselect) {
54+
if ($this->_multiselect) {
3855
// Check for a separated comma values
3956
if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
40-
throw new \InvalidArgumentException(sprintf($errorMessage, $selected));
57+
throw new \InvalidArgumentException(sprintf($this->_errorMessage, $selected));
4158
}
4259
$selectedChoices = explode(',', $selectedChoices);
4360
} else {
@@ -46,25 +63,58 @@ public function getValidator()
4663

4764
$selectedKeys = array();
4865

49-
foreach ($selectedChoices as $value) {
50-
if (array_key_exists($value, $choices)) {
51-
$selectedKeys[] = $value;
52-
continue;
53-
}
54-
55-
$key = array_search($value, $choices);
56-
if ($key === false) {
57-
throw new \InvalidArgumentException(sprintf($errorMessage, $value));
58-
}
59-
60-
$selectedKeys[] = $key;
66+
foreach ($selectedChoices as $selectedValue) {
67+
$selectedKeys[] = $this->resolveChoiceViewValue($selectedValue);
6168
}
6269

63-
if ($multiselect) {
70+
if ($this->_multiselect) {
6471
return $selectedKeys;
6572
}
6673

6774
return current($selectedKeys);
6875
};
6976
}
77+
78+
/**
79+
* @param string $selectedValue The selected value
80+
* @return string The corresponding value of the ChoiceView
81+
*/
82+
private function resolveChoiceViewValue($selectedValue)
83+
{
84+
foreach ($this->choiceViews as $choiceView) {
85+
if (in_array($selectedValue, [$choiceView->data, $choiceView->value, $choiceView->label])) {
86+
return $choiceView->value;
87+
}
88+
}
89+
90+
throw new \InvalidArgumentException(sprintf($this->_errorMessage, $selectedValue));
91+
}
92+
93+
private function prepareChoices()
94+
{
95+
$choices = [];
96+
foreach ($this->choiceViews as $choiceView) {
97+
$label = $choiceView->label;
98+
if ($choiceView->data != $choiceView->value) {
99+
$label .= ' (<comment>' . $choiceView->data . '</comment>)';
100+
}
101+
102+
$choices[$choiceView->value] = $label;
103+
}
104+
105+
return $choices;
106+
}
107+
108+
private function prepareAutocompleteValues()
109+
{
110+
$autocompleteValues = array();
111+
112+
foreach ($this->choiceViews as $choiceView) {
113+
$autocompleteValues[] = $choiceView->value;
114+
$autocompleteValues[] = $choiceView->data;
115+
$autocompleteValues[] = $choiceView->label;
116+
}
117+
118+
return $autocompleteValues;
119+
}
70120
}

0 commit comments

Comments
 (0)