Symfony 序列化器:规范化后删除字段
Symfony serializer: removing fields after normalization
升级到 Api 平台 2.6 后,非 ApiResource
实体开始被序列化 (ld-json) 以及伪造的标识符及其类型。例如:
{
"@type": "MetaData",
"@id": "_:11294",
"id": "bf1e417c-27ff-48c1-a591-40e5a43c708c",
"key": "key1",
"value": "value1"
}
我们想删除这些字段。为此,我尝试实现一个自定义规范化器,希望能够在对象转换为数组之后和数组转换为 json.
之前挂钩
查看已注册的规范化器:
----------------------------------------------------------- ---------- ---------------------------------------------------------------------------
Service ID priority Class name
----------------------------------------------------------- ---------- ---------------------------------------------------------------------------
api_platform.serializer.normalizer.item -895 ApiPlatform\Core\Serializer\ItemNormalizer
api_platform.problem.normalizer.constraint_violation_list -780 ApiPlatform\Core\Problem\Serializer\ConstraintViolationListNormalizer
api_platform.hydra.normalizer.collection_filters -985 ApiPlatform\Core\Hydra\Serializer\CollectionFiltersNormalizer
api_platform.hydra.normalizer.error -800 ApiPlatform\Core\Hydra\Serializer\ErrorNormalizer
api_platform.hydra.normalizer.entrypoint -800 ApiPlatform\Core\Hydra\Serializer\EntrypointNormalizer
api_platform.hydra.normalizer.constraint_violation_list -780 ApiPlatform\Core\Hydra\Serializer\ConstraintViolationListNormalizer
api_platform.hydra.normalizer.documentation -800 ApiPlatform\Core\Hydra\Serializer\DocumentationNormalizer
api_platform.jsonld.normalizer.object -995 ApiPlatform\Core\JsonLd\Serializer\ObjectNormalizer
api_platform.swagger.normalizer.api_gateway -780 ApiPlatform\Core\Swagger\Serializer\ApiGatewayNormalizer
api_platform.openapi.normalizer.api_gateway -780 ApiPlatform\Core\Swagger\Serializer\ApiGatewayNormalizer
api_platform.serializer.uuid_denormalizer ApiPlatform\Core\Bridge\RamseyUuid\Serializer\UuidDenormalizer
serializer.denormalizer.array -990 Symfony\Component\Serializer\Normalizer\ArrayDenormalizer
serializer.normalizer.object -1000 Symfony\Component\Serializer\Normalizer\ObjectNormalizer
serializer.normalizer.problem -890 Symfony\Component\Serializer\Normalizer\ProblemNormalizer
serializer.normalizer.json_serializable -900 Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer
serializer.normalizer.datetime -910 Symfony\Component\Serializer\Normalizer\DateTimeNormalizer
serializer.normalizer.data_uri -920 Symfony\Component\Serializer\Normalizer\DataUriNormalizer
serializer.normalizer.dateinterval -915 Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer
serializer.normalizer.datetimezone -915 Symfony\Component\Serializer\Normalizer\DateTimeZoneNormalizer
serializer.normalizer.constraint_violation_list -915 Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer
api_platform.problem.normalizer.error -810 ApiPlatform\Core\Problem\Serializer\ErrorNormalizer
----------------------------------------------------------- ---------- ---------------------------------------------------------------------------
我得到的最接近的是 api_platform.jsonld.normalizer.object
但是如果我使用的优先级是 -994,我得到原始对象,如果我使用 -996 我得到单个 string/boolean/numeric 字段(所以归一化之后)。
如果@id 以 _:
开头,是否有任何方法可以获得关联数组,以便删除 @id 和 @type?
添加这些属性的代码行似乎是 this 然而,这可能只是添加到上下文中,它不包括规范化数组中的那些字段。
不知道如何装饰序列化器,但我会用 event subscriber.
来处理你的问题
“POST_SERIALIZE”优先级包含序列化的响应体,您可以获取并修改。
像这样:
<?php
namespace App\EventSubscriber;
use ApiPlatform\Core\EventListener\EventPriorities;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class PostSerializeProductEventSubScriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => ["removeFakeIdentifiersFromJsonLdResponseBody", EventPriorities::POST_SERIALIZE],
];
}
public function removeFakeIdentifiersFromJsonLdResponseBody(ViewEvent $event): void
{
$requestAcceptHeader = $event->getRequest()->headers->get('accept', 'none');
if (str_contains($requestAcceptHeader, "application/ld+json")) {
$this->removefakeIdentifiersFromResponseBody($event);
}
}
private function removefakeIdentifiersFromResponseBody(ViewEvent $event): void
{
$responseBody = $event->getControllerResult();
$decodedResponseBody = json_decode($responseBody);
$this->removeFakeIdentifiersFromObject($decodedResponseBody);
$encodedResponseBody = json_encode($decodedResponseBody);
$event->setControllerResult($encodedResponseBody);
}
private function removeFakeIdentifiersFromObject(object $responseBody): void
{
foreach ($responseBody as $property => $value) {
$this->removeFakeIdRecursively($property, $value, $responseBody);
}
}
private function removeFakeIdRecursively(string $property, mixed $value, object $responseBody): void
{
if ($property === "@id" && str_starts_with($value, "_:")) {
unset($responseBody->$property); // removes "@id"
unset($responseBody->{"@type"});
} elseif (is_object($value)) {
$this->removeFakeIdentifiersFromObject($value);
} elseif (is_array($value)) {
foreach ($value as $object) {
if (is_object($object)) {
$this->removeFakeIdentifiersFromObject($object);
}
}
}
}
}
升级到 Api 平台 2.6 后,非 ApiResource
实体开始被序列化 (ld-json) 以及伪造的标识符及其类型。例如:
{
"@type": "MetaData",
"@id": "_:11294",
"id": "bf1e417c-27ff-48c1-a591-40e5a43c708c",
"key": "key1",
"value": "value1"
}
我们想删除这些字段。为此,我尝试实现一个自定义规范化器,希望能够在对象转换为数组之后和数组转换为 json.
之前挂钩查看已注册的规范化器:
----------------------------------------------------------- ---------- ---------------------------------------------------------------------------
Service ID priority Class name
----------------------------------------------------------- ---------- ---------------------------------------------------------------------------
api_platform.serializer.normalizer.item -895 ApiPlatform\Core\Serializer\ItemNormalizer
api_platform.problem.normalizer.constraint_violation_list -780 ApiPlatform\Core\Problem\Serializer\ConstraintViolationListNormalizer
api_platform.hydra.normalizer.collection_filters -985 ApiPlatform\Core\Hydra\Serializer\CollectionFiltersNormalizer
api_platform.hydra.normalizer.error -800 ApiPlatform\Core\Hydra\Serializer\ErrorNormalizer
api_platform.hydra.normalizer.entrypoint -800 ApiPlatform\Core\Hydra\Serializer\EntrypointNormalizer
api_platform.hydra.normalizer.constraint_violation_list -780 ApiPlatform\Core\Hydra\Serializer\ConstraintViolationListNormalizer
api_platform.hydra.normalizer.documentation -800 ApiPlatform\Core\Hydra\Serializer\DocumentationNormalizer
api_platform.jsonld.normalizer.object -995 ApiPlatform\Core\JsonLd\Serializer\ObjectNormalizer
api_platform.swagger.normalizer.api_gateway -780 ApiPlatform\Core\Swagger\Serializer\ApiGatewayNormalizer
api_platform.openapi.normalizer.api_gateway -780 ApiPlatform\Core\Swagger\Serializer\ApiGatewayNormalizer
api_platform.serializer.uuid_denormalizer ApiPlatform\Core\Bridge\RamseyUuid\Serializer\UuidDenormalizer
serializer.denormalizer.array -990 Symfony\Component\Serializer\Normalizer\ArrayDenormalizer
serializer.normalizer.object -1000 Symfony\Component\Serializer\Normalizer\ObjectNormalizer
serializer.normalizer.problem -890 Symfony\Component\Serializer\Normalizer\ProblemNormalizer
serializer.normalizer.json_serializable -900 Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer
serializer.normalizer.datetime -910 Symfony\Component\Serializer\Normalizer\DateTimeNormalizer
serializer.normalizer.data_uri -920 Symfony\Component\Serializer\Normalizer\DataUriNormalizer
serializer.normalizer.dateinterval -915 Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer
serializer.normalizer.datetimezone -915 Symfony\Component\Serializer\Normalizer\DateTimeZoneNormalizer
serializer.normalizer.constraint_violation_list -915 Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer
api_platform.problem.normalizer.error -810 ApiPlatform\Core\Problem\Serializer\ErrorNormalizer
----------------------------------------------------------- ---------- ---------------------------------------------------------------------------
我得到的最接近的是 api_platform.jsonld.normalizer.object
但是如果我使用的优先级是 -994,我得到原始对象,如果我使用 -996 我得到单个 string/boolean/numeric 字段(所以归一化之后)。
如果@id 以 _:
开头,是否有任何方法可以获得关联数组,以便删除 @id 和 @type?
添加这些属性的代码行似乎是 this 然而,这可能只是添加到上下文中,它不包括规范化数组中的那些字段。
不知道如何装饰序列化器,但我会用 event subscriber.
来处理你的问题“POST_SERIALIZE”优先级包含序列化的响应体,您可以获取并修改。
像这样:
<?php
namespace App\EventSubscriber;
use ApiPlatform\Core\EventListener\EventPriorities;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class PostSerializeProductEventSubScriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => ["removeFakeIdentifiersFromJsonLdResponseBody", EventPriorities::POST_SERIALIZE],
];
}
public function removeFakeIdentifiersFromJsonLdResponseBody(ViewEvent $event): void
{
$requestAcceptHeader = $event->getRequest()->headers->get('accept', 'none');
if (str_contains($requestAcceptHeader, "application/ld+json")) {
$this->removefakeIdentifiersFromResponseBody($event);
}
}
private function removefakeIdentifiersFromResponseBody(ViewEvent $event): void
{
$responseBody = $event->getControllerResult();
$decodedResponseBody = json_decode($responseBody);
$this->removeFakeIdentifiersFromObject($decodedResponseBody);
$encodedResponseBody = json_encode($decodedResponseBody);
$event->setControllerResult($encodedResponseBody);
}
private function removeFakeIdentifiersFromObject(object $responseBody): void
{
foreach ($responseBody as $property => $value) {
$this->removeFakeIdRecursively($property, $value, $responseBody);
}
}
private function removeFakeIdRecursively(string $property, mixed $value, object $responseBody): void
{
if ($property === "@id" && str_starts_with($value, "_:")) {
unset($responseBody->$property); // removes "@id"
unset($responseBody->{"@type"});
} elseif (is_object($value)) {
$this->removeFakeIdentifiersFromObject($value);
} elseif (is_array($value)) {
foreach ($value as $object) {
if (is_object($object)) {
$this->removeFakeIdentifiersFromObject($object);
}
}
}
}
}