Skip to content

[Form] RadioListMapper does not handle empty array #18817

Closed
@julienfastre

Description

@julienfastre

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions