【问题标题】:Symfony form, One-to-one relationship, one side can be nullSymfony形式,一对一关系,一侧可以为空
【发布时间】:2024-04-24 09:55:02
【问题描述】:

我有一个 MainConfig 实体,它与 LedConfig 实体具有一对一的关系。 LedConfig 可以为空。

<?php

namespace ...


use Doctrine\ORM\Mapping as ORM;
...

/**
 * @ORM\Entity
 */
class MainConfig
{

    ...

    /**
     * @ORM\OneToOne(targetEntity="...\LedConfig", cascade={"all"})
     * @ORM\JoinColumn(name="led_config_id", referencedColumnName="id", nullable=true, unique = true)
     */
    private $ledConfig = null;

    ...

}

<?php

namespace ...


use Doctrine\ORM\Mapping as ORM;
...

/**
 * @ORM\Entity
 */
class LedConfig
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**
     * @ORM\Column(type="float")
     * @Assert\Type(type="float")
     */
    private $lowerVoltageThreshold = 11.9;

    /**
     * @ORM\Column(type="float")
     * @Assert\Type(type="float")
     */
    private $upperVoltageThreshold = 12.85;


}

<?php

namespace ...;

use Symfony\Component\Form\AbstractType;
...

class MainConfigType extends AbstractType
{
    ...

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(...)
            ->add('ledConfig', LedConfigType::class)
            ...
    }
    ...
}

我在不使用 Symfony 表单的情况下自动将主配置插入数据库。因此,如果我在代码中将 led config 设置为 null - 主配置表内的字段 led_config_id 正确设置为 NULL。

但是,当我更新主配置时,我使用的是通过 Symfony 表单处理的 HTTP PUT 请求。 我使用的是 JSON,所以请求正文如下所示:

{..., "ssid":"test","runningMode":"force_on","led_config":null, ...}

处理完表单后,MainConfig 实体中的属性$ledConfig 神奇地实例化为LedConfig 对象,所有属性都设置为NULL?! 并且数据库更新失败,因为它试图用空字段保存 LedEnttiy。 为什么会这样?

有人可以帮助我并指出我做错了什么吗?

编辑: 在表单验证之后,我可以在控制器更新操作中破解它:

/**
 * @Route("...")
 * @Method("PUT")
 */
public function updateMainConfigAction($id, Request $request)
{
    $requestData = \GuzzleHttp\json_decode($request->getContent(), true);

    ...

    if (!$form->isValid()) {
        throw $this->throwApiProblemValidationException($form);
    }

    if (empty($requestData['led_config'])) {
        $mainConfig->setLedConfig(null);
    }

    $em = $this->getDoctrine()->getManager();
    $em->persist($mainConfig);
    $em->flush();

    ...

}

但这有点脏……

【问题讨论】:

    标签: doctrine-orm symfony-forms one-to-one symfony-3.2


    【解决方案1】:

    Symfony 的 FormType 上有 empty_datarequired 选项。

    empty_data 选项具有以下行为:

    1. 当设置了data_class并且required选项是true,那么empty_data是新的$data_class();
    2. 当设置了data_class且required选项为false时,则empty_data为空;
    3. 当data_class未设置且compound选项为true时,则empty_data为空数组;
    4. 当未设置data_class且compound选项为false时,则empty_data为空字符串。

    required 选项默认为true,并且在 ledConfig 字段中设置了 data_class,因此当您将其留空时,会为其设置新类。如果您希望在未选择任何值时将 ledConfig 字段显式设置为null,则可以直接设置empty_data 选项。

    在您的情况下,您需要 #2 方案,因此在 ledConfig 字段中将 required 选项设置为 falseempty_data 选项设置为 null

    ...
    $builder
        ->add(...)
        ->add('ledConfig', LedConfigType::class, array(
            'required' => false
            'empty_data' => null
        ))
        ...
    

    【讨论】:

    • 嗯...我已经尝试过...array('required' =&gt; false),但没有帮助。
    • 尽管理论上它应该可以工作 XD 我必须更仔细地研究代码。
    • 您是否尝试在 ledConfig 字段中将 empty_data 选项设置为 null
    • 如果我设置-&gt;add('ledConfig', LedConfigType::class, array('required' =&gt; false, 'empty_data' =&gt; null)),它就可以工作。我会接受你的回答,但请更新代码,所以如果其他人有同样的问题,他们不需要阅读 cmets 来找到正确的解决方案:) Tnx!
    最近更新 更多