2016-12-12 134 views
0

我有一個/checkout JSON API端點,它允許可選的billingAddress參數以及其他參數(如電子郵件和deliveryAddress)。Symfony窗​​體 - 允許刪除嵌套窗體關聯實體

這些地址存儲在與Order實體相關的Address實體中。

如果用戶輸入其billingAddress,一切都很好,但如果用戶刪除以前提交的帳單地址,我無法找到任何方法刪除billingAddress實體。理想情況下,要刪除帳單地址我會使用下面的JSON POST請求。

{ 
    "email": "[email protected]", 
    "deliveryAddress": { 
     "line1": "1 Box Lane" 
    }, 
    "billingAddress": null 
} 

這是所有可能的Symfony形式?

有關當前設置的簡單說明,請參見下文。

實體

/** 
* @ORM\Entity 
*/ 
class Order 
{ 
    // ... 

    /** 
    * @var Address 
    * 
    * @ORM\OneToOne(targetEntity = "Address", cascade = {"persist", "remove"}) 
    * @ORM\JoinColumn(name = "deliveryAddressId", referencedColumnName = "addressId") 
    */ 
    private $deliveryAddress; 

    /** 
    * @var Address 
    * 
    * @ORM\OneToOne(targetEntity = "Address", cascade = {"persist", "remove"}, orphanRemoval = true) 
    * @ORM\JoinColumn(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; 
    } 

    // ... 
} 

/** 
* @ORM\Entity 
*/ 
class Address 
{ 
    // ... 

    /** 
    * @var string 
    * 
    * @ORM\Column(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 ''; 
    } 
} 

回答

0

表事件是你所需要的:https://symfony.com/doc/current/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'); 
     } 
    }); 
} 

仔細閱讀文檔知道哪個事件對您的情況最好。

+0

有趣的想法,已經適應了這個只是刪除元素沒有更新實體。稍後我會有機會發布更新。 Thnaks – Nick

0

非常感謝勒南和拉斐爾的答案,因爲他們使我發現下面的解決方案,同時適用於一個部分區塊和完整的POST請求。

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); 
     } 
    } 

}