@@ -30,14 +30,21 @@ class ArrayChoiceList implements ChoiceListInterface
30
30
*
31
31
* @var array
32
32
*/
33
- protected $ choices = array () ;
33
+ protected $ choices ;
34
34
35
35
/**
36
- * The values of the choices .
36
+ * The values indexed by the original keys .
37
37
*
38
- * @var string[]
38
+ * @var array
39
+ */
40
+ protected $ structuredValues ;
41
+
42
+ /**
43
+ * The original keys of the choices array.
44
+ *
45
+ * @var int[]|string[]
39
46
*/
40
- protected $ values = array () ;
47
+ protected $ originalKeys ;
41
48
42
49
/**
43
50
* The callback for creating the value for a choice.
@@ -51,31 +58,41 @@ class ArrayChoiceList implements ChoiceListInterface
51
58
*
52
59
* The given choice array must have the same array keys as the value array.
53
60
*
54
- * @param array $choices The selectable choices
55
- * @param callable|null $value The callable for creating the value for a
56
- * choice. If `null` is passed, incrementing
57
- * integers are used as values
61
+ * @param array|\Traversable $choices The selectable choices
62
+ * @param callable|null $value The callable for creating the value
63
+ * for a choice. If `null` is passed,
64
+ * incrementing integers are used as
65
+ * values
58
66
*/
59
- public function __construct (array $ choices , $ value = null )
67
+ public function __construct ($ choices , $ value = null )
60
68
{
61
69
if (null !== $ value && !is_callable ($ value )) {
62
70
throw new UnexpectedTypeException ($ value , 'null or callable ' );
63
71
}
64
72
65
- $ this -> choices = $ choices ;
66
- $ this -> values = array ( );
67
- $ this -> valueCallback = $ value ;
73
+ if ( $ choices instanceof \Traversable) {
74
+ $ choices = iterator_to_array ( $ choices );
75
+ }
68
76
69
- if (null === $ value ) {
70
- $ i = 0 ;
71
- foreach ($ this ->choices as $ key => $ choice ) {
72
- $ this ->values [$ key ] = (string ) $ i ++;
73
- }
77
+ if (null !== $ value ) {
78
+ // If a deterministic value generator was passed, use it later
79
+ $ this ->valueCallback = $ value ;
74
80
} else {
75
- foreach ($ choices as $ key => $ choice ) {
76
- $ this ->values [$ key ] = (string ) call_user_func ($ value , $ choice );
77
- }
81
+ // Otherwise simply generate incrementing integers as values
82
+ $ i = 0 ;
83
+ $ value = function () use (&$ i ) {
84
+ return $ i ++;
85
+ };
78
86
}
87
+
88
+ // If the choices are given as recursive array (i.e. with explicit
89
+ // choice groups), flatten the array. The grouping information is needed
90
+ // in the view only.
91
+ $ this ->flatten ($ choices , $ value , $ choicesByValues , $ keysByValues , $ structuredValues );
92
+
93
+ $ this ->choices = $ choicesByValues ;
94
+ $ this ->originalKeys = $ keysByValues ;
95
+ $ this ->structuredValues = $ structuredValues ;
79
96
}
80
97
81
98
/**
@@ -91,7 +108,23 @@ public function getChoices()
91
108
*/
92
109
public function getValues ()
93
110
{
94
- return $ this ->values ;
111
+ return array_map ('strval ' , array_keys ($ this ->choices ));
112
+ }
113
+
114
+ /**
115
+ * {@inheritdoc}
116
+ */
117
+ public function getStructuredValues ()
118
+ {
119
+ return $ this ->structuredValues ;
120
+ }
121
+
122
+ /**
123
+ * {@inheritdoc}
124
+ */
125
+ public function getOriginalKeys ()
126
+ {
127
+ return $ this ->originalKeys ;
95
128
}
96
129
97
130
/**
@@ -102,17 +135,8 @@ public function getChoicesForValues(array $values)
102
135
$ choices = array ();
103
136
104
137
foreach ($ values as $ i => $ givenValue ) {
105
- foreach ($ this ->values as $ j => $ value ) {
106
- if ($ value !== (string ) $ givenValue ) {
107
- continue ;
108
- }
109
-
110
- $ choices [$ i ] = $ this ->choices [$ j ];
111
- unset($ values [$ i ]);
112
-
113
- if (0 === count ($ values )) {
114
- break 2 ;
115
- }
138
+ if (isset ($ this ->choices [$ givenValue ])) {
139
+ $ choices [$ i ] = $ this ->choices [$ givenValue ];
116
140
}
117
141
}
118
142
@@ -131,28 +155,56 @@ public function getValuesForChoices(array $choices)
131
155
$ givenValues = array ();
132
156
133
157
foreach ($ choices as $ i => $ givenChoice ) {
134
- $ givenValues [$ i ] = ( string ) call_user_func ($ this ->valueCallback , $ givenChoice );
158
+ $ givenValues [$ i ] = call_user_func ($ this ->valueCallback , $ givenChoice );
135
159
}
136
160
137
- return array_intersect ($ givenValues , $ this ->values );
161
+ return array_intersect ($ givenValues , array_keys ( $ this ->choices ) );
138
162
}
139
163
140
164
// Otherwise compare choices by identity
141
165
foreach ($ choices as $ i => $ givenChoice ) {
142
- foreach ($ this ->choices as $ j => $ choice ) {
143
- if ($ choice !== $ givenChoice ) {
144
- continue ;
145
- }
146
-
147
- $ values [$ i ] = $ this ->values [$ j ];
148
- unset($ choices [$ i ]);
149
-
150
- if (0 === count ($ choices )) {
151
- break 2 ;
166
+ foreach ($ this ->choices as $ value => $ choice ) {
167
+ if ($ choice === $ givenChoice ) {
168
+ $ values [$ i ] = (string ) $ value ;
169
+ break ;
152
170
}
153
171
}
154
172
}
155
173
156
174
return $ values ;
157
175
}
176
+
177
+ /**
178
+ * Flattens an array into the given output variables.
179
+ *
180
+ * @param array $choices The array to flatten
181
+ * @param callable $value The callable for generating choice values
182
+ * @param array $choicesByValues The flattened choices indexed by the
183
+ * corresponding values
184
+ * @param array $keysByValues The original keys indexed by the
185
+ * corresponding values
186
+ *
187
+ * @internal Must not be used by user-land code
188
+ */
189
+ protected function flatten (array $ choices , $ value , &$ choicesByValues , &$ keysByValues , &$ structuredValues )
190
+ {
191
+ if (null === $ choicesByValues ) {
192
+ $ choicesByValues = array ();
193
+ $ keysByValues = array ();
194
+ $ structuredValues = array ();
195
+ }
196
+
197
+ foreach ($ choices as $ key => $ choice ) {
198
+ if (is_array ($ choice )) {
199
+ $ this ->flatten ($ choice , $ value , $ choicesByValues , $ keysByValues , $ structuredValues [$ key ]);
200
+
201
+ continue ;
202
+ }
203
+
204
+ $ choiceValue = (string ) call_user_func ($ value , $ choice );
205
+ $ choicesByValues [$ choiceValue ] = $ choice ;
206
+ $ keysByValues [$ choiceValue ] = $ key ;
207
+ $ structuredValues [$ key ] = $ choiceValue ;
208
+ }
209
+ }
158
210
}
0 commit comments