Search code examples
phpentity-frameworksymfonyformbuilder

represent collection entity as one multiple field


I have an entity Alert who can contain multiple entity Category :

  /**
     * @ORM\ManyToMany(targetEntity="MDB\AnnonceBundle\Entity\Category")
     * @ORM\JoinTable(name="alerts_categories",
     *      joinColumns={@ORM\JoinColumn(name="alert_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="cateory_id", referencedColumnName="id")}
     *      )
     * */
    private $categories;

i have no probeme with the creation and persist of my entity but when i want to edit i have a representation problem. I want to display all the current Category entity attached to my Alert in a selected field like that :

enter image description here

but currently it displaying a selected field for each entity attached :

enter image description here

So, if a have 100 Category in this Alert entity i will have 100 category select field. What i want is only one with the existing category pre-checked.

AlertType.php

class AlertType extends AbstractType {

    public function __construct() {

    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                ->remove('user')
                ->remove('date')
                ->add('itemsToFind', 'collection')
                ->add("categories", "collection", array("type" => new CategoryType(true, true)))
                ->add('lieu')
                ->add("regions", "collection", array("type" => new RegionType()))
                ->add('fullCountry', 'checkbox', array(
                    'label' => 'Créer une alerte pour toute la France ?',
                    'required' => false,
                ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'MDB\UserBundle\Entity\Alert'
        ));
    }

    /**
     * @return string
     */
    public function getName() {
        return 'mdb_userbundle_alert';
    }

}

CategoryType.php

<?php


class CategoryType extends AbstractType {

    public function __construct($multiple, $mapped) {
        $this->multiple = $multiple;
        $this->mapped=$mapped;
    }


    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                ->add('category', 'entity', array(
                    'class' => 'MDBAnnonceBundle:Category',
                    'required' => true,
                    'choice_label' => 'nom',
                    'multiple' => $this->multiple,
                    'mapped' => $this->mapped,
                    'label' => false,
                    'attr' => array('class' => 'multiple categoriesToControl'),
                    'query_builder' => function(CategoryRepository $cr) {
                        return $cr->findAllOrderedByName();
                    }

        ));
    }

   public function configureOptions(OptionsResolver  $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'MDB\AnnonceBundle\Entity\Category'
        ));
    }


    public function getName() {
        return 'mdb_annoncebundle_category';
    }

}

I know this is normal cause in alertType Category is represented as a collection. And if a i use :

 ->add('categories', new CategoryType(false, true))  

i will have an who said symfony is waiting for a collection and get a Category.

Thanks


Solution

  • I find a solution,

    Previously i used this in my controller to edit my alert :

    $form = $this->createForm(new AlertType(), $alert);
    

    Because of that SF directly loaded the persistent collection and caused an error . Now i use this :

    $form = $this->createForm(new AlertType($alert));
    

    and i persist the the field manually.

    if ($form->handleRequest($request)->isValid()) {
    
                $em = $this->getDoctrine()->getManager();
    
                $alert->setItemsToFind($form->get('itemsToFind')->getData());
                $alert->setLieu($form->get('lieu')->getData());
                $alert->setfullCountry($form->get('fullCountry')->getData());
                $em->persist($alert);
                $em->flush();
    
                return $this->redirect($this->generateUrl('my_alerts'));
            }
    

    For the form type i use this now :

    class AlertType extends AbstractType {
    
        public function __construct($alert = null) {
            $this->alert = $alert;
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options) {
            $builder
                    ->remove('user')
                    ->remove('date')
                    ->add('itemsToFind', 'text', array('data' => $this->alert->getItemsToFind()))
                    ->add('categories', new CategoryType(true, true, $this->alert))
                    ->add('lieu', 'text', array('data' => $this->alert->getLieu()))
                    ->add('regions', new RegionType($this->alert->getRegions()))
                    ->add('fullCountry', 'checkbox', array(
                        'label' => 'Créer une alerte pour toute la France ?',
                        'data' => $this->alert->getFullCountry()
                    ))
            ;
        }
    

    And here the builder of my CategoryType :

     $builder
                    ->add('category', 'entity', array(
                        'class' => 'MDBAnnonceBundle:Category',
                        'required' => true,
                        'choice_label' => 'nom',
                        'multiple' => $this->multiple,
                        'mapped' => $this->mapped,
                        'label' => false,
                        'attr' => array('class' => 'multiple categoriesToControl'),                  
                        'query_builder' => function(CategoryRepository $cr) {
                                return $cr->findAllOrderedByName();
                        },'data' => (!$this->alert)?(null):($this->alert->getCategories())
            ));
        }
    

    of course i have to set set getter and setter of Category type in Alert Entity.

    Does someone know if this way have low performance? I'm just re-writing the method that SF is used to use so i don't think.

    Hope this will help other people