8000 Merge branch '2.8' · symfony/symfony@9b9fa3d · GitHub
[go: up one dir, main page]

Skip to content

Commit 9b9fa3d

Browse files
committed
Merge branch '2.8'
* 2.8: [Form] Deprecated setting "choices_as_values" to "false" [Form] Deprecated setting "choices_as_values" to "false" [Form] Deprecated ArrayKeyChoiceList [Form] Deprecated TimezoneType::getTimezones()
2 parents 0468f74 + 78ff9dc commit 9b9fa3d

16 files changed

+320
-52
lines changed

UPGRADE-3.0.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,12 @@ UPGRADE FROM 2.x to 3.0
319319

320320
* The `Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList` class has been removed in
321321
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
322+
323+
* The `TimezoneType::getTimezones()` method was removed. You should not use
324+
this method.
325+
326+
* The `Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList` class has been removed in
327+
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
322328

323329
### FrameworkBundle
324330

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ public function __construct($choices, callable $value = null)
6868
$choices = iterator_to_array($choices);
6969
}
7070

71+
if (null === $value && $this->castableToString($choices)) {
72+
$value = function ($choice) {
73+
return (string) $choice;
74+
};
75+
}
76+
7177
if (null !== $value) {
7278
// If a deterministic value generator was passed, use it later
7379
$this->valueCallback = $value;
@@ -201,4 +207,35 @@ protected function flatten(array $choices, $value, &$choicesByValues, &$keysByVa
201207
$structuredValues[$key] = $choiceValue;
202208
}
203209
}
210+
211+
/**
212+
* Checks whether the given choices can be cast to strings without
213+
* generating duplicates.
214+
*
215+
* @param array $choices The choices.
216+
* @param array|null $cache The cache for previously checked entries. Internal
217+
*
218+
* @return bool Returns true if the choices can be cast to strings and
219+
* false otherwise.
220+
*/
221+
private function castableToString(array $choices, array &$cache = array())
222+
{
223+
foreach ($choices as $choice) {
224+
if (is_array($choice)) {
225+
if (!$this->castableToString($choice, $cache)) {
226+
return false;
227+
}
228+
229+
continue;
230+
} elseif (!is_scalar($choice)) {
231+
return false;
232+
} elseif (isset($cache[(string) $choice])) {
233+
return false;
234+
}
235+
236+
$cache[(string) $choice] = true;
237+
}
238+
239+
return true;
240+
}
204241
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Form\ChoiceList;
1313

14+
@trigger_error('The '.__NAMESPACE__.'\ArrayKeyChoiceList class is deprecated since version 2.8 and will be removed in 3.0. Use '.__NAMESPACE__.'\ArrayChoiceList instead.', E_USER_DEPRECATED);
15+
1416
use Symfony\Component\Form\Exception\InvalidArgumentException;
1517

1618
/**

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,14 @@ public function configureOptions(OptionsResolver $resolver)
268268
return $choiceListFactory->createListFromChoices($choices, $options['choice_value'< 8000 /span>]);
269269
};
270270

271+
$choicesAsValuesNormalizer = function (Options $options, $choicesAsValues) {
272+
if (true !== $choicesAsValues) {
273+
@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);
274+
}
275+
276+
return $choicesAsValues;
277+
};
278+
271279
$placeholderNormalizer = function (Options $options, $placeholder) {
272280
if ($options['multiple']) {
273281
// never use an empty value for this case
@@ -323,6 +331,7 @@ public function configureOptions(OptionsResolver $resolver)
323331
$resolver->setNormalizer('choice_list', $choiceListNormalizer);
324332
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
325333
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
334+
$resolver->setNormalizer('choices_as_values', $choicesAsValuesNormalizer);
326335

327336
$resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface'));
328337
$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
@@ -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
}
@@ -282,14 +285,15 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
282285
{
283286
$pattern = $formatter->getPattern();
284287
$timezone = $formatter->getTimezoneId();
288+
$formattedTimestamps = array();
285289

286290
$formatter->setTimeZone('UTC');
287291

288292
if (preg_match($regex, $pattern, $matches)) {
289293
$formatter->setPattern($matches[0]);
290294

291-
foreach ($timestamps as $key => $timestamp) {
292-
$timestamps[$key] = $formatter->format($timestamp);
295+
foreach ($timestamps as $timestamp => $choice) {
296+
$formattedTimestamps[$formatter->format($timestamp)] = $choice;
293297
}
294298

295299
// I'd like to clone the formatter above, but then we get a
@@ -299,7 +303,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
299303

300304
$formatter->setTimeZone($timezone);
301305

302-
return $timestamps;
306+
return $formattedTimestamps;
303307
}
304308

305309
private function listYears(array $years)
@@ -308,7 +312,7 @@ private function listYears(array $years)
308312

309313
foreach ($years as $year) {
310314
if (false !== $y = gmmktime(0, 0, 0, 6, 15, $year)) {
311-
$result[$year] = $y;
315+
$result[$y] = $year;
312316
}
313317
}
314318

@@ -320,7 +324,7 @@ private function listMonths(array $months)
320324
$result = array();
321325

322326
foreach ($months as $month) {
323-
$result[$month] = gmmktime(0, 0, 0, $month, 15);
327+
$result[gmmktime(0, 0, 0, $month, 15)] = $month;
324328
}
325329

326330
return $result;
@@ -331,7 +335,7 @@ private function listDays(array $days)
331335
$result = array();
332336

333337
foreach ($days as $day) {
334-
$result[$day] = gmmktime(0, 0, 0, 5, $day);
338+
$result[gmmktime(0, 0, 0, 5, $day)] = $day;
335339
}
336340

337341
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
@@ -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

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 getBlockPrefix()
5967
* overhead.
6068
*
6169
* @return array The timezone choices
70+
*
71+
* @deprecated Deprecated since version 2.8
6272
*/
6373
public static function getTimezones()
6474
{
75+
@trigger_error('The TimezoneType::getTimezones() method is deprecated since version 2.8 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 === self::$timezones) {
114+
self::$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+
self::$timezones[$region][str_replace('_', ' ', $name)] = $timezone;
131+
}
132+
}
133+
134+
return self::$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
@@ -57,22 +57,56 @@ public function testCreateChoiceListWithValueCallback()
5757
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz')));
5858
}
5959

