diff options
Diffstat (limited to 'vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php')
-rw-r--r-- | vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php | 510 |
1 files changed, 0 insertions, 510 deletions
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php deleted file mode 100644 index f9d381cd..00000000 --- a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php +++ /dev/null | |||
@@ -1,510 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of the Symfony package. | ||
5 | * | ||
6 | * (c) Fabien Potencier <fabien@symfony.com> | ||
7 | * | ||
8 | * For the full copyright and license information, please view the LICENSE | ||
9 | * file that was distributed with this source code. | ||
10 | */ | ||
11 | |||
12 | namespace Symfony\Component\Form\Extension\Core\ChoiceList; | ||
13 | |||
14 | use Symfony\Component\Form\FormConfigBuilder; | ||
15 | use Symfony\Component\Form\Exception\UnexpectedTypeException; | ||
16 | use Symfony\Component\Form\Exception\InvalidConfigurationException; | ||
17 | use Symfony\Component\Form\Exception\InvalidArgumentException; | ||
18 | use Symfony\Component\Form\Extension\Core\View\ChoiceView; | ||
19 | |||
20 | /** | ||
21 | * A choice list for choices of arbitrary data types. | ||
22 | * | ||
23 | * Choices and labels are passed in two arrays. The indices of the choices | ||
24 | * and the labels should match. Choices may also be given as hierarchy of | ||
25 | * unlimited depth by creating nested arrays. The title of the sub-hierarchy | ||
26 | * can be stored in the array key pointing to the nested array. The topmost | ||
27 | * level of the hierarchy may also be a \Traversable. | ||
28 | * | ||
29 | * <code> | ||
30 | * $choices = array(true, false); | ||
31 | * $labels = array('Agree', 'Disagree'); | ||
32 | * $choiceList = new ChoiceList($choices, $labels); | ||
33 | * </code> | ||
34 | * | ||
35 | * @author Bernhard Schussek <bschussek@gmail.com> | ||
36 | */ | ||
37 | class ChoiceList implements ChoiceListInterface | ||
38 | { | ||
39 | /** | ||
40 | * The choices with their indices as keys. | ||
41 | * | ||
42 | * @var array | ||
43 | */ | ||
44 | private $choices = array(); | ||
45 | |||
46 | /** | ||
47 | * The choice values with the indices of the matching choices as keys. | ||
48 | * | ||
49 | * @var array | ||
50 | */ | ||
51 | private $values = array(); | ||
52 | |||
53 | /** | ||
54 | * The preferred view objects as hierarchy containing also the choice groups | ||
55 | * with the indices of the matching choices as bottom-level keys. | ||
56 | * | ||
57 | * @var array | ||
58 | */ | ||
59 | private $preferredViews = array(); | ||
60 | |||
61 | /** | ||
62 | * The non-preferred view objects as hierarchy containing also the choice | ||
63 | * groups with the indices of the matching choices as bottom-level keys. | ||
64 | * | ||
65 | * @var array | ||
66 | */ | ||
67 | private $remainingViews = array(); | ||
68 | |||
69 | /** | ||
70 | * Creates a new choice list. | ||
71 | * | ||
72 | * @param array|\Traversable $choices The array of choices. Choices may also be given | ||
73 | * as hierarchy of unlimited depth. Hierarchies are | ||
74 | * created by creating nested arrays. The title of | ||
75 | * the sub-hierarchy can be stored in the array | ||
76 | * key pointing to the nested array. The topmost | ||
77 | * level of the hierarchy may also be a \Traversable. | ||
78 | * @param array $labels The array of labels. The structure of this array | ||
79 | * should match the structure of $choices. | ||
80 | * @param array $preferredChoices A flat array of choices that should be | ||
81 | * presented to the user with priority. | ||
82 | * | ||
83 | * @throws UnexpectedTypeException If the choices are not an array or \Traversable. | ||
84 | */ | ||
85 | public function __construct($choices, array $labels, array $preferredChoices = array()) | ||
86 | { | ||
87 | if (!is_array($choices) && !$choices instanceof \Traversable) { | ||
88 | throw new UnexpectedTypeException($choices, 'array or \Traversable'); | ||
89 | } | ||
90 | |||
91 | $this->initialize($choices, $labels, $preferredChoices); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Initializes the list with choices. | ||
96 | * | ||
97 | * Safe to be called multiple times. The list is cleared on every call. | ||
98 | * | ||
99 | * @param array|\Traversable $choices The choices to write into the list. | ||
100 | * @param array $labels The labels belonging to the choices. | ||
101 | * @param array $preferredChoices The choices to display with priority. | ||
102 | */ | ||
103 | protected function initialize($choices, array $labels, array $preferredChoices) | ||
104 | { | ||
105 | $this->choices = array(); | ||
106 | $this->values = array(); | ||
107 | $this->preferredViews = array(); | ||
108 | $this->remainingViews = array(); | ||
109 | |||
110 | $this->addChoices( | ||
111 | $this->preferredViews, | ||
112 | $this->remainingViews, | ||
113 | $choices, | ||
114 | $labels, | ||
115 | $preferredChoices | ||
116 | ); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * {@inheritdoc} | ||
121 | */ | ||
122 | public function getChoices() | ||
123 | { | ||
124 | return $this->choices; | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * {@inheritdoc} | ||
129 | */ | ||
130 | public function getValues() | ||
131 | { | ||
132 | return $this->values; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * {@inheritdoc} | ||
137 | */ | ||
138 | public function getPreferredViews() | ||
139 | { | ||
140 | return $this->preferredViews; | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * {@inheritdoc} | ||
145 | */ | ||
146 | public function getRemainingViews() | ||
147 | { | ||
148 | return $this->remainingViews; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * {@inheritdoc} | ||
153 | */ | ||
154 | public function getChoicesForValues(array $values) | ||
155 | { | ||
156 | $values = $this->fixValues($values); | ||
157 | $choices = array(); | ||
158 | |||
159 | foreach ($values as $j => $givenValue) { | ||
160 | foreach ($this->values as $i => $value) { | ||
161 | if ($value === $givenValue) { | ||
162 | $choices[] = $this->choices[$i]; | ||
163 | unset($values[$j]); | ||
164 | |||
165 | if (0 === count($values)) { | ||
166 | break 2; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | return $choices; | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * {@inheritdoc} | ||
177 | */ | ||
178 | public function getValuesForChoices(array $choices) | ||
179 | { | ||
180 | $choices = $this->fixChoices($choices); | ||
181 | $values = array(); | ||
182 | |||
183 | foreach ($this->choices as $i => $choice) { | ||
184 | foreach ($choices as $j => $givenChoice) { | ||
185 | if ($choice === $givenChoice) { | ||
186 | $values[] = $this->values[$i]; | ||
187 | unset($choices[$j]); | ||
188 | |||
189 | if (0 === count($choices)) { | ||
190 | break 2; | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
196 | return $values; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * {@inheritdoc} | ||
201 | */ | ||
202 | public function getIndicesForChoices(array $choices) | ||
203 | { | ||
204 | $choices = $this->fixChoices($choices); | ||
205 | $indices = array(); | ||
206 | |||
207 | foreach ($this->choices as $i => $choice) { | ||
208 | foreach ($choices as $j => $givenChoice) { | ||
209 | if ($choice === $givenChoice) { | ||
210 | $indices[] = $i; | ||
211 | unset($choices[$j]); | ||
212 | |||
213 | if (0 === count($choices)) { | ||
214 | break 2; | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | return $indices; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * {@inheritdoc} | ||
225 | */ | ||
226 | public function getIndicesForValues(array $values) | ||
227 | { | ||
228 | $values = $this->fixValues($values); | ||
229 | $indices = array(); | ||
230 | |||
231 | foreach ($this->values as $i => $value) { | ||
232 | foreach ($values as $j => $givenValue) { | ||
233 | if ($value === $givenValue) { | ||
234 | $indices[] = $i; | ||
235 | unset($values[$j]); | ||
236 | |||
237 | if (0 === count($values)) { | ||
238 | break 2; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
244 | return $indices; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * Recursively adds the given choices to the list. | ||
249 | * | ||
250 | * @param array $bucketForPreferred The bucket where to store the preferred | ||
251 | * view objects. | ||
252 | * @param array $bucketForRemaining The bucket where to store the | ||
253 | * non-preferred view objects. | ||
254 | * @param array|\Traversable $choices The list of choices. | ||
255 | * @param array $labels The labels corresponding to the choices. | ||
256 | * @param array $preferredChoices The preferred choices. | ||
257 | * | ||
258 | * @throws InvalidArgumentException If the structures of the choices and labels array do not match. | ||
259 | * @throws InvalidConfigurationException If no valid value or index could be created for a choice. | ||
260 | */ | ||
261 | protected function addChoices(array &$bucketForPreferred, array &$bucketForRemaining, $choices, array $labels, array $preferredChoices) | ||
262 | { | ||
263 | // Add choices to the nested buckets | ||
264 | foreach ($choices as $group => $choice) { | ||
265 | if (!array_key_exists($group, $labels)) { | ||
266 | throw new InvalidArgumentException('The structures of the choices and labels array do not match.'); | ||
267 | } | ||
268 | |||
269 | if (is_array($choice)) { | ||
270 | // Don't do the work if the array is empty | ||
271 | if (count($choice) > 0) { | ||
272 | $this->addChoiceGroup( | ||
273 | $group, | ||
274 | $bucketForPreferred, | ||
275 | $bucketForRemaining, | ||
276 | $choice, | ||
277 | $labels[$group], | ||
278 | $preferredChoices | ||
279 | ); | ||
280 | } | ||
281 | } else { | ||
282 | $this->addChoice( | ||
283 | $bucketForPreferred, | ||
284 | $bucketForRemaining, | ||
285 | $choice, | ||
286 | $labels[$group], | ||
287 | $preferredChoices | ||
288 | ); | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * Recursively adds a choice group. | ||
295 | * | ||
296 | * @param string $group The name of the group. | ||
297 | * @param array $bucketForPreferred The bucket where to store the preferred | ||
298 | * view objects. | ||
299 | * @param array $bucketForRemaining The bucket where to store the | ||
300 | * non-preferred view objects. | ||
301 | * @param array $choices The list of choices in the group. | ||
302 | * @param array $labels The labels corresponding to the choices in the group. | ||
303 | * @param array $preferredChoices The preferred choices. | ||
304 | * | ||
305 | * @throws InvalidConfigurationException If no valid value or index could be created for a choice. | ||
306 | */ | ||
307 | protected function addChoiceGroup($group, array &$bucketForPreferred, array &$bucketForRemaining, array $choices, array $labels, array $preferredChoices) | ||
308 | { | ||
309 | // If this is a choice group, create a new level in the choice | ||
310 | // key hierarchy | ||
311 | $bucketForPreferred[$group] = array(); | ||
312 | $bucketForRemaining[$group] = array(); | ||
313 | |||
314 | $this->addChoices( | ||
315 | $bucketForPreferred[$group], | ||
316 | $bucketForRemaining[$group], | ||
317 | $choices, | ||
318 | $labels, | ||
319 | $preferredChoices | ||
320 | ); | ||
321 | |||
322 | // Remove child levels if empty | ||
323 | if (empty($bucketForPreferred[$group])) { | ||
324 | unset($bucketForPreferred[$group]); | ||
325 | } | ||
326 | if (empty($bucketForRemaining[$group])) { | ||
327 | unset($bucketForRemaining[$group]); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * Adds a new choice. | ||
333 | * | ||
334 | * @param array $bucketForPreferred The bucket where to store the preferred | ||
335 | * view objects. | ||
336 | * @param array $bucketForRemaining The bucket where to store the | ||
337 | * non-preferred view objects. | ||
338 | * @param mixed $choice The choice to add. | ||
339 | * @param string $label The label for the choice. | ||
340 | * @param array $preferredChoices The preferred choices. | ||
341 | * | ||
342 | * @throws InvalidConfigurationException If no valid value or index could be created. | ||
343 | */ | ||
344 | protected function addChoice(array &$bucketForPreferred, array &$bucketForRemaining, $choice, $label, array $preferredChoices) | ||
345 | { | ||
346 | $index = $this->createIndex($choice); | ||
347 | |||
348 | if ('' === $index || null === $index || !FormConfigBuilder::isValidName((string) $index)) { | ||
349 | throw new InvalidConfigurationException(sprintf('The index "%s" created by the choice list is invalid. It should be a valid, non-empty Form name.', $index)); | ||
350 | } | ||
351 | |||
352 | $value = $this->createValue($choice); | ||
353 | |||
354 | if (!is_string($value)) { | ||
355 | throw new InvalidConfigurationException(sprintf('The value created by the choice list is of type "%s", but should be a string.', gettype($value))); | ||
356 | } | ||
357 | |||
358 | $view = new ChoiceView($choice, $value, $label); | ||
359 | |||
360 | $this->choices[$index] = $this->fixChoice($choice); | ||
361 | $this->values[$index] = $value; | ||
362 | |||
363 | if ($this->isPreferred($choice, $preferredChoices)) { | ||
364 | $bucketForPreferred[$index] = $view; | ||
365 | } else { | ||
366 | $bucketForRemaining[$index] = $view; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | /** | ||
371 | * Returns whether the given choice should be preferred judging by the | ||
372 | * given array of preferred choices. | ||
373 | * | ||
374 | * Extension point to optimize performance by changing the structure of the | ||
375 | * $preferredChoices array. | ||
376 | * | ||
377 | * @param mixed $choice The choice to test. | ||
378 | * @param array $preferredChoices An array of preferred choices. | ||
379 | * | ||
380 | * @return Boolean Whether the choice is preferred. | ||
381 | */ | ||
382 | protected function isPreferred($choice, array $preferredChoices) | ||
383 | { | ||
384 | return false !== array_search($choice, $preferredChoices, true); | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * Creates a new unique index for this choice. | ||
389 | * | ||
390 | * Extension point to change the indexing strategy. | ||
391 | * | ||
392 | * @param mixed $choice The choice to create an index for | ||
393 | * | ||
394 | * @return integer|string A unique index containing only ASCII letters, | ||
395 | * digits and underscores. | ||
396 | */ | ||
397 | protected function createIndex($choice) | ||
398 | { | ||
399 | return count($this->choices); | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * Creates a new unique value for this choice. | ||
404 | * | ||
405 | * By default, an integer is generated since it cannot be guaranteed that | ||
406 | * all values in the list are convertible to (unique) strings. Subclasses | ||
407 | * can override this behaviour if they can guarantee this property. | ||
408 | * | ||
409 | * @param mixed $choice The choice to create a value for | ||
410 | * | ||
411 | * @return string A unique string. | ||
412 | */ | ||
413 | protected function createValue($choice) | ||
414 | { | ||
415 | return (string) count($this->values); | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * Fixes the data type of the given choice value to avoid comparison | ||
420 | * problems. | ||
421 | * | ||
422 | * @param mixed $value The choice value. | ||
423 | * | ||
424 | * @return string The value as string. | ||
425 | */ | ||
426 | protected function fixValue($value) | ||
427 | { | ||
428 | return (string) $value; | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * Fixes the data types of the given choice values to avoid comparison | ||
433 | * problems. | ||
434 | * | ||
435 | * @param array $values The choice values. | ||
436 | * | ||
437 | * @return array The values as strings. | ||
438 | */ | ||
439 | protected function fixValues(array $values) | ||
440 | { | ||
441 | foreach ($values as $i => $value) { | ||
442 | $values[$i] = $this->fixValue($value); | ||
443 | } | ||
444 | |||
445 | return $values; | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * Fixes the data type of the given choice index to avoid comparison | ||
450 | * problems. | ||
451 | * | ||
452 | * @param mixed $index The choice index. | ||
453 | * | ||
454 | * @return integer|string The index as PHP array key. | ||
455 | */ | ||
456 | protected function fixIndex($index) | ||
457 | { | ||
458 | if (is_bool($index) || (string) (int) $index === (string) $index) { | ||
459 | return (int) $index; | ||
460 | } | ||
461 | |||
462 | return (string) $index; | ||
463 | } | ||
464 | |||
465 | /** | ||
466 | * Fixes the data types of the given choice indices to avoid comparison | ||
467 | * problems. | ||
468 | * | ||
469 | * @param array $indices The choice indices. | ||
470 | * | ||
471 | * @return array The indices as strings. | ||
472 | */ | ||
473 | protected function fixIndices(array $indices) | ||
474 | { | ||
475 | foreach ($indices as $i => $index) { | ||
476 | $indices[$i] = $this->fixIndex($index); | ||
477 | } | ||
478 | |||
479 | return $indices; | ||
480 | } | ||
481 | |||
482 | /** | ||
483 | * Fixes the data type of the given choice to avoid comparison problems. | ||
484 | * | ||
485 | * Extension point. In this implementation, choices are guaranteed to | ||
486 | * always maintain their type and thus can be typesafely compared. | ||
487 | * | ||
488 | * @param mixed $choice The choice. | ||
489 | * | ||
490 | * @return mixed The fixed choice. | ||
491 | */ | ||
492 | protected function fixChoice($choice) | ||
493 | { | ||
494 | return $choice; | ||
495 | } | ||
496 | |||
497 | /** | ||
498 | * Fixes the data type of the given choices to avoid comparison problems. | ||
499 | * | ||
500 | * @param array $choices The choices. | ||
501 | * | ||
502 | * @return array The fixed choices. | ||
503 | * | ||
504 | * @see fixChoice | ||
505 | */ | ||
506 | protected function fixChoices(array $choices) | ||
507 | { | ||
508 | return $choices; | ||
509 | } | ||
510 | } | ||