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

Symfony 6:同一关联对象仅首次序列化Blob字段正常,后续为空

同一用户实体多次序列化时Blob字段仅首次返回有效值

实体定义

Post 实体

#[ORM\Entity(repositoryClass: Post::class)]
class Post
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $body = null;

    #[ORM\ManyToOne(inversedBy: 'post')]
    private ?User $user = null;
}

User 实体

#[ORM\Entity(repositoryClass: User::class)]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180, unique: true)]
    private ?string $email = null;

     #[ORM\Column(type: Types::BLOB, nullable: true)]
    private $summary = null;

    #[ORM\OneToMany(mappedBy: 'posts', targetEntity: Post::class)]
    private Collection $posts;
}

二者为一对多关联:一个用户可拥有多篇帖子,一篇帖子仅属于一个用户。

序列化处理与问题表现

User::$summary是数据库Blob类型,因此实现了StreamNormalizer将PHP流资源转为字符串:

class StreamNormalizer implements NormalizerInterface
{
    public function normalize($topic, string $format = null, array $context = [])
    {
        $data = stream_get_contents($topic);
        return $data;
    }

    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {
        return is_resource($data);
    }
}

Post控制器的feed路由逻辑:

#[Route('/feed', name: 'app_post_feed', methods: 'GET')]
public function feed(EntityManagerInterface $entityManager): Response
{
    $posts = $entityManager->getRepository(Post::class)->findAll();
    
    return $this->json($posts);
}

当同一用户发布多篇帖子时,JSON响应中仅第一篇帖子关联的用户summary有值,后续出现的同一用户对象的summary为空:

[
    {
        "id": 1,
        "user": {
            "id": 1,
            "summary": "This is a summary",
            "email": "test@example.com",
            "userIdentifier": "test@example.com",
            "verified": false
        }
    },
    {
        "id": 2,
        "user": {
            "id": 1,
            "summary": "",
            "email": "test@example.com",
            "userIdentifier": "test@example.com",
            "verified": false
        }
    }
]

猜测这是序列化组件为避免重复序列化同一对象的优化行为,但预期同一实体的所有实例数据应一致。

已尝试的无效解决方案

  1. 调整Normalizer尝试处理非资源类型:
class StreamNormalizer implements NormalizerInterface
{
    public function normalize($topic, string $format = null, array $context = [])
    {
        $data = is_resource($topic) ? stream_get_contents($topic) : $topic;
        return $data;
    }

    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {
        return is_resource($data);
    }
}
  1. 修改User实体的getter方法:
public function getSummary()
{
    return is_resource($this->summary) ? stream_get_contents($this->summary) : $this->summary;
}

以上两种调整均未解决问题,求问如何让重复出现的同一实体对象返回一致的序列化结果?

内容的提问来源于stack exchange,提问作者Alex Carter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:22:03