Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1176ba1

Browse files
committed
[Form] Deprecated setting "choices_as_values" to "false"
1 parent d1a50a2 commit 1176ba1

File tree

13 files changed

+321
-52
lines changed

13 files changed

+321
-52
lines changed

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

Lines changed: 41 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,39 @@ 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 = null)
228+
{
229+
if (null === $cache) {
230+
$cache = array();
231+
}
232+
233+
foreach ($choices as $choice) {
234+
if (is_array($choice)) {
235+
if (!$this->castableToString($choice, $cache)) {
236+
return false;
237+
}
238+
239+
continue;
240+
} elseif (!is_scalar($choice)) {
241+
return false;
242+
} elseif (isset($cache[(string) $choice])) {
243+
return false;
244+
}
245+
246+
$cache[(string) $choice] = true;
247+
}
248+
249+
return true;
250+
}
210251
}

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

Lines 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.7 and will be removed 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

Lines 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

Lines 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

Lines 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

Lines 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

Lines 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

Lines 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

Lines changed: 49 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
}
@@ -59,9 +67,13 @@ public function getName()
5967
* overhead.
6068
*
6169
* @return array The timezone choices
70+
*
71+
* @deprecated Deprecated since version 2.7
6272
*/
6373
public static function getTimezones()
6474
{
75+
@trigger_error('The TimezoneType::getTimezones() method is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
76+
6577
if (null === static::$timezones) {
6678
static::$timezones = array();
6779

@@ -85,4 +97,40 @@ public static function getTimezones()
8597

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

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

Lines 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

Lines 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)