【问题标题】:Symfony Form - Allow removal of nested form associated entitySymfony Form - 允许删除嵌套的表单关联实体
【发布时间】:2016-12-12 18:59:29
【问题描述】:

我有一个/checkout JSON API 端点,它允许在电子邮件和deliveryAddress 等其他参数旁边使用可选的billingAddress 参数。

这些地址存储在与Order 实体相关的Address 实体中。

如果用户输入他们的 billingAddress,一切正常,但如果用户删除了之前提交的帐单地址,我找不到删除 billingAddress 实体的方法。理想情况下,要删除帐单地址,我会使用以下 JSON POST 请求。

{
    "email": "nick@example.com",
    "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 '';
    }
}

【问题讨论】:

    标签: symfony doctrine-orm


    【解决方案1】:

    表单事件是你需要的: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');
            }
        });
    }
    

    仔细阅读文档,了解哪种活动最适合您的场景。

    【讨论】:

    • 有趣的想法,将其调整为简单地删除元素并没有更新实体。稍后我有机会时会发布更新。谢谢
    【解决方案2】:

    尝试将“billingAddress”字段的“by_reference”选项设置为 false,以确保调用 setter。

    http://symfony.com/doc/current/reference/forms/types/form.html#by-reference

    【讨论】:

    • 如果您在请求有效负载中提供 billingAddress: null 它仍然不会被调用。
    【解决方案3】:

    非常感谢 Renan 和 Raphael 的回答,因为他们让我发现了以下解决方案,该解决方案适用于部分 PATCH 和完整 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);
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2022-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多