33namespace Matthias \SymfonyConsoleForm \Console \Helper \Question ;
44
55use Symfony \Component \Console \Question \ChoiceQuestion ;
6+ use Symfony \Component \Form \Extension \Core \View \ChoiceView ;
67
78class 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