symfonyapi平台下MongoDb嵌入式文档的反规范化

symfonyapi平台下MongoDb嵌入式文档的反规范化,symfony,symfony4,api-platform.com,Symfony,Symfony4,Api Platform.com,我正在尝试使用API平台捆绑包在带有Symfony 4.4的嵌入式MongoDB文档上运行反规范化程序(data in)。这与规范化(数据输出)的预期效果一样,但对于非规范化过程,不会对嵌入数据触发任何操作,只对父数据触发任何操作 如果这是它的工作方式,那么我可能需要将反规范化的逻辑移到父级。或许我只是做错了什么。我试图完成的是对包含已弃用字段的入站请求抛出异常。解析注释和扫描属性的类按预期工作,它只是确定在哪里插入它,我希望嵌入文档上的非规范化过程能够工作 这是我的服务。yaml: 'App\

我正在尝试使用API平台捆绑包在带有Symfony 4.4的嵌入式MongoDB文档上运行反规范化程序(data in)。这与规范化(数据输出)的预期效果一样,但对于非规范化过程,不会对嵌入数据触发任何操作,只对父数据触发任何操作

如果这是它的工作方式,那么我可能需要将反规范化的逻辑移到父级。或许我只是做错了什么。我试图完成的是对包含已弃用字段的入站请求抛出异常。解析注释和扫描属性的类按预期工作,它只是确定在哪里插入它,我希望嵌入文档上的非规范化过程能够工作

这是我的服务。yaml:

'App\Serializer\InvestmentNormalizer':
    arguments: [ '@security.authorization_checker' ]
    tags:
        - { name: 'serializer.normalizer', priority: 64 }
'App\Serializer\InvestmentDenormalizer':
    tags:
        - { name: 'serializer.denormalizer', priority: 64 }
'App\Serializer\ProjectNormalizer':
    tags:
        - { name: 'serializer.normalizer', priority: 64 }
'App\Serializer\ProjectDenormalizer':
    tags:
        - { name: 'serializer.denormalizer', priority: 64 }
然后我的反规范化器类永远不会执行:

class ProjectDenormalizer implements DenormalizerInterface
{
    private const ALREADY_CALLED = 'PROJECT_DENORMALIZER_ALREADY_CALLED';

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        $context[self::ALREADY_CALLED] = true;

        return $this->removeDeprecatedFields($data);
    }

    public function supportsDenormalization($data, $type, $format = null)
    {
        if (isset($context[self::ALREADY_CALLED])) {
            return false;
        }

        return $type == get_class(new Project());
    }

    private function removeDeprecatedFields(array $normalizedData) : array
    {
        $apiPropertyReader = new AnnotationReader(Project::class, ApiProperty::class);
        $deprecatedProperties = $apiPropertyReader->readAllHavingAttribute('deprecationReason');

        $errors = [];

        foreach (array_keys($deprecatedProperties) as $deprecatedPropertyName) {

            if (!isset($normalizedData[$deprecatedPropertyName])) {
                continue;
            }

            $errors[] = $deprecatedPropertyName . ' has been deprecated';
        }

        if (!empty($errors)) {
            throw new DeprecatedFieldException(implode('. ', $errors));
        }

        return $normalizedData;
    }
}

如果您查看文档,您会发现序列化程序组件没有任何
序列化程序。反规范化程序
服务,
因此,自动发现不会检测到您的类

您需要遵循并实现Normalizer,它在单个类中实现Normalizer和denormalizer逻辑,并将其注册为Normalizer

然后名称约定听起来很混乱,但是如果您的规范化程序有
反规范化接口
,那么它负责反规范化,如果它有
规范化接口
,那么它负责非规范化,通过将序列化逻辑标记到适当的方法,它们将被相应地调用

API平台it自身有关于两者如何工作的示例: 下面是如何在api平台中修饰normalizer:

api/config/services.yaml 或者您可以按照symfony方式注册此规范化器:

config/services.yaml 实施:
namespace App\Serializer;

use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;

final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
    private $decorated;

    public function __construct(NormalizerInterface $decorated)
    {
        if (!$decorated instanceof DenormalizerInterface) {
            throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
        }

        $this->decorated = $decorated;
    }

    public function supportsNormalization($data, $format = null)
    {
        return $this->decorated->supportsNormalization($data, $format);
    }

    public function normalize($object, $format = null, array $context = [])
    {
        $data = $this->decorated->normalize($object, $format, $context);
        if (is_array($data)) {
            $data['date'] = date(\DateTime::RFC3339);
        }

        return $data;
    }

    public function supportsDenormalization($data, $type, $format = null)
    {
        return $this->decorated->supportsDenormalization($data, $type, $format);
    }

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        return $this->decorated->denormalize($data, $class, $format, $context);
    }

    public function setSerializer(SerializerInterface $serializer)
    {
        if($this->decorated instanceof SerializerAwareInterface) {
            $this->decorated->setSerializer($serializer);
        }
    }
}
您可以折射逻辑并为每个实体创建规范化器类。不管您使用什么数据库,对于PHP和Symfony,它都是对象


在这里浏览完整的文档以了解它是如何实现的:

API平台选择的命名约定非常混乱,奇怪的是我无法通过分离流程来遵循可靠的实践。我回到办公室后会试试这个。谢谢。事实上,它本质上是实现规范化、非规范化接口的数据转换器类。服务标记将检查它是否是其中一个的实例,并调用相应的方法。您可以尝试注册seprate类以进行反规范化,它应该可以正常工作,只需使用适当的标记,即可被序列化程序捕获。因此,如果在单独的类中尝试,也可以将其标记为反规范化程序?我还没有时间使用api平台对其进行测试,理论上它应该可以工作,symfony希望使用NormalizerInterface实例,使用正确实现的序列化程序(api平台的api_platform.jsonld.normalizer.item)反规范化接口。
services:
    get_set_method_normalizer:
        class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
        tags: [serializer.normalizer]
namespace App\Serializer;

use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;

final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
    private $decorated;

    public function __construct(NormalizerInterface $decorated)
    {
        if (!$decorated instanceof DenormalizerInterface) {
            throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
        }

        $this->decorated = $decorated;
    }

    public function supportsNormalization($data, $format = null)
    {
        return $this->decorated->supportsNormalization($data, $format);
    }

    public function normalize($object, $format = null, array $context = [])
    {
        $data = $this->decorated->normalize($object, $format, $context);
        if (is_array($data)) {
            $data['date'] = date(\DateTime::RFC3339);
        }

        return $data;
    }

    public function supportsDenormalization($data, $type, $format = null)
    {
        return $this->decorated->supportsDenormalization($data, $type, $format);
    }

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        return $this->decorated->denormalize($data, $class, $format, $context);
    }

    public function setSerializer(SerializerInterface $serializer)
    {
        if($this->decorated instanceof SerializerAwareInterface) {
            $this->decorated->setSerializer($serializer);
        }
    }
}