-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Form] fixed BC break with pre selection of choices with ChoiceType
and its children
#18180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,8 +11,8 @@ | |
|
||
namespace Symfony\Component\Form\Extension\Core\DataMapper; | ||
|
||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface; | ||
use Symfony\Component\Form\DataMapperInterface; | ||
use Symfony\Component\Form\Exception\UnexpectedTypeException; | ||
|
||
/** | ||
* Maps choices to/from radio forms. | ||
|
@@ -25,24 +25,18 @@ | |
*/ | ||
class RadioListMapper implements DataMapperInterface | ||
{ | ||
/** | ||
* @var ChoiceListInterface | ||
*/ | ||
private $choiceList; | ||
|
||
public function __construct(ChoiceListInterface $choiceList) | ||
{ | ||
$this->choiceList = $choiceList; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function mapDataToForms($data, $radios) | ||
public function mapDataToForms($choice, $radios) | ||
{ | ||
if (!is_string($choice)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should I test null of force a string casting before throwing here ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @webmozart I re-check the code and here the view data should always be a string. In contrary, since Do you agree or am I missing something ? Thanks. |
||
throw new UnexpectedTypeException($choice, 'string'); | ||
} | ||
|
||
foreach ($radios as $radio) { | ||
$value = $radio->getConfig()->getOption('value'); | ||
$radio->setData($value === $data ? true : false); | ||
$radio->setData($choice === $value); | ||
} | ||
} | ||
|
||
|
@@ -51,6 +45,10 @@ public function mapDataToForms($data, $radios) | |
*/ | ||
public function mapFormsToData($radios, &$choice) | ||
{ | ||
if (null !== $choice && !is_string($choice)) { | ||
throw new UnexpectedTypeException($choice, 'null or string'); | ||
} | ||
|
||
$choice = null; | ||
|
||
foreach ($radios as $radio) { | ||
|
@@ -59,8 +57,7 @@ public function mapFormsToData($radios, &$choice) | |
return; | ||
} | ||
|
||
$value = $radio->getConfig()->getOption('value'); | ||
$choice = current($this->choiceList->getChoicesForValues(array($value))); | ||
$choice = $radio->getConfig()->getOption('value'); | ||
|
||
return; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,9 +60,7 @@ public function __construct(ChoiceListFactoryInterface $choiceListFactory = null | |
public function buildForm(FormBuilderInterface $builder, array $options) | ||
{ | ||
if ($options['expanded']) { | ||
$builder->setDataMapper($options['multiple'] | ||
? new CheckboxListMapper($options['choice_list']) | ||
: new RadioListMapper($options['choice_list'])); | ||
$builder->setDataMapper($options['multiple'] ? new CheckboxListMapper() : new RadioListMapper()); | ||
|
||
// Initialize all choices before doing the index check below. | ||
// This helps in cases where index checks are optimized for non | ||
|
@@ -133,30 +131,13 @@ public function buildForm(FormBuilderInterface $builder, array $options) | |
|
||
$event->setData($data); | ||
}); | ||
} | ||
|
||
if (!$options['multiple']) { | ||
// For radio lists, transform empty arrays to null | ||
// This is kind of a hack necessary because the RadioListMapper | ||
// is not invoked for forms without choices | ||
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) { | ||
if (array() === $event->getData()) { | ||
$event->setData(null); | ||
} | ||
}); | ||
// For radio lists, pre selection of the choice needs to pre set data | ||
// with the string value so it can be matched in | ||
// {@link \Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper::mapDataToForms()} | ||
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { | ||
$choiceList = $event->getForm()->getConfig()->getOption('choice_list'); | ||
$value = current($choiceList->getValuesForChoices(array($event->getData()))); | ||
$event->setData((string) $value); | ||
}); | ||
} | ||
} elseif ($options['multiple']) { | ||
// <select> tag with "multiple" option | ||
if ($options['multiple']) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't fully understand why this is necessary. It seems to me the transformer and the data mappers are doing the same thing already. Can you add some explanation? |
||
// <select> tag with "multiple" option or list of checkbox inputs | ||
$builder->addViewTransformer(new ChoicesToValuesTransformer($options['choice_list'])); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @webmozart it also prevents this hack |
||
} else { | ||
// <select> tag without "multiple" option | ||
// <select> tag without "multiple" option or list of radio inputs | ||
$builder->addViewTransformer(new ChoiceToValueTransformer($options['choice_list'])); | ||
} | ||
|
||
|
@@ -255,7 +236,11 @@ public function configureOptions(OptionsResolver $resolver) | |
$choiceListFactory = $this->choiceListFactory; | ||
|
||
$emptyData = function (Options $options) { | ||
if ($options['multiple'] || $options['expanded']) { | ||
if ($options['expanded'] && !$options['multiple']) { | ||
return; | ||
} | ||
|
||
if ($options['multiple']) { | ||
return array(); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here