phparrayssymfonyentityformbuilder

Symfony2 form collection array error


I have build user entity with roles which have field to store the roles in the database:

    /**
     * @var array
     * @ORM\Column(name="roles", type="json_array")
     */
    private $roles = array();   

    public function getRoles()
    {
        $roles = $this->roles;
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setPassword($password)
    {
        $this->password = $password;

        return $this;
    }

It is stored like a array in the database. This is build on tutorial. I realize that if it is like a array in the database it will need to be a collection in the form builder right? Here is the code:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('username')
        ->add('password')
        ->add('plainPassword', 'repeated', array('type' => 'password', 'required' => false))
        ->add('roles', 'choice', array(
           'choices' => array(
               'ROLE_USER'   => 'ROLE_USER',
               'ROLE_ADMIN' => 'ROLE_ADMIN'
           ),
           'multiple' => true,
       ))
        ->add('isActive')
        ->add('mail');
}

End the twig render

 {{ form_widget(edit_form.roles) }}

So the basic idea is to have a select field with all the roles to select for a user and then update the database. But for some reason when i remove

'multiple' => true

I got error like this ...

enter image description here

What is the best workaround here? I want not to have multiple choice but only single one.

And the last thing is that it not populate the database but i got the information and when I call before persist it saves them but not on default.

 $entity->setRoles($entity->getRoles());

Solution

  • You have to transform your values.

    You can build a widget

        <?php
    
    namespace Atix\UserBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    use Atix\UserBundle\Form\DataTransformer\RolesFormDataTransformer;
    
    class RolesFormType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $transformer = new RolesFormDataTransformer();
            $builder->add('roles', 'choice', array(
                'choices'   => array(
                                'ROLE_P1'        => 'Role p1',
                                'ROLE_RESPONSABLE'   => 'Role responsable',
                                'ROLE_ADMIN'             => 'Role admin',
                                ),
                'label' => false,
                'required'  => false
            ))->addModelTransformer($transformer);
    
        }
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            // $resolver->setDefaults(array(
            //     'data_class' => '',
            // ));
        }
    
        public function getName()
        {
            return 'roles_widget';
        }
    }
    

    And your datatransformer

    <?php
    
    namespace Atix\UserBundle\Form\DataTransformer;
    
    use Symfony\Component\Form\DataTransformerInterface;
    use Symfony\Component\Form\Exception\TransformationFailedException;
    
    class RolesFormDataTransformer implements DataTransformerInterface
    {
        /**
         * Transforms an array to a string.
         * POSSIBLE LOSS OF DATA
         *
         * @return string
         */
        public function transform($array)
        {
            if (empty($array)) {
                return $array;
            }
    
            $newArray = array();
            $newArray["roles"] = $array;
    
            return $newArray;
        }
    
        /**
         * Transforms a string to an array.
         *
         * @param  string $string
         *
         * @return array
         */
        public function reverseTransform($array)
        {
    
            //var_dump($string);
            $aRoles = array();
            foreach($array as $allValue)
            {
                foreach($allValue as $value)
                {
                    $aRoles[] = $value;
                }
            }
            return $aRoles;
        }
    }
    

    You declare the form at a service

    user.form.type.roles:
        class: Atix\UserBundle\Form\Type\RolesFormType
        tags:
            - { name: form.type, alias: roles_widget }
    

    You can now call your widget like this

    $builder->add('roles', 'roles_widget');