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);
                }
            }
        }
    }
}