我正在使用 Symfony 2.1 和 Doctrine 2。
我正在处理 2 个主要实体:Place 和 Feature,它们之间具有 ManyToMany 关系。数据库中有许多特征,为了按主题对它们进行分组,特征还与具有 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;
}
}
功能表已填充,用户将无法添加功能,只能在表单集合中选择它们以将它们链接到地方。(Feature 实体目前仅与 Places 相关联,但稍后将与我的应用程序中的其他实体相关联,并将包含所有实体可用的所有功能)
在 Place 表单中,我需要显示 Place 可用功能的复选框,但我需要按类别分组显示它们。例子 :
访问(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。
关于如何以另一种方式做到这一点的任何想法?如果我需要更改模型,我仍然可以做到。什么是最好的方法,可以在我未来也与功能相关的其他实体上重用,来处理这个?
感谢你们。