Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5d7678e

Browse filesBrowse files
webmozartfabpot
authored andcommitted
[Form] Deprecated setting "choices_as_values" to "false"
1 parent 5de9c35 commit 5d7678e
Copy full SHA for 5d7678e

File tree

13 files changed

+314
-53
lines changed
Filter options

13 files changed

+314
-53
lines changed

‎src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ public function __construct($choices, $value = null)
7474
$choices = iterator_to_array($choices);
7575
}
7676

77+
if (null === $value && $this->castableToString($choices)) {
78+
$value = function ($choice) {
79+
return (string) $choice;
80+
};
81+
}
82+
7783
if (null !== $value) {
7884
// If a deterministic value generator was passed, use it later
7985
$this->valueCallback = $value;
@@ -207,4 +213,35 @@ protected function flatten(array $choices, $value, &$choicesByValues, &$keysByVa
207213
$structuredValues[$key] = $choiceValue;
208214
}
209215
}
216+
217+
/**
218+
* Checks whether the given choices can be cast to strings without
219+
* generating duplicates.
220+
*
221+
* @param array $choices The choices.
222+
* @param array|null $cache The cache for previously checked entries. Internal
223+
*
224+
* @return bool Returns true if the choices can be cast to strings and
225+
* false otherwise.
226+
*/
227+
private function castableToString(array $choices, array &$cache = array())
228+
{
229+
foreach ($choices as $choice) {
230+
if (is_array($choice)) {
231+
if (!$this->castableToString($choice, $cache)) {
232+
return false;
233+
}
234+
235+
continue;
236+
} elseif (!is_scalar($choice)) {
237+
return false;
238+
} elseif (isset($cache[(string) $choice])) {
239+
return false;
240+
}
241+
242+
$cache[(string) $choice] = true;
243+
}
244+
245+
return true;
246+
}
210247
}

‎src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,14 @@ public function configureOptions(OptionsResolver $resolver)
281281
return $choiceListFactory->createListFromChoices($choices, $options['choice_value']);
282282
};
283283

284+
$choicesAsValuesNormalizer = function (Options $options, $choicesAsValues) {
285+
if (true !== $choicesAsValues) {
286+
@trigger_error('The value "false" for the "choices_as_values" option is deprecated since version 2.8 and will not be supported anymore in 3.0. Set this option to "true" and flip the contents of the "choices" option instead.', E_USER_DEPRECATED);
287+
}
288+
289+
return $choicesAsValues;
290+
};
291+
284292
$placeholderNormalizer = function (Options $options, $placeholder) {
285293
if (!is_object($options['empty_value']) || !$options['empty_value'] instanceof \Exception) {
286294
@trigger_error('The form option "empty_value" is deprecated since version 2.6 and will be removed in 3.0. Use "placeholder" instead.', E_USER_DEPRECATED);
@@ -343,6 +351,7 @@ public function configureOptions(OptionsResolver $resolver)
343351
$resolver->setNormalizer('choice_list', $choiceListNormalizer);
344352
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
345353
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
354+
$resolver->setNormalizer('choices_as_values', $choicesAsValuesNormalizer);
346355

347356
$resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'));
348357
$resolver->setAllowedTypes('choices', array('null', 'array', '\Traversable'));

‎src/Symfony/Component/Form/Extension/Core/Type/CountryType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/CountryType.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class CountryType extends AbstractType
2323
public function configureOptions(OptionsResolver $resolver)
2424
{
2525
$resolver->setDefaults(array(
26-
'choices' => Intl::getRegionBundle()->getCountryNames(),
26+
'choices' => array_flip(Intl::getRegionBundle()->getCountryNames()),
27+
'choices_as_values' => true,
2728
'choice_translation_domain' => false,
2829
));
2930
}

‎src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class CurrencyType extends AbstractType
2323
public function configureOptions(OptionsResolver $resolver)
2424
{
2525
$resolver->setDefaults(array(
26-
'choices' => Intl::getCurrencyBundle()->getCurrencyNames(),
26+
'choices' => array_flip(Intl::getCurrencyBundle()->getCurrencyNames()),
27+
'choices_as_values' => true,
2728
'choice_translation_domain' => false,
2829
));
2930
}

‎src/Symfony/Component/Form/Extension/Core/Type/DateType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/DateType.php
+10-6Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,15 @@ public function buildForm(FormBuilderInterface $builder, array $options)
9393
if ('choice' === $options['widget']) {
9494
// Only pass a subset of the options to children
9595
$yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years']));
96+
$yearOptions['choices_as_values'] = true;
9697
$yearOptions['placeholder'] = $options['placeholder']['year'];
9798
$yearOptions['choice_translation_domain'] = $options['choice_translation_domain']['year'];
9899
$monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months']));
100+
$monthOptions['choices_as_values'] = true;
99101
$monthOptions['placeholder'] = $options['placeholder']['month'];
100102
$monthOptions['choice_translation_domain'] = $options['choice_translation_domain']['month'];
101103
$dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days']));
104+
$dayOptions['choices_as_values'] = true;
102105
$dayOptions['placeholder'] = $options['placeholder']['day'];
103106
$dayOptions['choice_translation_domain'] = $options['choice_translation_domain']['day'];
104107
}
@@ -297,6 +300,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
297300
{
298301
$pattern = $formatter->getPattern();
299302
$timezone = $formatter->getTimezoneId();
303+
$formattedTimestamps = array();
300304

301305
if ($setTimeZone = PHP_VERSION_ID >= 50500 || method_exists($formatter, 'setTimeZone')) {
302306
$formatter->setTimeZone('UTC');
@@ -307,8 +311,8 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
307311
if (preg_match($regex, $pattern, $matches)) {
308312
$formatter->setPattern($matches[0]);
309313

310-
foreach ($timestamps as $key => $timestamp) {
311-
$timestamps[$key] = $formatter->format($timestamp);
314+
foreach ($timestamps as $timestamp => $choice) {
315+
$formattedTimestamps[$formatter->format($timestamp)] = $choice;
312316
}
313317

314318
// I'd like to clone the formatter above, but then we get a
@@ -322,7 +326,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
322326
$formatter->setTimeZoneId($timezone);
323327
}
324328

325-
return $timestamps;
329+
return $formattedTimestamps;
326330
}
327331

328332
private function listYears(array $years)
@@ -331,7 +335,7 @@ private function listYears(array $years)
331335

332336
foreach ($years as $year) {
333337
if (false !== $y = gmmktime(0, 0, 0, 6, 15, $year)) {
334-
$result[$year] = $y;
338+
$result[$y] = $year;
335339
}
336340
}
337341

@@ -343,7 +347,7 @@ private function listMonths(array $months)
343347
$result = array();
344348

345349
foreach ($months as $month) {
346-
$result[$month] = gmmktime(0, 0, 0, $month, 15);
350+
$result[gmmktime(0, 0, 0, $month, 15)] = $month;
347351
}
348352

349353
return $result;
@@ -354,7 +358,7 @@ private function listDays(array $days)
354358
$result = array();
355359

356360
foreach ($days as $day) {
357-
$result[$day] = gmmktime(0, 0, 0, 5, $day);
361+
$result[gmmktime(0, 0, 0, 5, $day)] = $day;
358362
}
359363

360364
return $result;

‎src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class LanguageType extends AbstractType
2323
public function configureOptions(OptionsResolver $resolver)
2424
{
2525
$resolver->setDefaults(array(
26-
'choices' => Intl::getLanguageBundle()->getLanguageNames(),
26+
'choices' => array_flip(Intl::getLanguageBundle()->getLanguageNames()),
27+
'choices_as_values' => true,
2728
'choice_translation_domain' => false,
2829
));
2930
}

‎src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class LocaleType extends AbstractType
2323
public function configureOptions(OptionsResolver $resolver)
2424
{
2525
$resolver->setDefaults(array(
26-
'choices' => Intl::getLocaleBundle()->getLocaleNames(),
26+
'choices' => array_flip(Intl::getLocaleBundle()->getLocaleNames()),
27+
'choices_as_values' => true,
2728
'choice_translation_domain' => false,
2829
));
2930
}

‎src/Symfony/Component/Form/Extension/Core/Type/TimeType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
+6-3Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,22 @@ public function buildForm(FormBuilderInterface $builder, array $options)
6363
$hours = $minutes = array();
6464

6565
foreach ($options['hours'] as $hour) {
66-
$hours[$hour] = str_pad($hour, 2, '0', STR_PAD_LEFT);
66+
$hours[str_pad($hour, 2, '0', STR_PAD_LEFT)] = $hour;
6767
}
6868

6969
// Only pass a subset of the options to children
7070
$hourOptions['choices'] = $hours;
71+
$hourOptions['choices_as_values'] = true;
7172
$hourOptions['placeholder'] = $options['placeholder']['hour'];
7273
$hourOptions['choice_translation_domain'] = $options['choice_translation_domain']['hour'];
7374

7475
if ($options['with_minutes']) {
7576
foreach ($options['minutes'] as $minute) {
76-
$minutes[$minute] = str_pad($minute, 2, '0', STR_PAD_LEFT);
77+
$minutes[str_pad($minute, 2, '0', STR_PAD_LEFT)] = $minute;
7778
}
7879

7980
$minuteOptions['choices'] = $minutes;
81+
$minuteOptions['choices_as_values'] = true;
8082
$minuteOptions['placeholder'] = $options['placeholder']['minute'];
8183
$minuteOptions['choice_translation_domain'] = $options['choice_translation_domain']['minute'];
8284
}
@@ -85,10 +87,11 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8587
$seconds = array();
8688

8789
foreach ($options['seconds'] as $second) {
88-
$seconds[$second] = str_pad($second, 2, '0', STR_PAD_LEFT);
90+
$seconds[str_pad($second, 2, '0', STR_PAD_LEFT)] = $second;
8991
}
9092

9193
$secondOptions['choices'] = $seconds;
94+
$secondOptions['choices_as_values'] = true;
9295
$secondOptions['placeholder'] = $options['placeholder']['second'];
9396
$secondOptions['choice_translation_domain'] = $options['choice_translation_domain']['second'];
9497
}

‎src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
+45-1Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,21 @@ class TimezoneType extends AbstractType
2323
*/
2424
private static $timezones;
2525

26+
/**
27+
* Stores the available timezone choices.
28+
*
29+
* @var array
30+
*/
31+
private static $flippedTimezones;
32+
2633
/**
2734
* {@inheritdoc}
2835
*/
2936
public function configureOptions(OptionsResolver $resolver)
3037
{
3138
$resolver->setDefaults(array(
32-
'choices' => self::getTimezones(),
39+
'choices' => self::getFlippedTimezones(),
40+
'choices_as_values' => true,
3341
'choice_translation_domain' => false,
3442
));
3543
}
@@ -93,4 +101,40 @@ public static function getTimezones()
93101

94102
return static::$timezones;
95103
}
104+
105+
/**
106+
* Returns the timezone choices.
107+
*
108+
* The choices are generated from the ICU function
109+
* \DateTimeZone::listIdentifiers(). They are cached during a single request,
110+
* so multiple timezone fields on the same page don't lead to unnecessary
111+
* overhead.
112+
*
113+
* @return array The timezone choices
114+
*/
115+
private static function getFlippedTimezones()
116+
{
117+
if (null === self::$timezones) {
118+
self::$timezones = array();
119+
120+
foreach (\DateTimeZone::listIdentifiers() as $timezone) {
121+
$parts = explode('/', $timezone);
122+
123+
if (count($parts) > 2) {
124+
$region = $parts[0];
125+
$name = $parts[1].' - '.$parts[2];
126+
} elseif (count($parts) > 1) {
127+
$region = $parts[0];
128+
$name = $parts[1];
129+
} else {
130+
$region = 'Other';
131+
$name = $parts[0];
132+
}
133+
134+
self::$timezones[$region][str_replace('_', ' ', $name)] = $timezone;
135+
}
136+
}
137+
138+
return self::$timezones;
139+
}
96140
}

‎src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php
+41-7Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,56 @@ public function testCreateChoiceListWithValueCallback()
6565
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz')));
6666
}
6767

