Symfony 2-一个数据库行的多个表单字段

Symfony 2-一个数据库行的多个表单字段,symfony,doctrine-orm,symfony-forms,symfony-2.1,Symfony,Doctrine Orm,Symfony Forms,Symfony 2.1,我用的是Symfony 2.1和Doctrine 2 我正在处理两个主要的实体:地点和特征,它们之间有很多关系。 数据库中有许多功能,要按主题对其进行分组,该功能还与具有多功能关系的FeatureCategory实体相关 以下是不同实体的代码: 地点实体 FeatureCategory实体: namespace Mv\MainBundle\Entity; ... /** * @ORM\Entity * @ORM\Table(name="feature_category") */ clas

我用的是Symfony 2.1和Doctrine 2

我正在处理两个主要的实体:地点和特征,它们之间有很多关系。 数据库中有许多功能,要按主题对其进行分组,该功能还与具有多功能关系的FeatureCategory实体相关

以下是不同实体的代码:

地点实体

FeatureCategory实体:

namespace Mv\MainBundle\Entity;
...

/**
 * @ORM\Entity
 * @ORM\Table(name="feature_category")
 */
class FeatureCategory 
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(name="code", type="string", length=255)
     * @Assert\NotBlank()
     */
    protected $code;

    /**
     * @ORM\Column(name="label", type="string", length=255)
     * @Assert\NotBlank()
     */
    protected $label;

    /**
     * @ORM\OneToMany(targetEntity="\Mv\MainBundle\Entity\Feature", mappedBy="category", cascade={"persist", "remove"}, orphanRemoval=true)
     * @Assert\Valid()
     */
    private $features;

    public function __construct()
    {
       $this->features = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set code
     *
     * @param string $code
     * @return Feature
     */
    public function setCode($code)
    {
        $this->code = $code;
        return $this;
    }

    /**
     * Get code
     *
     * @return string 
     */
    public function getCode()
    {
        return $this->code;
    }

    /**
     * Set label
     *
     * @param string $label
     * @return Feature
     */
    public function setLabel($label)
    {
        $this->label = $label;
        return $this;
    }

    /**
     * Get label
     *
     * @return string 
     */
    public function getLabel()
    {
        return $this->label;
    }

    /**
    * Add features
    *
    * @param \Mv\MainBundle\Entity\Feature $features
    */
    public function addFeatures(\Mv\MainBundle\Entity\Feature $features){
      $features->setCategory($this);
      $this->features[] = $features;
    }

    /**
     * Get features
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getFeatures()
    {
        return $this->features;
    }

    /*
     * Set features
     */
    public function setFeatures(\Doctrine\Common\Collections\Collection $features)
    {
      foreach ($features as $feature)
      {
        $feature->setCategory($this);
      }
      $this->features = $features;
    }

    /**
     * Remove features
     *
     * @param Mv\MainBundle\Entity\Feature $features
     */
    public function removeFeature(\Mv\MainBundle\Entity\Feature $features)
    {
        $this->features->removeElement($features);
    }

    /**
     * Add features
     *
     * @param Mv\MainBundle\Entity\Feature $features
     * @return FeatureCategory
     */
    public function addFeature(\Mv\MainBundle\Entity\Feature $features)
    {
        $features->setCategory($this);
        $this->features[] = $features;
    }
}
要素表已填充,用户将无法添加要素,只能在表单集合中选择要素以将其链接到该位置。 要素实体目前仅链接到位置,但稍后将与我的应用程序中的其他实体关联,并将包含所有实体可用的所有要素

在Place表单中,我需要显示可用于某个位置的功能的复选框,但我需要显示按类别分组的功能。 例如:

访问功能类别-代码VIS:

自由特征 付费功能 语言口语功能类别-代码LAN:

英语特色 法国特色 西班牙特色 我的想法

在我的PlaceType表单中使用虚拟表单,如下所示:

$builder
    ->add('name')
    ->add('visit', new FeatureType('VIS'), array(
        'data_class' => 'Mv\PlaceBundle\Entity\Place'
    ))
    ->add('language', new FeatureType('LAN'), array(
        'data_class' => 'Mv\PlaceBundle\Entity\Place'
    ));
    class FeatureType extends AbstractType
    {
        protected $codeCat;

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

        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('features', 'entity', array(
                    'class' => 'MvMainBundle:Feature',
                    'query_builder' => function(EntityRepository $er)
                    {
                      return $er->createQueryBuilder('f')
                              ->leftJoin('f.category', 'c')
                              ->andWhere('c.code = :codeCat')
                              ->setParameter('codeCat', $this->codeCat)
                              ->orderBy('f.position', 'ASC');
                    },
                    'expanded' => true,
                    'multiple' => true
                ));
        }

        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'virtual' => true
            ));
        }

        public function getName()
        {
            return 'features';
        }
    }
并创建一个FeatureType虚拟表单,如下所示:

$builder
    ->add('name')
    ->add('visit', new FeatureType('VIS'), array(
        'data_class' => 'Mv\PlaceBundle\Entity\Place'
    ))
    ->add('language', new FeatureType('LAN'), array(
        'data_class' => 'Mv\PlaceBundle\Entity\Place'
    ));
    class FeatureType extends AbstractType
    {
        protected $codeCat;

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

        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('features', 'entity', array(
                    'class' => 'MvMainBundle:Feature',
                    'query_builder' => function(EntityRepository $er)
                    {
                      return $er->createQueryBuilder('f')
                              ->leftJoin('f.category', 'c')
                              ->andWhere('c.code = :codeCat')
                              ->setParameter('codeCat', $this->codeCat)
                              ->orderBy('f.position', 'ASC');
                    },
                    'expanded' => true,
                    'multiple' => true
                ));
        }

        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'virtual' => true
            ));
        }

        public function getName()
        {
            return 'features';
        }
    }
有了这个解决方案,我得到了我想要的,但是绑定过程并没有保留所有的特性。它没有对它们进行分组,只保留最后一种分组语言,并删除所有以前的功能数据。要查看它的实际运行情况,如果我选中5个复选框,它将进入Place->addFeature函数5次,但features arrayCollection的长度依次为:1、2、1、2、3

你知道怎么用另一种方法吗?如果我需要改变模型,我仍然能够做到。 处理这个问题的最佳方法是什么,在我未来的其他实体上可重用,也与功能相关


谢谢你们。

我认为你们最初的需求只是模板制作

因此,您不应该调整表单和实体持久性逻辑以获得所需的自动生成表单

你应该回到基本形式

$builder
    ->add('name')
    ->add('features', 'entity', array(
        'class' => 'MvMainBundle:Feature',
        'query_builder' => function(EntityRepository $er) {
              return $er->createQueryBuilder('f')
              //order by category.xxx, f.position
            },
                'expanded' => true,
                'multiple' => true
            ));

并调整你的form.html.twig

我认为你最初的需求只是模板化

因此,您不应该调整表单和实体持久性逻辑以获得所需的自动生成表单

你应该回到基本形式

$builder
    ->add('name')
    ->add('features', 'entity', array(
        'class' => 'MvMainBundle:Feature',
        'query_builder' => function(EntityRepository $er) {
              return $er->createQueryBuilder('f')
              //order by category.xxx, f.position
            },
                'expanded' => true,
                'multiple' => true
            ));
并调整form.html.twig