Symfony 2 Embedded Form Collection Many to Many

前端 未结 1 510
再見小時候
再見小時候 2021-02-01 10:19

I have 2 Entities - User and Group. They have a many-to-many relationship and Group is used to store a users\' roles.

I\'m trying to make a User edit form by adding a co

相关标签:
1条回答
  • 2021-02-01 10:50

    Well I worked out a solution for anyone else struggling with similar problems...

    I had to create a custom form type and declare it as a service so I could pass in the Entity Manager. I then needed to make a dataTransformer to change my group objects into an integer for the form

    Custom GroupSelectType:

    class GroupSelectType extends AbstractType
    
    {
        /**
         * @var ObjectManager
         */
        private $om;
    
        private $choices;
    
        /**
         * @param ObjectManager $om
         */
        public function __construct(ObjectManager $om)
        {
            $this->om = $om;
    
            // Build our choices array from the database
            $groups = $om->getRepository('SfoxCoreBundle:Group')->findAll();
            foreach ($groups as $group)
            {
                // choices[key] = label
                $this->choices[$group->getId()] = $group->getName() . " [". $group->getRole() ."]";
            }
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $transformer = new GroupToNumberTransformer($this->om);
            $builder->addModelTransformer($transformer);
        }
    
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                    "choices" => $this->choices,
                    ));
        }
    
        public function getParent()
        {
            return 'choice';
        }
    
        public function getName()
        {
            return 'group_select';
        }
    }
    

    In the constructor I'm getting all available groups and putting them into a "choices" array which is passed to the select box as an option.

    You'll also notice I'm using a custom data transformer, this is to change the groupId (which is used in the rendering of the form) to a Group entity. I made the GroupSelectType a service as well and passed in the [@doctrine.orm.entity_manager]

    services.yml (bundle config):

    services:
        sfox_core.type.group_select:
            class: Sfox\CoreBundle\Form\Type\GroupSelectType
            arguments: [@doctrine.orm.entity_manager]
            tags:
              - { name: form.type, alias: group_select }
    

    GroupToNumberTranformer.php

    class GroupToNumberTransformer implements DataTransformerInterface
    {
        /**
         * @var ObjectManager
         */
        private $om;
    
        /**
         * @param ObjectManager $om
         */
        public function __construct(ObjectManager $om)
        {
            $this->om = $om;
        }
    
        /**
         * Transforms an object (group) to a string (number).
         *
         * @param  Group|null $group
         * @return string
         */
        public function transform($group)
        {
            if (null === $group) {
                return "";
            }
    
            return $group->getId();
        }
    
        /**
         * Transforms a string (number) to an object (group).
         *
         * @param  string $number
         * @return Group|null
         * @throws TransformationFailedException if object (group) is not found.
         */
        public function reverseTransform($number)
        {
            if (!$number) {
                return null;
            }
    
            $group = $this->om
            ->getRepository('SfoxCoreBundle:Group')
            ->findOneBy(array('id' => $number))
            ;
    
            if (null === $group) {
                throw new TransformationFailedException(sprintf(
                        'Group with ID "%s" does not exist!',
                        $number
                ));
            }
    
            return $group;
        }
    }
    

    And my modified UserType.php - Notice I'm using my custom form type "group_select" now as it's running as a service:

    class UserType extends AbstractType
    {
        private $entityManager;
    
        public function __construct($entityManager)
        {
            $this->entityManager = $entityManager;
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $transformer = new GroupToNumberTransformer($this->entityManager);
    
            $builder
                ->add('username')
                ->add('email')
                ->add('forename')
                ->add('surname')
                ->add('isActive')
                ->add('joinDate', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy'))
                ->add('lastActive', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy'));
            $builder
                ->add(
                    $builder->create('groups', 'collection', array(
                        'type' => 'group_select',
                        'allow_add' => true,
                        'options' => array(
                                'multiple' => false,
                                'expanded' => false,
                                )
                        ))
            );
        }
    
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'Sfox\CoreBundle\Entity\User'
            ));
        }
    
        public function getName()
        {
            return 'sfox_corebundle_usertype';
        }
    }
    
    0 讨论(0)
提交回复
热议问题