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

Symfony 7中如何压缩存储请求与响应的实体数据

解决方案

推荐方案:自定义Doctrine字段类型

这种方式能让你在实体中依然保持array类型的request和response属性,Doctrine会自动在持久化时压缩数据,读取时自动解压,完全不影响业务代码逻辑。

1. 创建自定义压缩JSON字段类型

新建类src/Doctrine/Type/CompressedJsonType.php:

<?php

namespace App\Doctrine\Type;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\JsonType;

class CompressedJsonType extends JsonType
{
    public const NAME = 'compressed_json';

    public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
    {
        $json = parent::convertToDatabaseValue($value, $platform);
        if ($json === null) {
            return null;
        }
        return gzcompress($json, 9);
    }

    public function convertToPHPValue($value, AbstractPlatform $platform): ?array
    {
        if ($value === null) {
            return null;
        }
        $json = gzuncompress($value);
        return parent::convertToPHPValue($json, $platform);
    }

    public function getName(): string
    {
        return self::NAME;
    }

    public function requiresSQLCommentHint(AbstractPlatform $platform): bool
    {
        return true;
    }
}

2. 修改实体字段类型

更新你的Log实体中的字段注解:

use App\Doctrine\Type\CompressedJsonType;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Column(name: 'request', type: CompressedJsonType::NAME)]
private array $request;

#[ORM\Column(name: 'response', type: CompressedJsonType::NAME, nullable: true)]
private ?array $response = null;

3. 注册自定义字段类型

在config/packages/doctrine.yaml中添加类型注册:

doctrine:
    dbal:
        types:
            compressed_json: App\Doctrine\Type\CompressedJsonType

4. 生成数据库迁移并执行

运行Symfony命令更新数据库结构:

php bin/console make:migration
php bin/console doctrine:migrations:migrate

数据库管理工具中查看解压数据

因为用的是标准gz压缩格式,不同数据库可以用内置函数直接解压查看:

  • MySQL/MariaDB:使用UNCOMPRESS()函数
    SELECT UNCOMPRESS(request) AS request_uncompressed, UNCOMPRESS(response) AS response_uncompressed FROM log_table;
    
  • PostgreSQL:使用pg_uncompress()函数(需安装pgcrypto扩展)
    SELECT pg_uncompress(request) AS request_uncompressed, pg_uncompress(response) AS response_uncompressed FROM log_table;
    
  • SQLite:使用gzuncompress()函数(SQLite 3.38+支持)
    SELECT gzuncompress(request) AS request_uncompressed, gzuncompress(response) AS response_uncompressed FROM log_table;
    

备选方案:实体生命周期回调

如果不想自定义字段类型,也可以用Doctrine的生命周期回调手动处理压缩和解压:

1. 修改实体字段类型为text

#[ORM\Column(name: 'request', type: 'text')]
private string $request;

#[ORM\Column(name: 'response', type: 'text', nullable: true)]
private ?string $response = null;

2. 添加生命周期回调方法

在实体中添加临时属性存储原始数组,以及压缩/解压的回调方法:

use Doctrine\ORM\Mapping as ORM;

private array $rawRequest = [];
private ?array $rawResponse = null;

// 对外提供原始数组的操作方法
public function setRequest(array $request): self
{
    $this->rawRequest = $request;
    return $this;
}

public function getRequest(): array
{
    return $this->rawRequest;
}

public function setResponse(?array $response): self
{
    $this->rawResponse = $response;
    return $this;
}

public function getResponse(): ?array
{
    return $this->rawResponse;
}

// 持久化前压缩数据
#[ORM\PrePersist]
#[ORM\PreUpdate]
public function compressData(): void
{
    $this->request = gzcompress(json_encode($this->rawRequest), 9);
    if ($this->rawResponse !== null) {
        $this->response = gzcompress(json_encode($this->rawResponse), 9);
    }
}

// 加载后解压数据
#[ORM\PostLoad]
public function decompressData(): void
{
    $this->rawRequest = json_decode(gzuncompress($this->request), true) ?? [];
    if ($this->response !== null) {
        $this->rawResponse = json_decode(gzuncompress($this->response), true) ?? null;
    }
}

这种方案需要修改实体结构和业务代码的调用逻辑,不如自定义字段类型优雅,优先推荐第一种方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:08:18