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
相关产品推荐
相关产品推荐