60+
public function testCreateChoiceListWithoutValueCallbackAndDuplicateFreeToStringChoices()
61+
{
62+
$choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 123));
63+
64+
$this->assertSame(array('foo', 'bar', '123'), $choiceList->getValues());
65+
$this->assertSame(array('foo' => 'foo', 'bar' => 'bar', '123' => 123), $choiceList->getChoices());
66+
$this->assertSame(array('foo' => 2, 'bar' => 7, '123' => 10), $choiceList->getOriginalKeys());
67+
$this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => 'foo', 2 => '123')));
68+
$this->assertSame(array(1 => 'foo', 2 => '123'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123)));
69+
}
70+
71+
public function testCreateChoiceListWithoutValueCallbackAndToStringDuplicates()
72+
{
73+
$choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => '123', 10 => 123));
74+
75+
$this->assertSame(array('0', '1', '2'), $choiceList->getValues());
76+
$this->assertSame(array('0' => 'foo', '1' => '123', '2' => 123), $choiceList->getChoices());
77+
$this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys());
78+
$this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2')));
79+
$this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123)));
80+
}
81+
82+
public function testCreateChoiceListWithoutValueCallbackAndMixedChoices()
83+
{
84+
$object = new \stdClass();
85+
$choiceList = new ArrayChoiceList(array(2 => 'foo', 5 => array(7 => '123'), 10 => $object));
86+
87+
$this->assertSame(array('0', '1', '2'), $choiceList->getValues());
88+
$this->assertSame(array('0' => 'foo', '1' => '123', '2' => $object), $choiceList->getChoices());
89+
$this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys());
90+
$this->assertSame(array(1 => 'foo', 2 => $object), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2')));
91+
$this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => $object)));
92+
}
93+
6094
public function testCreateChoiceListWithGroupedChoices()
6195
{
6296
$choiceList = new ArrayChoiceList(array(
6397
'Group 1' => array('A' => 'a', 'B' => 'b'),
6498
'Group 2' => array('C' => 'c', 'D' => 'd'),
6599
));
66100

67-
$this->assertSame(array('0', '1', '2', '3'), $choiceList->getValues());
101+
$this->assertSame(array('a', 'b', 'c', 'd'), $choiceList->getValues());
68102
$this->assertSame(array(
69-
'Group 1' => array('A' => '0', 'B' => '1'),
70-
'Group 2' => array('C' => '2', 'D' => '3'),
103+
'Group 1' => array('A' => 'a', 'B' => 'b'),
104+
'Group 2' => array('C' => 'c', 'D' => 'd'),
71105
), $choiceList->getStructuredValues());
72-
$this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $choiceList->getChoices());
73-
$this->assertSame(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'), $choiceList->getOriginalKeys());
74-
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => '0', 2 => '1')));
75-
$this->assertSame(array(1 => '0', 2 => '1'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b')));
106+
$this->assertSame(array('a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd'), $choiceList->getChoices());
107+
$this->assertSame(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'), $choiceList->getOriginalKeys());
108+
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => 'a', 2 => 'b')));
109+
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b')));
76110
}
77111

78112
public function testCompareChoicesByIdentityByDefault()

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
/**
1717
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*
19+
* @group legacy
1820
*/
1921
class ArrayKeyChoiceListTest extends AbstractChoiceListTest
2022
{

0 commit comments

Comments
 (0)
0