将集合实体表示为一个多字段

represent collection entity as one multiple field

我有一个可以包含多个实体类别的实体警报:

  /**
     * @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;

我对我的实体的创建和持久化没有任何问题,但是当我想编辑时,我遇到了表示问题。我想在像这样的 selected 字段中显示附加到我的警报的所有当前类别实体:

但目前它显示每个附加实体的 selected 字段:

因此,如果在此警报实体中有 100 个类别,我将有 100 个类别 select 字段。我想要的只是预先检查了现有类别的一个。

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';
    }

}

我知道这是正常的,因为 alertType 类别表示为一个集合。如果我使用:

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

我会有一个人说 symfony 正在等待收集并获得一个类别。

谢谢

在您的情况下,我通常会将 $alertId = null 等参数传递给您的 AlertType。稍后,在初始化您的 CategoryType 时,我也会传递该变量。然后在 CategoryType 中的 buildForm 方法中,我将根据 $alertId 值执行查询。

把我的话写成代码:

class AlertType extends AbstractType {

    private $alertId;

    public function __construct($alertId = null) {
        $this->alertId = $alertId;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->remove('user')
            ->remove('date')
            ->add('itemsToFind', 'collection')
            ->add(
                "categories",
                "collection",
                array(
                    "type" => new CategoryType(
                        $this->alertId, 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';
    }
}

class CategoryType extends AbstractType {

    private $alertId;

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


    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) {
                    if(!$this->alertId) {
                        return $cr->findAllOrderedByName();
                    } else {
                        return $cr->findAllOrderedByNameForAlertId($alertId);
                    }
                }

            ));
    }

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

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

}

现在,在您的 CategoryRepository 中,只需创建一个名为 findAllOrderedByNameForAlertId 的方法,其中 returns 为您的 Alert 选择的特定结果,您应该完成了。

我找到了解决办法,

以前我在我的控制器中使用它来编辑我的警报:

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

因为那个SF直接加载了persistent collection导致了错误。现在我用这个:

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

并且我手动保存该字段。

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'));
        }

对于我现在使用的表单类型:

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()
                ))
        ;
    }

这里是我的 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())
        ));
    }

当然我必须在警报实体中设置类别类型的集合getter和setter。

有人知道这种方式是否性能低下?我只是重写了SF习惯使用的方法,所以我不认为。

希望这对其他人有帮助