Skip to content

Form with ChoiceType and option "expanded" return integer keys #44792

Closed
@willemverspyck

Description

@willemverspyck

Symfony version(s) affected

6.0.0

Description

When creating a form with ChoiceType and the option "expanded" is set as true, the choices are changed into "checkbox" fields. But the keys of those fields are integers (0 for the first, 1 for the second). If you want to "get" one of those fields with FormBuilderInterface->get(string $name) that impossible with "declare(strict_types=1);" and bundles like Sonata use these get methods. In Symfony 5.4 it worked.

How to reproduce

<?php

// First, run "composer require symfony/form"
// Then, execute this file:

declare(strict_types=1);

require_once __DIR__.'/vendor/autoload.php';

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;

/**
 * Class TestType
 */
final class TestType extends AbstractType
{
    /**
     * Build the form
     *
     * @param FormBuilderInterface $builder
     * @param array                $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('type', ChoiceType::class, [
                'choices' => [
                    'Artist' => 'artist',
                    'Label' => 'label',
                ],
//                'choice_name' => function (string $choice, string $key): string {
//                    return $key;
//                },
                'expanded' => true,
            ]);
    }
}

use Symfony\Component\Form\Forms;

$formFactory = Forms::createFormFactory();

$form = $formFactory->createBuilder(TestType::class);

dump(array_keys($form->all()));
dump($form->get('type')->getName());
dump(array_keys($form->get('type')->all()));

// The next dump doesn’t give result
dump($form->get('type')->get('0')->getName());

// The next dump failes
dump($form->get('type')->get(0)->getName());

Possible Solution

As FormBuilderInterface defines:

    /**
     * Returns a child by name.
     *
     * @throws Exception\InvalidArgumentException if the given child does not exist
     */
    public function get(string $name): self;

So the key must always be string.

In the class "Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory" convert the nextIndex to string, then it works again: https://github.com/symfony/form/blob/6.0/ChoiceList/Factory/DefaultChoiceListFactory.php#L165

It can be temporary fixed by uncomment the “choice_name” callback in my example, that changes the key of the options.

Additional Context

No response

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