68+
public function testCreateChoiceListWithoutValueCallbackAndDuplicateFreeToStringChoices()
69+
{
70+
$choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 123));
71+
72+
$this->assertSame(array('foo', 'bar', '123'), $choiceList->getValues());
73+
$this->assertSame(array('foo' => 'foo', 'bar' => 'bar', '123' => 123), $choiceList->getChoices());
74+
$this->assertSame(array('foo' => 2, 'bar' => 7, '123' => 10), $choiceList->getOriginalKeys());
75+
$this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => 'foo', 2 => '123')));
76+
$this->assertSame(array(1 => 'foo', 2 => '123'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123)));
77+
}
78+
79+
public function testCreateChoiceListWithoutValueCallbackAndToStringDuplicates()
80+
{
81+
$choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => '123', 10 => 123));
82+
83+
$this->assertSame(array('0', '1', '2'), $choiceList->getValues());
84+
$this->assertSame(array('0' => 'foo', '1' => '123', '2' => 123), $choiceList->getChoices());
85+
$this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys());
86+
$this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2')));
87+
$this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123)));
88+
}
89+
90+
public function testCreateChoiceListWithoutValueCallbackAndMixedChoices()
91+
{
92+
$object = new \stdClass();
93+
$choiceList = new ArrayChoiceList(array(2 => 'foo', 5 => array(7 => '123'), 10 => $object));
94+
95+
$this->assertSame(array('0', '1', '2'), $choiceList->getValues());
96+
$this->assertSame(array('0' => 'foo', '1' => '123', '2' => $object), $choiceList->getChoices());
97+
$this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys());
98+
$this->assertSame(array(1 => 'foo', 2 => $object), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2')));
99+
$this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => $object)));
100+
}
101+
68102
public function testCreateChoiceListWithGroupedChoices()
69103
{
70104
$choiceList = new ArrayChoiceList(array(
71105
'Group 1' => array('A' => 'a', 'B' => 'b'),
72106
'Group 2' => array('C' => 'c', 'D' => 'd'),
73107
));
74108

75-
$this->assertSame(array('0', '1', '2', '3'), $choiceList->getValues());
109+
$this->assertSame(array('a', 'b', 'c', 'd'), $choiceList->getValues());
76110
$this->assertSame(array(
77-
'Group 1' => array('A' => '0', 'B' => '1'),
78-
'Group 2' => array('C' => '2', 'D' => '3'),
111+
'Group 1' => array('A' => 'a', 'B' => 'b'),
112+
'Group 2' => array('C' => 'c', 'D' => 'd'),
79113
), $choiceList->getStructuredValues());
80-
$this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $choiceList->getChoices());
81-
$this->assertSame(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'), $choiceList->getOriginalKeys());
82-
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => '0', 2 => '1')));
83-
$this->assertSame(array(1 => '0', 2 => '1'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b')));
114+
$this->assertSame(array('a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd'), $choiceList->getChoices());
115+
$this->assertSame(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'), $choiceList->getOriginalKeys());
116+
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => 'a', 2 => 'b')));
117+
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b')));
84118
}
85119

86120
public function testCompareChoicesByIdentityByDefault()

‎src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ChoiceToValueTransformerTest extends \PHPUnit_Framework_TestCase
2020

2121
protected function setUp()
2222
{
23-
$list = new ArrayChoiceList(array('', 0, 'X'));
23+
$list = new ArrayChoiceList(array('', false, 'X'));
2424

2525
$this->transformer = new ChoiceToValueTransformer($list);
2626
}
@@ -35,7 +35,7 @@ public function transformProvider()
3535
return array(
3636
// more extensive test set can be found in FormUtilTest
3737
array('', '0'),
38-
array(0, '1'),
38+
array(false, '1'),
3939
);
4040
}
4141

@@ -53,7 +53,7 @@ public function reverseTransformProvider()
5353
// values are expected to be valid choice keys already and stay
5454
// the same
5555
array('0', ''),
56-
array('1', 0),
56+
array('1', false),
5757
array('2', 'X'),
5858
);
5959
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.