自定义序列化
在symfony开发中,特别是使用api-platform进行开发时,整个entity可以很方便的被序列化与反序列化
设想有这样一个场景:
你的entity有一个字段存放的是上传文件的路径,但是这个文件是放在oss上的,并且使用了私有读写,所以每一次访问时都需要根据文件路径去生成鉴权访问url
一般的做法是针对整个entity写一个自定义的序列化类,假如你有几十上百个entity,每一个都有同样的需求,那么重复写序列化类就太浪费了。所以今天我们来写一个注解方式的序列化。
对于我个人来说,我喜欢把这个字段定义为json格式,因为文件可能是一个可能是多个,而每一个json里我会存放路径、文件原名、上传后的文件名、大小、格式等数据
代码如下:
# src/Entity/SomeEntity.php
#[ORM\Column(length: 255)]
#[Groups(['expert.read'])]
private array $media = [];
现在我们用命令创建一个自定义序列化类:
php bin/console make:serializer:normalizer
生成MediaNormalizer.php,然后在Entity的属性上加上注解:
#[ORM\Column(length: 255)]
#[Groups(['expert.read'])]
#[Context([MediaNormalizer::SERIALIZER_MEDIA=>true])]
private array $media = [];
接下来我们看看MediaNormalizer.php:
<?php
namespace App\Serializer\Normalizer;
use App\Service\FileUploadService;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class MediaNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;
const SERIALIZER_MEDIA = 'media_array';
public function __construct(
private FileUploadService $fileUploadService
)
{
}
public function normalize($object, ?string $format = null, array $context = []): array
{
foreach ($object as $key => $item) {
if (is_array($item) && isset($item['path'])) {
$object[$key]['url'] = $this->fileUploadService->readFile($item['path']);
} else {
if ($key === 'path') {
$object['url'] = $this->fileUploadService->readFile($item);
}
}
}
return $object;
}
public function supportsNormalization($data, ?string $format = null, array $context = []): bool
{
return is_iterable($data) && key_exists(self::SERIALIZER_MEDIA, $context);
}
public function getSupportedTypes(?string $format): array
{
return ['object' => null, '*' => true];
}
}
在getSupportedTypes方法中我们返回了支持缓存的属性, 然后在supportsNormalization中我们判断data是不是array,并且在content数组中media_array是否存在。在这两个条件都满足情况下 说明就是我们需要进行序列化的字段。 然后在normalize中进行读取oss文件的逻辑。整个代码就完成了,使用也非常的方便