You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

API Platform:使用反序列化保存OneToOne关联ID失败求助

问题描述

我尝试为OneToOne关联配置正确的序列化(normalization)和反序列化(denormalization),希望不使用Processor类就能持久化关联列的ID。但通过CompanyLogo实体发起POST请求后,CompanyLogo中的company_id和Company中的company_logo_url_id始终无法保存。附上分组和端点定义,不确定分组配置是否正确,求帮助。

CompanyLogo实体原代码

#[Vich\Uploadable]
#[ORM\Entity]
#[ApiResource(
    types: ['https://schema.org/MediaObject'],
    operations: [
        new Post(
            uriTemplate: '/company/{companyId}/logo',
            inputFormats: ['multipart' => ['multipart/form-data']],
            uriVariables: [
                'companyId' => new Link(
                    fromProperty: 'companyLogoUrl',
                    fromClass: Company::class
                )
            ],
            openapi: new Model\Operation(
                requestBody: new Model\RequestBody(
                    content: new \ArrayObject([
                        'multipart/form-data' => [
                            'schema' => [
                                'type' => 'object',
                                'properties' => [
                                    'file' => [
                                        'type' => 'string',
                                        'format' => 'binary'
                                    ]
                                ]
                            ]
                        ]
                    ])
                )
            ),
        )
    ],
    outputFormats: ['jsonld' => ['application/ld+json']],
    normalizationContext: ['groups' => ['companyLogo:read']],
    denormalizationContext: ['groups' => ['companyLogo:write']],
)]
class CompanyLogo
{
    // ... 其他字段

    #[ORM\OneToOne(inversedBy: 'companyLogoUrl', targetEntity: Company::class)]
    #[ORM\JoinColumn(name: 'company_id', referencedColumnName: 'id', unique: true, nullable: false)]
    #[Groups(['companyLogo:read', 'companyLogo:write'])]
    private ?Company $company = null;
}

Company实体原代码

class Company
{
    #[ORM\OneToOne(mappedBy: 'company', targetEntity: CompanyLogo::class, cascade: ['persist', 'remove'])]
    #[ORM\JoinColumn(nullable: true)]
    #[ApiProperty(types: ['https://schema.org/image'])]
    #[Groups(['company:read', 'company:write'])]
    public ?CompanyLogo $companyLogoUrl = null;
}

解决思路及修正方案

1. 修正URI变量的关联映射

原配置中uriVariables的fromProperty指向错误:Company的companyLogoUrl是mappedBy端(不持有外键),而CompanyLogo的company是inversedBy端(持有外键),正确映射应指向CompanyLogo的company属性,让API平台自动将URI中的companyId绑定到该字段。

2. 同步双向关联的两端

双向OneToOne关联需要手动同步两端的属性,否则仅设置一端无法完成完整的关联绑定,导致外键字段无法持久化。

3. 确保实体具备完整的Setter/Getter方法

原代码中缺少必要的Setter方法,API平台无法正确完成关联对象的赋值操作。


修正后的CompanyLogo实体

#[Vich\Uploadable]
#[ORM\Entity]
#[ApiResource(
    types: ['https://schema.org/MediaObject'],
    operations: [
        new Post(
            uriTemplate: '/company/{companyId}/logo',
            inputFormats: ['multipart' => ['multipart/form-data']],
            uriVariables: [
                'companyId' => new Link(
                    fromProperty: 'company', // 修正:指向CompanyLogo的company属性
                    fromClass: CompanyLogo::class
                )
            ],
            openapi: new Model\Operation(
                requestBody: new Model\RequestBody(
                    content: new \ArrayObject([
                        'multipart/form-data' => [
                            'schema' => [
                                'type' => 'object',
                                'properties' => [
                                    'file' => [
                                        'type' => 'string',
                                        'format' => 'binary'
                                    ]
                                ]
                            ]
                        ]
                    ])
                )
            ),
        )
    ],
    outputFormats: ['jsonld' => ['application/ld+json']],
    normalizationContext: ['groups' => ['companyLogo:read']],
    denormalizationContext: ['groups' => ['companyLogo:write']],
)]
class CompanyLogo
{
    // ... 其他字段

    #[ORM\OneToOne(inversedBy: 'companyLogoUrl', targetEntity: Company::class)]
    #[ORM\JoinColumn(name: 'company_id', referencedColumnName: 'id', unique: true, nullable: false)]
    #[Groups(['companyLogo:read', 'companyLogo:write'])]
    private ?Company $company = null;

    // 修正setCompany方法,同步双向关联
    public function setCompany(?Company $company): self
    {
        $this->company = $company;
        // 同步Company端的关联,避免循环调用
        if ($company !== null && $company->getCompanyLogoUrl() !== $this) {
            $company->setCompanyLogoUrl($this);
        }
        return $this;
    }

    public function getCompany(): ?Company
    {
        return $this->company;
    }

    // ... VichUploadable相关的文件处理方法(需确保存在)
}

修正后的Company实体

class Company
{
    #[ORM\OneToOne(mappedBy: 'company', targetEntity: CompanyLogo::class, cascade: ['persist', 'remove'])]
    #[ORM\JoinColumn(nullable: true)]
    #[ApiProperty(types: ['https://schema.org/image'])]
    #[Groups(['company:read', 'company:write'])]
    public ?CompanyLogo $companyLogoUrl = null;

    // 新增setter方法,同步双向关联
    public function setCompanyLogoUrl(?CompanyLogo $companyLogoUrl): self
    {
        $this->companyLogoUrl = $companyLogoUrl;
        // 避免循环调用,仅当对方未绑定当前实例时同步
        if ($companyLogoUrl !== null && $companyLogoUrl->getCompany() !== $this) {
            $companyLogoUrl->setCompany($this);
        }
        return $this;
    }

    public function getCompanyLogoUrl(): ?CompanyLogo
    {
        return $this->companyLogoUrl;
    }
}

内容的提问来源于stack exchange,提问作者Filip Stojanovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:56:10