更新多对多关系
Update Many to Many relationship
我正在使用 symfony 3 和 doctrine 进行项目。
我在 Pack 和 Produit 之间有多对多的关系:
包实体:
class Pack
{
/**
* @var ArrayCollection | Produit[]
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Produit", inversedBy="packs")
* @ORM\JoinTable(name="link_pack")
*/
private $produits;
public function __construct()
{
$this->produits = new ArrayCollection();
}
/**
* @return Produit[]|ArrayCollection
*/
public function getProduits()
{
return $this->produits;
}
public function addProduit(Produit $produit)
{
if ($this->produits->contains($produit)) {
return;
}
$this->produits[] = $produit;
}
public function removeProduit(Produit $produit)
{
if (! $this->produits->contains($produit)) {
return;
}
return $this->produits->removeElement($produit);
}
}
产品实体:
class Produit
{
/**
* @var ArrayCollection | Pack[]
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Pack", mappedBy="produits")
*/
private $packs;
public function __construct()
{
$this->packs = new ArrayCollection();
}
/**
* @return Pack[]|ArrayCollection
*/
public function getPacks()
{
return $this->packs;
}
public function addPack(Pack $pack)
{
if ($this->packs->contains($pack)) {
return;
}
$pack->addProduit($this);
$this->packs[] = $pack;
}
}
我想将产品分配给一个包,所以我有一个在 select 字段中包含产品的表单。 (包装和产品是之前创建的)。
表单类型:
class PackAffectProduitType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('produits', EntityType::class, array(
'class' => Produit::class,
'choice_label' => 'libelle',
'multiple' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Pack::class,
));
}
}
控制器:
public function affectProduitsAction(Pack $pack, Request $request)
{
$form = $this->createForm(PackAffectProduitType::class, $pack);
$form->handleRequest($request);
dump($pack);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
dump($pack);
$em->flush();
// ...
}
//...
}
问题是当我 select 产品并提交时,它将 selected 产品分配给包,但之前分配的产品被删除了。我希望他们仍然分配,那么如何解决这个问题?
- 如果你想让你的视图添加或删除值,如果你手动生成你的字段视图结构,你需要不要忘记填充已经设置的值(例如之前添加到
Pack
的产品)。
例如,将 selected
属性添加到 select
的选项中。这样做会用当前值预填充您的字段,因此在提交时仅删除那些被故意取消选择的值。
- 如果您不想显示您的视图,也不了解此包上已设置的
Produit
个实体,只是盲目地执行添加,您可以将 mapped => false
添加到您的字段选项并处理手动将您的产品添加到您的控制器中。
这将只允许您添加,因为它不知道已经设置的值,并且您必须再创建一个 case/action 才能执行删除。我认为以上方式更好。
在最后一种情况下,您的控制器看起来像:
public function affectProduitsAction(Pack $pack, Request $request)
{
$form = $this->createForm(PackAffectProduitType::class, $pack);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
if(is_array($form->get('produits')->getData()){
foreach($form->get('produits')->getData() as $produit){
$pack->addProduit($produit);
}
}
$em->flush();
// ...
}
//...
}
还有你的表单类型:
class PackAffectProduitType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('produits', EntityType::class, array(
'class' => Produit::class,
'mapped' => false,
'choice_label' => 'libelle',
'multiple' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Pack::class,
));
}
}
尝试向您的表单添加 'by_reference' => false
选项,它将强制使用您实体中的 setter 和 getter
我正在使用 symfony 3 和 doctrine 进行项目。 我在 Pack 和 Produit 之间有多对多的关系:
包实体:
class Pack
{
/**
* @var ArrayCollection | Produit[]
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Produit", inversedBy="packs")
* @ORM\JoinTable(name="link_pack")
*/
private $produits;
public function __construct()
{
$this->produits = new ArrayCollection();
}
/**
* @return Produit[]|ArrayCollection
*/
public function getProduits()
{
return $this->produits;
}
public function addProduit(Produit $produit)
{
if ($this->produits->contains($produit)) {
return;
}
$this->produits[] = $produit;
}
public function removeProduit(Produit $produit)
{
if (! $this->produits->contains($produit)) {
return;
}
return $this->produits->removeElement($produit);
}
}
产品实体:
class Produit
{
/**
* @var ArrayCollection | Pack[]
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Pack", mappedBy="produits")
*/
private $packs;
public function __construct()
{
$this->packs = new ArrayCollection();
}
/**
* @return Pack[]|ArrayCollection
*/
public function getPacks()
{
return $this->packs;
}
public function addPack(Pack $pack)
{
if ($this->packs->contains($pack)) {
return;
}
$pack->addProduit($this);
$this->packs[] = $pack;
}
}
我想将产品分配给一个包,所以我有一个在 select 字段中包含产品的表单。 (包装和产品是之前创建的)。
表单类型:
class PackAffectProduitType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('produits', EntityType::class, array(
'class' => Produit::class,
'choice_label' => 'libelle',
'multiple' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Pack::class,
));
}
}
控制器:
public function affectProduitsAction(Pack $pack, Request $request)
{
$form = $this->createForm(PackAffectProduitType::class, $pack);
$form->handleRequest($request);
dump($pack);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
dump($pack);
$em->flush();
// ...
}
//...
}
问题是当我 select 产品并提交时,它将 selected 产品分配给包,但之前分配的产品被删除了。我希望他们仍然分配,那么如何解决这个问题?
- 如果你想让你的视图添加或删除值,如果你手动生成你的字段视图结构,你需要不要忘记填充已经设置的值(例如之前添加到
Pack
的产品)。
例如,将 selected
属性添加到 select
的选项中。这样做会用当前值预填充您的字段,因此在提交时仅删除那些被故意取消选择的值。
- 如果您不想显示您的视图,也不了解此包上已设置的
Produit
个实体,只是盲目地执行添加,您可以将mapped => false
添加到您的字段选项并处理手动将您的产品添加到您的控制器中。
这将只允许您添加,因为它不知道已经设置的值,并且您必须再创建一个 case/action 才能执行删除。我认为以上方式更好。
在最后一种情况下,您的控制器看起来像:
public function affectProduitsAction(Pack $pack, Request $request)
{
$form = $this->createForm(PackAffectProduitType::class, $pack);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
if(is_array($form->get('produits')->getData()){
foreach($form->get('produits')->getData() as $produit){
$pack->addProduit($produit);
}
}
$em->flush();
// ...
}
//...
}
还有你的表单类型:
class PackAffectProduitType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('produits', EntityType::class, array(
'class' => Produit::class,
'mapped' => false,
'choice_label' => 'libelle',
'multiple' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Pack::class,
));
}
}
尝试向您的表单添加 'by_reference' => false
选项,它将强制使用您实体中的 setter 和 getter