Description
Hi,
I do not know if this is a bug or a feature... I am still investigating this, but if you have some guidance I would appreciate.
For a reason I do not know (yet), sometimes, an empty array is passed to the method Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper::mapFormsToData
(a var_dump
gives array (size=0) empty
) when nothing is checked by the user (this form is not required).
Until 2.8.5
, everything was great. But from 2.8.5
, the class Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper
has changed in commit ea5375c, an and Symfony\Component\Form\Exception\UnexpectedTypeException
is thrown.
Logically, when I change the method mapFormsToData
to allow empty arrays, the method is processed without any error :
public function mapFormsToData($radios, &$choice)
{
// the condition was if (null !== $choice && !is_string($choice))
if (
null !== $choice && !is_string($choice)
AND
!(is_array($choice) && count($choice) === 0)
) {
throw new UnexpectedTypeException($choice, 'null, string or empty array');
}
$choice = null;
// as we have an empty array, this loop is not executed, the $choice remains on `null` and everything is fine...
foreach ($radios as $radio) {
if ($radio->getData()) {
if ('placeholder' === $radio->getName()) {
return;
}
$choice = $radio->getConfig()->getOption('value');
return;
}
}
}
I do not know if we have to be so strong in the condition, or if this class should also accept empty array.
So, is this a bug or a feature ?
Some context
As I said before, I do not know why we have an empty array. This array comes from a CustomType which produce a field "Choice with other" (the user may choose amongst different values, or pick another value and fill a text). This Type may allow multiple choices ('multiple' => true
) or not, and is not required. When multiple
is true
, we do not encounter problems. When multiple
is false
, the RadioListMapper
is executed and the exception is thrown. This Type is attached to a DataTransformer which transform the values into an array and store that as an array.
Some code :
class ChoiceWithOtherType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//add an 'other' entry in choices array
$options['choices']['_other'] = $this->otherValueLabel;
//ChoiceWithOther must always be expanded
$options['expanded'] = true;
$builder
->add('_other', 'text', array('required' => false))
->add('_choices', 'choice', $options)
;
}
}
When coming out of the DataTransformer
, the data is this :
array (size=2)
'_other' => string '' (length=0)
'_choices' => null
Something else...
Something else which might be interesting is this block in Form::submit
line 616-623.
if (count($this->children) > 0) {
// Use InheritDataAwareIterator to process children of
// descendants that inherit this form's data.
// These descendants will not be submitted normally (see the check
// for $this->config->getInheritData() above)
$childrenIterator = new InheritDataAwareIterator($this->children);
$childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
$this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData);
}
When $this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData);
is executed, $viewData
contains an empty array, and this throw and Exception. But var_dump($this->getViewData()))
, return string '' (length=0)
. I wonder if the $viewData
would have some transformation from an empty string to an empty array...
But, if I replace $this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData)
by $this->config->getDataMapper()->mapFormsToData($childrenIterator, $this->getViewData())
, the validation does not pass any more.
If you think this might be a bug, could you tell me how I should improve this bug report ? (I hadn't time to reproduce the bug).