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 b3fa216

Browse filesBrowse files
committed
[Form] refactor CheckboxListMapper and RadioListMapper
fixes #14712 and #17789. `ChoiceType` now always use `ChoiceToValueTransformer` or `ChoicesToValuesTransformer` depending on `multiple` option. Hence `CheckboxListMapper` and `RadioListMapper` don’t handle the transformation anymore. Fixes pre selection of choice with model values such as `null`, `false` or empty string.
1 parent 46b325c commit b3fa216
Copy full SHA for b3fa216

File tree

Expand file treeCollapse file tree

5 files changed

+87
-92
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+87
-92
lines changed

‎src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ public function testSubmitSingleExpandedNull()
261261
$field->submit(null);
262262

263263
$this->assertNull($field->getData());
264-
$this->assertNull($field->getViewData());
264+
$this->assertSame('', $field->getViewData(), 'View data is always a string');
265265
}
266266

267267
public function testSubmitSingleNonExpandedNull()

‎src/Symfony/Component/Form/Extension/Core/DataMapper/CheckboxListMapper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/DataMapper/CheckboxListMapper.php
+8-33Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@
1111

1212
namespace Symfony\Component\Form\Extension\Core\DataMapper;
1313

14-
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
1514
use Symfony\Component\Form\DataMapperInterface;
16-
use Symfony\Component\Form\Exception\TransformationFailedException;
15+
use Symfony\Component\Form\Exception\UnexpectedTypeException;
1716

1817
/**
1918
* Maps choices to/from checkbox forms.
@@ -26,16 +25,6 @@
2625
*/
2726
class CheckboxListMapper implements DataMapperInterface
2827
{
29-
/**
30-
* @var ChoiceListInterface
31-
*/
32-
private $choiceList;
33-
34-
public function __construct(ChoiceListInterface $choiceList)
35-
{
36-
$this->choiceList = $choiceList;
37-
}
38-
3928
/**
4029
* {@inheritdoc}
4130
*/
@@ -46,22 +35,12 @@ public function mapDataToForms($choices, $checkboxes)
4635
}
4736

4837
if (!is_array($choices)) {
49-
throw new TransformationFailedException('Expected an array.');
50-
}
51-
52-
try {
53-
$valueMap = array_flip($this->choiceList->getValuesForChoices($choices));
54-
} catch (\Exception $e) {
55-
throw new TransformationFailedException(
56-
'Can not read the choices from the choice list.',
57-
$e->getCode(),
58-
$e
59-
);
38+
throw new UnexpectedTypeException($choices, 'array');
6039
}
6140

6241
foreach ($checkboxes as $checkbox) {
6342
$value = $checkbox->getConfig()->getOption('value');
64-
$checkbox->setData(isset($valueMap[$value]) ? true : false);
43+
$checkbox->setData(in_array($value, $choices, true));
6544
}
6645
}
6746

@@ -70,6 +49,10 @@ public function mapDataToForms($choices, $checkboxes)
7049
*/
7150
public function mapFormsToData($checkboxes, &$choices)
7251
{
52+
if (!is_array($choices)) {
53+
throw new UnexpectedTypeException($choices, 'array');
54+
}
55+
7356
$values = array();
7457

7558
foreach ($checkboxes as $checkbox) {
@@ -79,14 +62,6 @@ public function mapFormsToData($checkboxes, &$choices)
7962
}
8063
}
8164

82-
try {
83-
$choices = $this->choiceList->getChoicesForValues($values);
84-
} catch (\Exception $e) {
85-
throw new TransformationFailedException(
86-
'Can not read the values from the choice list.',
87-
$e->getCode(),
88-
$e
89-
);
90-
}
65+
$choices = $values;
9166
}
9267
}

‎src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php
+10-15Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
namespace Symfony\Component\Form\Extension\Core\DataMapper;
1313

14-
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
1514
use Symfony\Component\Form\DataMapperInterface;
15+
use Symfony\Component\Form\Exception\UnexpectedTypeException;
1616

