Symfony form - Choicetype - Error "Array to string covnersion"
Asked Answered
I

3

6

I'm running Symfony 3.4 with FosUserBundle. I customized the registration form in order to get the Roles included :

<?php

    $form->add('roles', ChoiceType::class, array(
        'choices' => array(
            'user' => 'ROLE_USER',
            'admin' => 'ROLE_ADMIN'
        ),
        'label' => 'Role :',
        'expanded' => true,
        'multiple' => true
    ));

Then roles are now selectable in the registration form through 2 new checkbox... but I'd like to display it with a <select> tag. When I set the expanded option to false I get a select, but if I set the multiple option to FALSE I get an error :

Array to string conversion

Any idea to fix my issue ?

EDIT : below is the stack trace :

Symfony\Component\Debug\Exception\ContextErrorException:
Notice: Array to string conversion

  at vendor\symfony\symfony\src\Symfony\Component\Form\ChoiceList\ArrayChoiceList.php:73
  at Symfony\Component\Form\ChoiceList\ArrayChoiceList->Symfony\Component\Form\ChoiceList\{closure}(array('ROLE_USER'))
  at call_user_func(object(Closure), array('ROLE_USER'))
     (vendor\symfony\symfony\src\Symfony\Component\Form\ChoiceList\ArrayChoiceList.php:158)
  at Symfony\Component\Form\ChoiceList\ArrayChoiceList->getValuesForChoices(array(array('ROLE_USER')))
     (vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer.php:32)
  at Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer->transform(array('ROLE_USER'))
     (vendor\symfony\symfony\src\Symfony\Component\Form\Form.php:1104)
  at Symfony\Component\Form\Form->normToView(array('ROLE_USER'))
     (vendor\symfony\symfony\src\Symfony\Component\Form\Form.php:350)
  at Symfony\Component\Form\Form->setData(array('ROLE_USER'))
     (vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper.php:49)
  at Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper->mapDataToForms(object(User), object(RecursiveIteratorIterator))
     (vendor\symfony\symfony\src\Symfony\Component\Form\Form.php:383)
  at Symfony\Component\Form\Form->setData(object(User))
     (vendor\friendsofsymfony\user-bundle\Controller\RegistrationController.php:70)
  at FOS\UserBundle\Controller\RegistrationController->registerAction(object(Request))
  at call_user_func_array(array(object(RegistrationController), 'registerAction'), array(object(Request)))
     (var\cache\dev\classes.php:4659)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (var\cache\dev\classes.php:4614)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Kernel.php:200)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (web\app_dev.php:29)
Informality answered 8/8, 2018 at 10:32 Comment(7)
Is there any more information in the stack trace?Avowal
try adding an 'empty_value' => nullLigation
You should use 'expanded' => false, and 'multiple' => trueBusyness
@MatthewUsurp I added the stack trace in my first topic.Informality
@Ligation If I add it I get a new error : The option "empty_value" does not existInformality
Did you do any research ? Your question seem very similar to this #17315496Miele
@JasminMistry : it generates a MULTIPLE <select>, and I try to have a UNIQUE <select>Informality
L
11

to solve your problem you need a data transformer, because the roles field is actually an array :

add the data transformer to your FormType class along with the roles field instead of adding it in the controller:

$builder->add('roles', ChoiceType::class, array(
    'choices' => array(
        'user' => 'ROLE_USER',
        'admin' => 'ROLE_ADMIN'
    ),
    'label' => 'Role :'
));

//roles field data transformer
$builder->get('roles')
    ->addModelTransformer(new CallbackTransformer(
        function ($rolesArray) {
             // transform the array to a string
             return count($rolesArray)? $rolesArray[0]: null;
        },
        function ($rolesString) {
             // transform the string back to an array
             return [$rolesString];
        }
));
Louvenialouver answered 8/8, 2018 at 12:42 Comment(0)
S
6

2020 - Symfony 5.0.8:

in your FormType file:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('roles', ChoiceType::class, [
            'required' => true,
            'multiple' => false,
            'expanded' => false,
            'choices'  => [
                'User' => 'ROLE_USER',
                'Admin' => 'ROLE_ADMIN',
            ],
        ]);

    $builder->get('roles')
        ->addModelTransformer(new CallbackTransformer(
            function ($rolesArray) {
                // transform the array to a string
                return count($rolesArray)? $rolesArray[0]: null;
            },
            function ($rolesString) {
                // transform the string back to an array
                return [$rolesString];
            }
        ));
}
Swan answered 13/5, 2020 at 7:50 Comment(0)
G
4

What is happening is normal : Your property roles is AN ARRAY of string. In your entity you got something like :

/**
 * @var array
 */
private $roles = [];

And logically, when you put the option multiple => 'true', Symfony form will treat it like an array and convert each element of your array in string (which they already are).

On the other hand, if you put multiple => false, it will consider the array as a single choice which it is not.

Simply put, you have an inconsistency between your model where your roles property is an array of string, and the form you are trying to create, which considers roles as a single value.

In your case, You have to put multiple => true.

Graveyard answered 8/8, 2018 at 14:3 Comment(1)
If you persist in wanting multiple => false, I suggest you look at the answer answer which is exactly your problemGraveyard

© 2022 - 2024 — McMap. All rights reserved.