我有一个/checkout
JSON API端点,该端点允许可选的billingAddress
参数与其他参数,例如电子邮件和deliveryAddress
。
这些地址存储在与Order
实体有关的Address
实体中。
如果用户输入其BillingAddress,一切都很好,但是如果用户删除先前提交的帐单地址,我找不到删除billingAddress
Entity的方法。理想情况下,要删除我使用以下JSON帖子请求的计费地址。
{
"email": "nick@example.com",
"deliveryAddress": {
"line1": "1 Box Lane"
},
"billingAddress": null
}
这根本有可能使用Symfony表格?
有关当前设置的简化说明,请参见下文。
实体
/**
* @ORMEntity
*/
class Order
{
// ...
/**
* @var Address
*
* @ORMOneToOne(targetEntity = "Address", cascade = {"persist", "remove"})
* @ORMJoinColumn(name = "deliveryAddressId", referencedColumnName = "addressId")
*/
private $deliveryAddress;
/**
* @var Address
*
* @ORMOneToOne(targetEntity = "Address", cascade = {"persist", "remove"}, orphanRemoval = true)
* @ORMJoinColumn(name = "billingAddressId", referencedColumnName = "addressId", nullable = true)
*/
private $billingAddress;
public function setDeliveryAddress(Address $deliveryAddress = null)
{
$this->deliveryAddress = $deliveryAddress;
return $this;
}
public function getDeliveryAddress()
{
return $this->deliveryAddress;
}
public function setBillingAddress(Address $billingAddress = null)
{
$this->billingAddress = $billingAddress;
return $this;
}
public function getBillingAddress()
{
return $this->billingAddress;
}
// ...
}
。
/**
* @ORMEntity
*/
class Address
{
// ...
/**
* @var string
*
* @ORMColumn(type = "string", length = 45, nullable = true)
*/
private $line1;
// ...
}
表格
class CheckoutType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class)
->add('deliveryAddress', AddressType::class, [
'required' => true
])
->add('billingAddress', AddressType::class, [
'required' => false
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Order::class,
'csrf_protection' => false,
'allow_extra_fields' => true,
'cascade_validation' => true
]);
}
public function getBlockPrefix()
{
return '';
}
}
。
class AddressType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('line1', TextType::class);
// ...
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Address::class,
'allow_extra_fields' => true
]);
}
public function getBlockPrefix()
{
return '';
}
}
表单事件是您需要的:https://symfony.com/doc/current/form/form/events.html
例如,如果要在表单提交后删除billingAddress
字段,则可以这样做:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class)
->add('deliveryAddress', AddressType::class, [
'required' => true
])
->add('billingAddress', AddressType::class, [
'required' => false
]);
$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
if (empty($data['billingAddress'])) {
$form->remove('billingAddress');
}
});
}
仔细阅读文档以了解哪个事件将是您的场景。
尝试将" billingaddress"字段的" by_reference"选项设置为false,以确保称为设置器。
http://symfony.com/doc/current/referent/forms/types/form.html#by-reference
非常感谢雷南(Renan)和拉斐尔(Raphael)的答案,因为我发现了下面的解决方案,该解决方案既适用于部分补丁和完整的帖子请求。
class CheckoutType extends AbstractType
{
/** @var bool */
private $removeBilling = false;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class)
->add('deliveryAddress', AddressType::class, [
'constraints' => [new Valid]
])
->add('billingAddress', AddressType::class, [
'required' => false,
'constraints' => [new Valid]
])
->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit'])
->addEventListener(FormEvents::POST_SUBMIT, [$this, 'onPostSubmit']);
}
public function onPreSubmit(FormEvent $event)
{
$data = $event->getData();
$this->removeBilling = array_key_exists('billingAddress', $data) && is_null($data['billingAddress']);
}
public function onPostSubmit(FormEvent $event)
{
if ($this->removeBilling) {
$event->getData()->setBillingAddress(null);
}
}
}