Денормализатор на внедренном документе MongoDb на платформе API Symfony - PullRequest
1 голос
/ 17 марта 2020

Я пытаюсь запустить денормализатор (данные в) для встроенного документа MongoDB с Symfony 4.4, используя пакет API Platform. Это работает, как и ожидалось, для нормализации (вывода данных), но для процесса денормализации ничего не запускается во встроенных данных, только в родительских данных.

Если это так, то мне может понадобиться переместите логи c для денормализации в родительский. Или, возможно, я просто делаю что-то не так. То, что я пытаюсь выполнить sh, - это выбросить исключения для входящих запросов, которые содержат поля, которые были объявлены устаревшими. Классы, которые анализируют аннотации и сканируют атрибуты, работают должным образом, это просто определяет, куда его подключить, и я надеялся, что процесс денормализации во встроенных документах будет работать.

Вот мой 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 Ответ

3 голосов
/ 27 марта 2020

Если вы посмотрите документы, вы обнаружите, что компонент сериализатора не имеет никакой службы serializer.denormalizer, поэтому ваши классы не обнаруживаются при автоматическом обнаружении. Symfony Сервисные теги

Вам необходимо следовать и реализовать Normalizer, который реализует как нормализатор, так и денормализатор logi c в одном классе и зарегистрировать его как нормализатор Использование нормализатора и кодировщика

Тогда соглашение об именах сбивает с толку, как это звучит, но ваш нормализатор позаботится о денормализации, если он имеет DenormalizerInterface, и нормализации, если он имеет NormalizerInfterface, пометив ваши сериализованные логики c соответствующим методом, они будут называться соответственно.

Платформа API сама имеет примеры того, как работают оба: decorating-a-serializer-and-добавление дополнительных данных Вот как вы декорируете нормализатор в API платформа:

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

Вы можете преломить свою логику c и создать класс нормализатора для каждой сущности. Независимо от того, какую БД вы используете, для PHP и Symfony это все объекты.

Go в полных документах, чтобы понять, как это реализовано: Документы Serializer

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...