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 721d09f

Browse filesBrowse files
committed
[Form] Deprecated setting "choices_as_values" to "false"
1 parent d1a50a2 commit 721d09f
Copy full SHA for 721d09f

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
@@ -88,10 +88,13 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8888
if ('choice' === $options['widget']) {
8989
// Only pass a subset of the options to children
9090
$yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years']));
91+
$yearOptions['choices_as_values'] = true;
9192
$yearOptions['placeholder'] = $options['placeholder']['year'];
9293
$monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months']));
94+
$monthOptions['choices_as_values'] = true;
9395
$monthOptions['placeholder'] = $options['placeholder']['month'];
9496
$dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days']));
97+
$dayOptions['choices_as_values'] = true;
9598
$dayOptions['placeholder'] = $options['placeholder']['day'];
9699
}
97100

@@ -262,6 +265,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
262265
{
263266
$pattern = $formatter->getPattern();
264267
$timezone = $formatter->getTimezoneId();
268+
$formattedTimestamps = array();
265269

266270
if ($setTimeZone = PHP_VERSION_ID >= 50500 || method_exists($formatter, 'setTimeZone')) {
267271
$formatter->setTimeZone('UTC');
@@ -272,8 +276,8 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
272276
if (preg_match($regex, $pattern, $matches)) {
273277
$formatter->setPattern($matches[0]);
274278

275-
foreach ($timestamps as $key => $timestamp) {
276-
$timestamps[$key] = $formatter->format($timestamp);
279+
foreach ($timestamps as $timestamp => $choice) {
280+
$formattedTimestamps[$formatter->format($timestamp)] = $choice;
277281
}
278282

279283
// I'd like to clone the formatter above, but then we get a
@@ -287,7 +291,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
287291
$formatter->setTimeZoneId($timezone);
288292
}
289293

290-
return $timestamps;
294+
return $formattedTimestamps;
291295
}
292296

293297
private function listYears(array $years)
@@ -296,7 +300,7 @@ private function listYears(array $years)
296300

297301
foreach ($years as $year) {
298302
if (false !== $y = gmmktime(0, 0, 0, 6, 15, $year)) {
299-
$result[$year] = $y;
303+
$result[$y] = $year;
300304
}
301305
}
302306

@@ -308,7 +312,7 @@ private function listMonths(array $months)
308312
$result = array();
309313

310314
foreach ($months as $month) {
311-
$result[$month] = gmmktime(0, 0, 0, $month, 15);
315+
$result[gmmktime(0, 0, 0, $month, 15)] = $month;
312316
}
313317

314318
return $result;
@@ -319,7 +323,7 @@ private function listDays(array $days)
319323
$result = array();
320324

321325
foreach ($days as $day) {
322-
$result[$day] = gmmktime(0, 0, 0, 5, $day);
326+
$result[gmmktime(0, 0, 0, 5, $day)] = $day;
323327
}
324328

325329
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
@@ -58,30 +58,33 @@ public function buildForm(FormBuilderInterface $builder, array $options)
5858
$hours = $minutes = array();
5959

6060
foreach ($options['hours'] as $hour) {
61-
$hours[$hour] = str_pad($hour, 2, '0', STR_PAD_LEFT);
61+
$hours[str_pad($hour, 2, '0', STR_PAD_LEFT)] = $hour;
6262
}
6363

6464
// Only pass a subset of the options to children
6565
$hourOptions['choices'] = $hours;
66+
$hourOptions['choices_as_values'] = true;
6667
$hourOptions['placeholder'] = $options['placeholder']['hour'];
6768

6869
if ($options['with_minutes']) {
6970
foreach ($options['minutes'] as $minute) {
70-
$minutes[$minute] = str_pad($minute, 2, '0', STR_PAD_LEFT);
71+
$minutes[str_pad($minute, 2, '0', STR_PAD_LEFT)] = $minute;
7172
}
7273

7374
$minuteOptions['choices'] = $minutes;
75+
$minuteOptions['choices_as_values'] = true;
7476
$minuteOptions['placeholder'] = $options['placeholder']['minute'];
7577
}
7678

7779
if ($options['with_seconds']) {
7880
$seconds = array();
7981

8082
foreach ($options['seconds'] as $second) {
81-
$seconds[$second] = str_pad($second, 2, '0', STR_PAD_LEFT);
83+
$seconds[str_pad($second, 2, '0', STR_PAD_LEFT)] = $second;
8284
}
8385

8486
$secondOptions['choices'] = $seconds;
87+
$secondOptions['choices_as_values'] = true;
8588
$secondOptions['placeholder'] = $options['placeholder']['second'];
8689
}
8790

‎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
}
@@ -85,4 +93,40 @@ public static function getTimezones()
8593

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

‎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
}

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

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

2121
protected function setUp()
2222
{
23-
$list = new ArrayChoiceList(array('A', 'B', 'C'));
23+
$list = new ArrayChoiceList(array('', false, 'X'));
2424
$this->transformer = new ChoicesToValuesTransformer($list);
2525
}
2626

@@ -31,7 +31,7 @@ protected function tearDown()
3131

3232
public function testTransform()
3333
{
34-
$in = array('A', 'B', 'C');
34+
$in = array('', false, 'X');
3535
$out = array('0', '1', '2');
3636

3737
$this->assertSame($out, $this->transformer->transform($in));
@@ -54,7 +54,7 @@ public function testReverseTransform()
5454
{
5555
// values are expected to be valid choices and stay the same
5656
$in = array('0', '1', '2');
57-
$out = array('A', 'B', 'C');
57+
$out = array('', false, 'X');
5858

5959
$this->assertSame($out, $this->transformer->reverseTransform($in));
6060
}

0 commit comments

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