1717
/**
1818
* Maps choices to/from radio forms.
@@ -25,26 +25,18 @@
2525
*/
2626
class RadioListMapper implements DataMapperInterface
2727
{
28-
/**
29-
* @var ChoiceListInterface
30-
*/
31-
private $choiceList;
32-
33-
public function __construct(ChoiceListInterface $choiceList)
34-
{
35-
$this->choiceList = $choiceList;
36-
}
37-
3828
/**
3929
* {@inheritdoc}
4030
*/
4131
public function mapDataToForms($choice, $radios)
4232
{
43-
$valueMap = array_flip($this->choiceList->getValuesForChoices(array($choice)));
33+
if (!is_string($choice)) {
34+
throw new UnexpectedTypeException($choice, 'string');
35+
}
4436

4537
foreach ($radios as $radio) {
4638
$value = $radio->getConfig()->getOption('value');
47-
$radio->setData(isset($valueMap[$value]) ? true : false);
39+
$radio->setData($choice === $value);
4840
}
4941
}
5042

@@ -53,6 +45,10 @@ public function mapDataToForms($choice, $radios)
5345
*/
5446
public function mapFormsToData($radios, &$choice)
5547
{
48+
if (null !== $choice && !is_string($choice)) {
49+
throw new UnexpectedTypeException($choice, 'null or string');
50+
}
51+
5652
$choice = null;
5753

5854
foreach ($radios as $radio) {
@@ -61,8 +57,7 @@ public function mapFormsToData($radios, &$choice)
6157
return;
6258
}
6359

64-
$value = $radio->getConfig()->getOption('value');
65-
$choice = current($this->choiceList->getChoicesForValues(array($value)));
60+
$choice = $radio->getConfig()->getOption('value');
6661

6762
return;
6863
}

‎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
+10-17Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ public function __construct(ChoiceListFactoryInterface $choiceListFactory = null
6060
public function buildForm(FormBuilderInterface $builder, array $options)
6161
{
6262
if ($options['expanded']) {
63-
$builder->setDataMapper($options['multiple']
64-
? new CheckboxListMapper($options['choice_list'])
65-
: new RadioListMapper($options['choice_list']));
63+
$builder->setDataMapper($options['multiple'] ? new CheckboxListMapper() : new RadioListMapper());
6664

6765
// Initialize all choices before doing the index check below.
6866
// This helps in cases where index checks are optimized for non
@@ -133,22 +131,13 @@ public function buildForm(FormBuilderInterface $builder, array $options)
133131

134132
$event->setData($data);
135133
});
134+
}
136135

137-
if (!$options['multiple']) {
138-
// For radio lists, transform empty arrays to null
139-
// This is kind of a hack necessary because the RadioListMapper
140-
// is not invoked for forms without choices
141-
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
142-
if (array() === $event->getData()) {
143-
$event->setData(null);
144-
}
145-
});
146-
}
147-
} elseif ($options['multiple']) {
148-
// <select> tag with "multiple" option
136+
if ($options['multiple']) {
137+
// <select> tag with "multiple" option or list of checkbox inputs
149138
$builder->addViewTransformer(new ChoicesToValuesTransformer($options['choice_list']));
150139
} else {
151-
// <select> tag without "multiple" option
140+
// <select> tag without "multiple" option or list of radio inputs
152141
$builder->addViewTransformer(new ChoiceToValueTransformer($options['choice_list']));
153142
}
154143

@@ -247,7 +236,11 @@ public function configureOptions(OptionsResolver $resolver)
247236
$choiceListFactory = $this->choiceListFactory;
248237

249238
$emptyData = function (Options $options) {
250-
if ($options['multiple'] || $options['expanded']) {
239+
if ($options['expanded'] && !$options['multiple']) {
240+
return;
241+
}
242+
243+
if ($options['multiple']) {
251244
return array();
252245
}
253246

0 commit comments

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