Having a ManyToMany
relation between Article
and Tag
i have a form with a multiselect of type EntityType
using Symfony FormBuilder.
Everything seems fine, even preselection, except when deselecting an already related Tag
from the tags-select, it does not remove the underlying relation. Therefor I can only add more relations.
I tried removing all relations before saving but because of LazyLoading I get other trouble there. I cannot find anything regarding this in the documentation but this might be very common basics, right?
Can anyone help me out here?
This is the code of my EntityType
-Field
$builder->add('tags', FormEntityType::class, [
'label' => 'Tags',
'required' => false,
'multiple' => true,
'expanded' => false,
'class' => Tag::class,
'choice_label' => function (Tag $tag) {
return $tag->getName();
},
'query_builder' => function (TagRepository $er) {
return $er->createQueryBuilder('t')
->where('t.isActive = true')
->orderBy('t.sort', 'ASC')
->addOrderBy('t.name', 'ASC');
},
'choice_value' => function(?Tag $entity) {
return $tag ? $tag->getId() : '';
},
'choice_attr' => function ($choice) use ($options) {
// Pre-Selection
if ($options['data']->getTags() instanceof Collection
&& $choice instanceof Tag) {
if ($options['data']->getTags()->contains($choice)) {
return ['selected' => 'selected'];
}
}
return [];
}
]);
And this is how I save after form-submit
$articleForm = $this->createForm(ArticleEditFormType::class, $article)->handleRequest($this->getRequest());
if ($articleForm->isSubmitted() && $articleForm->isValid()) {
// saving the article
$article = $articleForm->getData();
$this->em->persist($article);
$this->em->flush();
}
The Relations look like this:
Article.php
/**
* @ORM\ManyToMany(targetEntity=Tag::class, mappedBy="articles", cascade={"remove"})
* @ORM\OrderBy({"sort" = "ASC"})
*/
private $tags;
public function removeTag(Tag $tag): self
{
if ($this->tags->removeElement($tag)) {
$tag->removeArticle($this);
}
return $this;
}
Tag.php
/**
* @ORM\ManyToMany(targetEntity=Article::class, inversedBy="tags", cascade={"remove"})
* @ORM\OrderBy({"isActive" = "DESC","name" = "ASC"})
*/
private $articles;
public function removeArticle(Article $article): self
{
$this->articles->removeElement($article);
return $this;
}
CodePudding user response:
Setters, adders, etc. won't be called on the entity by default.
In the case of a multiselect where the underlying object is a collection, to ensure that the element is removed by calling removeArticle
you have to set the option by_reference
to false
.
This is applicable to CollectionType
as well.