如何创建自定义规范化器
Serializer 组件 使用规范化器将任何数据转换为数组。该组件提供了几个 内置规范化器,但您可能需要创建自己的规范化器来转换不受支持的数据结构。
创建新的规范化器
假设您想在序列化过程中添加、修改或删除一些属性。为此,您必须创建自己的规范化器。但是,通常最好让 Symfony 规范化对象,然后挂钩到规范化以自定义规范化数据。为此,您可以注入 NormalizerInterface
并将其连接到 Symfony 的对象规范化器。这将使您可以访问 $normalizer
属性,该属性负责处理大部分规范化过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
// src/Serializer/TopicNormalizer.php
namespace App\Serializer;
use App\Entity\Topic;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class TopicNormalizer implements NormalizerInterface
{
public function __construct(
#[Autowire(service: 'serializer.normalizer.object')]
private readonly NormalizerInterface $normalizer,
private UrlGeneratorInterface $router,
) {
}
public function normalize($topic, ?string $format = null, array $context = []): array
{
$data = $this->normalizer->normalize($topic, $format, $context);
// Here, add, edit, or delete some data:
$data['href']['self'] = $this->router->generate('topic_show', [
'id' => $topic->getId(),
], UrlGeneratorInterface::ABSOLUTE_URL);
return $data;
}
public function supportsNormalization($data, ?string $format = null, array $context = []): bool
{
return $data instanceof Topic;
}
public function getSupportedTypes(?string $format): array
{
return [
Topic::class => true,
];
}
}
在您的应用中注册它
在 Symfony 应用程序中使用此规范化器之前,必须将其注册为服务,并使用 serializer.normalizer
进行标记。如果您使用的是 默认 services.yaml 配置,则会自动完成此操作!
如果您不使用 autoconfigure
,则必须使用 serializer.normalizer
标记该服务。您也可以使用此方法设置优先级(值越高表示在过程中调用得越早)
1 2 3 4 5 6 7 8
# config/services.yaml
services:
# ...
App\Serializer\TopicNormalizer:
tags:
# register the normalizer with a high priority (called earlier)
- { name: 'serializer.normalizer', priority: 500 }
规范化器/反规范化器的性能
为了确定必须使用哪个规范化器(或反规范化器)来处理对象,Serializer 类将循环调用所有已注册规范化器(或反规范化器)的 supportsNormalization() (或 supportsDenormalization())。
此外,NormalizerInterface 和 DenormalizerInterface 都包含 getSupportedTypes()
方法。此方法允许规范化器或反规范化器声明它们可以处理的对象类型,以及它们是否可缓存。有了这些信息,即使 supports*()
调用不可缓存,Serializer 也可以跳过大量对 supports*()
的方法调用,从而在某些情况下显着提高性能。
getSupportedTypes()
方法应返回一个数组,其中键表示支持的类型,值指示 supports*()
方法调用的结果是否可以缓存。返回数组的格式如下
- 特殊键
object
可用于指示规范化器或反规范化器支持任何类或接口。 - 特殊键
*
可用于指示规范化器或反规范化器可能支持任何类型。 - 数组中的其他键应对应于规范化器或反规范化器支持的特定类型。
- 与每种类型关联的值应为布尔值,指示该类型的
supports*()
方法调用的结果是否可以缓存。值true
表示结果可缓存,而false
表示结果不可缓存。 - 类型的
null
值表示规范化器或反规范化器不支持该类型。
以下是如何使用 getSupportedTypes()
方法的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class MyNormalizer implements NormalizerInterface
{
// ...
public function getSupportedTypes(?string $format): array
{
return [
'object' => null, // Doesn't support any classes or interfaces
'*' => false, // Supports any other types, but the result is not cacheable
MyCustomClass::class => true, // Supports MyCustomClass and result is cacheable
];
}
}
注意
supports*()
方法的实现不应假设在之前已调用 getSupportedTypes()
。