按照本指南https://symfony.com/doc/current/form/embedded.html,我创建了一个包含三个实体的表单。患者,PatientSample和PatientOrder。当我提交表格时,我收到一个错误,Patient_id不能为null。
我一直在尝试各种方法在PatientOrderController中创建一个新的Patient对象,并在那里获取数据,然后调用$ entityManager-> persist($ Patient),但是在使用表单数据填充新的Patient对象时遇到了问题。 / p>
PatientOrderType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('accession_number')
->add('patient', PatientType::class)
->add('patientSample', PatientSampleType::class);
}
PatientOrderController
{
$patientOrder = new PatientOrder();
$form = $this->createForm(PatientOrderType::class, $patientOrder);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$patientOrder = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($patientOrder);
$entityManager->flush();
return $this->redirectToRoute('patient_order_index');
}
患者分类
class Patient
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
public $id;
/**
* @ORM\OneToMany(targetEntity="App\Entity\PatientOrder",
* mappedBy="patient")
*/
public $patientOrders;
/**
* @ORM\OneToMany(targetEntity="App\Entity\PatientSample",
* mappedBy="patient")
*/
public $patientSamples;
PatientOrder类
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Patient",
* inversedBy="patientOrders", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
* @Assert\Valid()
*/
protected $patient;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\PatientSample",
*inversedBy="patientOrders", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
* @Assert\Valid()
*/
private $patientSample;
PatientSample类
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Patient",
* inversedBy="patientSamples")
* @ORM\JoinColumn(nullable=false)
*/
private $patient;
/**
* @ORM\OneToMany(targetEntity="App\Entity\PatientOrder",
* mappedBy="patientSample")
*/
private $patientOrders;
我的期望是,当用户单击“保存”按钮时,它将在数据库的3个单独的表中插入3个新行。相反,我得到了SQLSTATE [23000]:违反完整性约束:1048列'Patient_id'不能为空
答案 0 :(得分:4)
好的。因此问题如下:
Patient
是一个独立的实体,这很好。它有两个关联,每个关联PatientSample
和PatientOrder
。 PatientSample
和PatientOrder
也有关联
您的表单会创建一个新的PatientOrder
,它会自动与Patient
关联,因为PatientOrder
是该关联的所有者,并且由于{{ 1}}。
cascade="PERSIST"
也会自动与PatientOrder
相关联,您可能也将其标记为级联持续存在。 但是,据我所知,PatientSample
的{{1}}属性/关联并没有自动设置。至少不是 the 问题,那至少是 a 问题。 -幸运的是,这是一个小问题,因为它仅在依赖关系图中创建一个三角形,但是-由于Patient是独立的,因此不会创建周期(那将是一个大问题)。但是,您的表单不容易能够设置这些类型的依赖项,尤其是因为它们并不明显。从技术上讲,样本可能属于另一位患者...(请参阅答案末尾的验证评论)
可能有几种解决方案,最简单但不是最好的:
patient
更干净的方法是在表单事件中的某个地方执行此操作...
您应将PatientSample
代码修改为如下形式:
if($form->isSubmitted() && $form->isValid()){
$patientOrder = $form->getData();
// NEW! However, I don't know if this violates the Law of Demeter:
$patientOrder->getSample()->setPatient($patientOrder->getPatient());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($patientOrder);
$entityManager->flush();
return $this->redirectToRoute('patient_order_index');
}
这种方法有些驯服。如果PatientOrderType
已经分配了不同患者,则可能还会引发异常(可以使用实体预先填写/设置表单)。但是,此方法将设置一名失踪患者,从而避免了该表单将// be aware you need to set the following use clauses:
// use Symfony\Component\Form\FormEvent;
// use Symfony\Component\Form\FormEvents;
$builder
// ...
->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
$patientOrder = $event->getData(); // view data, i.e. your objects
$patientSample = $patientOrder->getPatientSample();
if(!$patientSample->getPatient()) {
$patientSample->setPatient($patientOrder->getPatient());
}
})
;
保留为$patientSample
的情况。
为什么在表单事件中而不是直接在控制器中设置它?因为这样一来,表单类型就可以重用,而无需记住“哦,我必须使用此表单类型在PersonSample上显式设置该人”。
对于validating患者样本属于相同患者的患者订单,您可以在PatientSample
上添加以下Expression约束(实体,而不是表单类型):
Patient
或回调约束,并且本质上是一样的...实际上,在注解中编写代码感觉很奇怪(平均而言,IDE不会有太大帮助)
更新:在验证部分混合了患者订单和患者样本