在表单(ContractType)中,我需要与Customer建立关联,Customer本身与公司和BillingAddress有关联。但是这些3个“嵌套实体”的数据本身在合同视图中根本不可编辑。这就是合同中客户ManyToOne-Relation的字段隐藏的原因。
但是出于显示目的,我还需要表格中的整个客户对象(包括底层公司和账单地址) - 但是只读。这就是为什么我在合同表单类型中添加了一个额外的字段 customerFullObject - 未映射( mapped => false )。由于它是一个未映射的字段,我通过表单事件设置数据。
现在,当我编辑合同数据时,客户的公司和账单地址数据无效 如果我删除/评论整个 customerFullObject 部分,一切都很好。
我不明白,未映射字段如何/为何可以更改实体的数据。 如何防止Symfony呢?或者是否有更好的“模式”/方式来实现我想要的?我在文档中找不到任何内容。
以下来自模型的一些代码段(为了简洁而删除了名称空间):
/**
* @ORM\Entity
*/
class Contract {
/**
* @var Customer
* @ORM\ManyToOne(targetEntity="Customer", inversedBy="contracts")
* @Assert\Type(type="Customer")
* @Assert\NotBlank(message = "customer.notBlank")
**/
private $customer;
// Other fields left out as irrelevant.
}
/**
* @ORM\Entity
*/
class Customer {
/**
* @var Company
* @ORM\OneToOne(targetEntity="Company")
* @Assert\NotBlank(message="company.notBlank")
**/
private $company;
/**
* @var Address
* @ORM\OneToOne(targetEntity="Address")
* @Assert\NotBlank(message="billingAddress.notBlank")
**/
private $billingAddress;
/**
* @var ArrayCollection
* @ORM\OneToMany(targetEntity="Contract", mappedBy="customer", orphanRemoval=true, cascade={"all"})
**/
private $contracts;
// Other fields left out as irrelevant.
}
class ContractType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add(
'customer',
'customerHiddenType',
array(
'label' => 'contract.customer',
)
);
$builder->add(
'customerFullObject',
'customerType',
array(
'cascade_validation' => false,
'mapped' => false
)
);
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$editMode = $form->getConfig()->getOption('editMode');
if (!empty($editMode) && $editMode === RequestAction::CREATE()) {
$form->remove('customerFullObject');
} else {
$form->get('customerFullObject')->setData($event->getData()->getCustomer());
}
}
);
// Other children left out as irrelevant.
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(
array(
'data_class' => 'Contract',
'cascade_validation' => true
)
);
}
public function getName() {
return 'contractType';
}
}
class CustomerType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add(
'company',
'companyType',
array(
'cascade_validation' => false,
'label' => 'customer.company'
)
);
$builder->add(
'billingAddress',
'addressType',
array(
'cascade_validation' => false,
'label' => 'customer.billingAddress'
)
);
// Other children left out as irrelevant.
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(
array(
'data_class' => 'Customer',
'cascade_validation' => true
)
);
}
public function getName() {
return 'customerType';
}
}