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

Skip to content

Commit ea5375c

Browse 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 71841c7 commit ea5375c

File tree

6 files changed

+88
-93
lines changed

6 files changed

+88
-93
lines changed

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

Lines 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/Bridge/Doctrine/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"require-dev": {
2323
"symfony/stopwatch": "~2.2",
2424
"symfony/dependency-injection": "~2.2",
25-
"symfony/form": "~2.7,>=2.7.1",
25+
"symfony/form": "~2.7.12|~2.8.5",
2626
"symfony/http-kernel": "~2.2",
2727
"symfony/property-access": "~2.3",
2828
"symfony/security": "~2.2",

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

Lines 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

Lines 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

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