我对Symfony比较陌生,因此我可能会严重误解某些东西。我对于何时要使用by_reference = true
在CollectionType表单字段上设置allow_add = true
感到困惑。
对于上下文:
当我尝试使用主义事件监听器来监听实体上的preRemove
时,我陷入了困境,该实体是通过使用allow_delete => true
从CollectionType表单字段中删除以触发更新而删除的在父实体上。在表单类上使用by_reference => false
时,我无法访问preRemove处理程序内的父实体,但是调用了父实体的removeEntity()方法。使用by_reference => true
,我可以从要删除的实体访问父对象,但是不会调用其removeEntity()方法。这对我来说很有意义,我的麻烦是添加带有表单的子实体。
简化,我有两个实体:
// SimpleParent.php
/**
* @ORM\Entity(repositoryClass="App\Repository\SimpleParentRepository")
*/
class SimpleParent
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\OneToMany(targetEntity="App\Entity\ChildEntity", mappedBy="parent", orphanRemoval=true, cascade={"persist", "remove"})
*/
private $childEntities;
public function addChildEntity(ChildEntity $childEntity): self
{
if (!$this->childEntities->contains($childEntity)) {
$this->childEntities[] = $childEntity;
$childEntity->setParent($this);
}
return $this;
}
// other getter, adder, remover methods as autogenerated, left out for brevity
}
和
// ChildEntity.php
/**
* @ORM\Entity(repositoryClass="App\Repository\ChildEntityRepository")
*/
class ChildEntity
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\SimpleParent", inversedBy="childEntities")
* @ORM\JoinColumn(nullable=false)
*/
private $parent;
// getter, adder, remover methods as autogenerated, left out for brevity
}
具有两个非常简单的表单类:
class SimpleParentType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => SimpleParent::class,
]);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('childEntities', NiceRepeaterType::class, [
"entry_type" => ChildEntityType::class,
"allow_delete" => true,
"by_reference" => true,
"allow_add" => true,
]);
}
}
class ChildEntityType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ChildEntity::class,
]);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add("name", TextType::class, ["required" => false]);
}
}
以及控制器中的一个非常简单的代码(为简单起见,我只是在这里刷新entityManager)
$form = $this->createForm(SimpleParentType::class, $simpleParent);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$simpleParent = $form->getData();
$this->entityManager->flush();
}
正确{@ {1}}分类,为简洁起见。 使用原型,我添加了新行。但是,提交表单会引发异常:
use
如果我将ChildEntity上的join列设置为可空,则将插入ChildEntity,但由于将parent_id设置为null,因此与SimpleParent没有任何连接。
不用说,这些插入的ChildEntity行不会显示在Collection中的表单中。这是有道理的,因为永远不会调用父级的加法器,因此永远不会在新的ChildEntity上An exception occurred while executing 'INSERT INTO child_entity (name, parent_id) VALUES (?, ?)' with params ["aaa", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'parent_id' cannot be null
。
使用setParent($this)
,它可以按预期正常工作,创建了ChildEntity并将其传递给设置ChildEntity父级的SimpleParent :: addChildEntity。刷新实体管理器后,将插入childEntity行,并将parent_id设置为SimpleParent的ID。
我的问题是:如果我还想要by_reference => false
,为什么我会在CollectionType上使用by_reference => true
?
我注意到,我从控制器中的allow_add => true
获取的对象包含Collection,其中包括ChildEntity,该ChildEntity当前没有父对象。我可以手动完成
$form->getData()
但是这种方法有什么原因呢?我觉得我缺少明显的东西。任何建议表示赞赏。