英文:
Symfony: How to persist new entities with ManytoMany relation in embedded form
问题
以下是您要翻译的内容:
用例
TLDR;
我有两个具有ManyToMany关系的实体。我想要同时使用一个单一表单持久化两个新对象。为此,我创建了两个FromTypes,其中一个嵌套了另一个。
稍微详细一点...
目标是为用户提供一个用于查询事件的表单。事件实体包含像starttime、endtime等属性,这些属性是Event的简单属性,以及位置(Location实体与OneToMany关系,一个事件有一个位置,一个位置可以有多个事件)和联系人(Contact实体与ManyToMany关系,一个事件可以有多个联系人,一个联系人可以有多个事件)。对于所讨论的特定表单,用户只需提供一个联系人就足够了,这是一个故意的选择,足够了。
为了构建可重用的表单,有两个简单的表单,LocationFormType和ContactFormType,以及一个更复杂的EventFormType。EventFormType更复杂,因为它嵌套了LocationFormType和ContactFormType,以便一次创建一个事件实体,所谓的“一次完成”。
当我使用选项A构建EventFormType时(请参阅下面的代码),表单呈现正确,按照预期的方式。一切都看起来很好,直到提交表单。然后问题开始...
问题
在$form->handleRequest()上,FormSystem引发错误,因为嵌入的表单未为相关对象提供可遍历的对象。
类“App\Entity\Event”中的属性“contact”可以使用方法“addContact()”、“removeContact()”来定义,但新值必须是数组或\Traversable的实例。
显然,嵌入的FormType提供了一个单一对象,而关系的属性需要一个Collection。当我使用CollectionType进行嵌入(选项B,请参阅下面的代码),表单不再呈现,因为CollectionType似乎需要已经存在的实体。但是我想创建一个新的实体,所以没有可以传递的对象。
我的代码
#[ORM\Entity(repositoryClass: EventRepository::class)]
class Event
{
...
#[ORM\ManyToMany(targetEntity: Contact::class, inversedBy: 'events')]
...
private Collection $contact;
...
public function __construct()
{
$this->contact = new ArrayCollection();
}
...
/**
* @return Collection<int, Contact>
*/
public function getContact(): Collection
{
return $this->contact;
}
public function addContact(Contact $contact): self
{
if (!$this->contact->contains($contact)) {
$this->contact->add($contact);
}
return $this;
}
public function removeContact(Contact $contact): self
{
$this->contact->removeElement($contact);
return $this;
}
...
}
#[ORM\Entity(repositoryClass: ContactRepository::class)]
class Contact
{
...
#[ORM\ManyToMany(targetEntity: Event::class, mappedBy: 'contact')]
private Collection $events;
public function __construct()
{
$this->events = new ArrayCollection();
}
...
/**
* @return Collection<int, Event>
*/
public function getEvents(): Collection
{
return $this->events;
}
public function addEvent(Event $event): self
{
if (!$this->events->contains($event)) {
$this->events->add($event);
$event->addContact($this);
}
return $this;
}
public function removeEvent(Event $event): self
{
if ($this->events->removeElement($event)) {
$event->removeContact($this);
}
return $this;
}
}
class EventFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
...
// 选项A:直接嵌入相关的FormType
->add('contact', ContactFormType::class, [
...
])
// 选项B:使用CollectionType嵌入
->add('contact', CollectionType::class, [
'entry_type' => ContactFormType::class
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Event::class,
]);
}
}
class ContactFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add(
... // 这里只添加Contact实体的字段,没有特殊配置
)
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Contact::class,
]);
}
}
失败的解决方案
使用原型设置“allow_add” => true
我发现有解决方案建议在CollectionType上设置“allow_add” => true,并在Twig中使用
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论