2012-09-21 43 views
2

我使用的Symfony 2.1和条令2.Symfony的2 - 多个表单字段为一个数据库行

我负责的两个主要实体:地点和特征,他们之间的多对多关系。 数据库中有很多功能,并按主题对它们进行分组,功能也与具有ManyToOne关系的FeatureCategory实体相关。

这里的不同实体的代码:

广场实体

namespace Mv\PlaceBundle\Entity; 
… 

/** 
* Mv\PlaceBundle\Entity\Place 
* 
* @ORM\Table(name="place") 
* @ORM\Entity(repositoryClass="Mv\PlaceBundle\Entity\Repository\PlaceRepository") 
* @ORM\HasLifecycleCallbacks 
*/ 
class Place 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string $name 
    * 
    * @ORM\Column(name="name", type="string", length=255, unique=true) 
    * @Assert\NotBlank 
    */ 
    private $name; 

    /** 
    * @ORM\ManyToMany(targetEntity="\Mv\MainBundle\Entity\Feature") 
    * @ORM\JoinTable(name="places_features", 
    * joinColumns={@ORM\JoinColumn(name="place_id", referencedColumnName="id")}, 
    * inverseJoinColumns={@ORM\JoinColumn(name="feature_id", referencedColumnName="id")} 
    *) 
    */ 
    private $features; 

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

    /** 
    * Set name 
    * 
    * @param string $name 
    * @return Place 
    */ 
    public function setName($name) 
    { 
    $this->name = $name; 
    return $this; 
    } 

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

    /** 
    * Add features 
    * 
    * @param \Mv\MainBundle\Entity\Feature $features 
    * @return Place 
    */ 
    public function addFeature(\Mv\MainBundle\Entity\Feature $features) 
    { 
    $this->features[] = $features; 
    echo 'Add "'.$features.'" - Total '.count($this->features).'<br />'; 
    return $this; 
    } 

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

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

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

特点实体:

namespace Mv\MainBundle\Entity; 
… 

/** 
* @ORM\Entity 
* @ORM\Table(name="feature") 
* @ORM\HasLifecycleCallbacks 
*/ 
class Feature 
{ 
    use KrToolsTraits\PictureTrait; 

    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

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

    /** 
    * @ORM\ManyToOne(targetEntity="\Mv\MainBundle\Entity\FeatureCategory", inversedBy="features", cascade={"persist"}) 
    * @ORM\JoinColumn(name="category_id", referencedColumnName="id") 
    */ 
    private $category; 

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

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

    /** 
    * Set category 
    * 
    * @param Mv\MainBundle\Entity\FeatureCategory $category 
    * @return Feature 
    */ 
    public function setCategory(\Mv\MainBundle\Entity\FeatureCategory $category = null) 
    { 
     $this->category = $category; 
     return $this; 
    } 

    /** 
    * Get category 
    * 
    * @return Mv\MainBundle\Entity\FeatureCategory 
    */ 
    public function getCategory() 
    { 
     return $this->category; 
    } 
} 

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

功能表已填充完毕,用户将无法添加功能,只能在表单集合中选择它们以将它们链接到“地点”。 (该功能实体目前仅与地点链接,但稍后将与我的应用程序中的其他实体相关,并将包含所有实体可用的所有功能)

在地方表单中,我需要显示复选框一个地方可用的功能,但我需要显示他们按类别分组。 实施例:

访问数(FeatureCategory - 代码VIS):

  • 免费(功能)
  • 付费(功能)

口头语(FeatureCategory - 代码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' 
    )); 

,并创建一个FeatureType虚拟表单,如下所示:

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次,但函数arrayCollection的长度是连续的:1,2,1,2,3。

任何想法如何以另一种方式做到这一点?如果我需要改变模型,我仍然可以做到。 什么是最好的方式,可重复使用我的未来其他实体也与功能相关,来处理这个问题?

谢谢你们。

回答

0

我认为你原来的需求只是约模板

所以你不应该调整窗体和实体持久性逻辑来获得所需的自动生成表单。

你应该回到一个基本形式

$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

相关问题