Symfony API平台中MongoDb嵌入式文档上的反规范化器

时间:2020-03-17 15:33:03

标签: symfony symfony4 api-platform.com

我正在尝试使用API​​ Platform捆绑软件在使用Symfony 4.4的嵌入式MongoDB文档上运行反规范化器(数据输入)。对于标准化(数据输出),这可以按预期工作,但是对于非标准化过程,嵌入式数据仅对父数据没有触发。

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

这是我的services.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;
    }
}

1 个答案:

答案 0 :(得分:2)

如果您查看文档,会发现序列化程序组件没有任何serializer.denormalizer服务, 因此,自动发现不会检测到您的班级。 Symfony Service Tags

您需要遵循并实现规范化程序,该规范化程序在单个类中同时实现规范化程序和去规范化程序逻辑,并将其注册为规范化程序Normalizer & Encoder usages

这听起来听起来有点令人困惑,但是您的规范化器会通过将序列化逻辑标记为适当的方法,来对是否具有DenormalizerInterface进行规范化和是否具有NormalizerInfterface进行规范化处理。

它自己的API平台提供了有关两者如何工作的示例:decorating-a-serializer-and-adding-extra-data 这是您在api平台上装饰Normalizer的方法:

api / config / services.yaml

services:
    'App\Serializer\ApiNormalizer':
        decorates: 'api_platform.jsonld.normalizer.item'
        arguments: [ '@App\Serializer\ApiNormalizer.inner' ]

或者您可以按照symfony方式注册此规范化器:

config / services.yaml

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

您可以修改逻辑并为每个实体创建Normalizer类。无论您使用哪种数据库,对于PHP和Symfony来说,都是对象。

在此处查看完整的文档以了解其实现方式:Serializer Docs

相关问题