Пользовательский обработчик циклических ссылок Symfony 4.2 не применяется - PullRequest
0 голосов
/ 12 апреля 2019

Контекст заключается в том, что я пытался настроить пользовательский обработчик циклических ссылок для моих сущностей, который будет влиять на ВСЕ сущности.

Согласно документации (https://symfony.com/doc/current/components/serializer.html#handling-circular-references), мы руководствуемся установкой значения circular_reference_handler в службе serializer в файле config/packages/framework.yaml следующим образом:

framework:
    validation:
        enabled: true

    messenger:
        enabled: true

    assets:
        enabled: true

    serializer:
        circular_reference_handler: App\Services\CircularReferenceHandler
        enable_annotations: true

Моя настоящая проблема заключается в том, что когда сериализатор пытается загрузить обработчик циклических ссылок, мое переопределение, кажется, не существует: изображение, показывающее ссылку на ключ изображение с пустым контекстом

Почему мое переопределение вообще не применяется к контексту ??

Я попытался:

  • Перезагрузить кеш
  • Используйте класс ContextBuilder из моего пакета API Platform
  • Примените его в нормализаторе

Ни один из них не работал

Я показал вам мой yaml, но вот обработчик:

<?php

namespace App\Services;

class CircularReferenceHandler
{
    /**
     * @param object $object
     * @return mixed
     */
    public function __invoke($object)
    {
        return $object->getId();
    }
}

и вот конструктор контекста, который я попытался использовать в качестве альтернативы:

<?php

namespace App\Serializer;

use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
use App\Services\CircularReferenceHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;

final class GlobalSerializerContextBuilder implements SerializerContextBuilderInterface
{
    /**
     * Creates a serialization context from a Request.
     *
     * @param Request    $request
     * @param bool       $normalization
     * @param array|null $extractedAttributes
     *
     * @return array
     */
    public function createFromRequest(Request $request, bool $normalization, array $extractedAttributes = null): array
    {
        $resourceClass = $context['resource_class'] ?? null;

        $context[AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER] = CircularReferenceHandler::class;

        return $context;
    }
}

и вот где я зарегистрировал это ( doc ):

    App\Serializer\GlobalSerializerContextBuilder:
        decorates: 'api_platform.serializer.context_builder'
        arguments: ['@App\Serializer\GlobalSerializerContextBuilder.inner']
        autoconfigure: false

Я ожидал мой пользовательский циркуляр_референт_хандлер, который будет применен при использовании метода AbstractNormalizer->handleCircularReference(), , но факт - контекст, полученный в этом методе, не включает мой дополнительный ключ / значение пара (например, ['circular_reference_handler => App\Services\CircularReferenceHandler]

1 Ответ

0 голосов
/ 12 апреля 2019

Итак, я обнаружил, что допустил ошибку, когда использовал стратегию нормализатора. По сути, если вы хотите глобально изменить сериализатор $context (3-й параметр в SerializerInterface-> serialize ($ data, $ format, array $ context = [] )), тогда Вы должны создать пользовательский Symfony Normalizer.

Вот мой последний класс:

<?php
namespace App\Serializer;

use App\Services\CircularReferenceHandler;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Class ApiNormalizer. Acts as an entrypoint to GLOBALLY alter context for all denormalizers and normalizers ( and subsequenty the serializers ).
 * @package App\Serializer
 */
final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface
{
    private $normalizer;

    public function __construct(NormalizerInterface $normalizer)
    {
        if (!$normalizer instanceof DenormalizerInterface) {
            throw new \InvalidArgumentException('The normalizer must implement the DenormalizerInterface');
        }

        $this->normalizer = $normalizer;
    }

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

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

    public function normalize($object, $format = null, array $context = [])
    {
        $context[AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER] = CircularReferenceHandler::class;
        $context['enable_max_depth'] = true;

        return $this->normalizer->normalize($object, $format, $context);
    }

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

Метод, который нужно посмотреть - просто normalize(). Это единственное место, где мне нужно было внести изменения на данный момент, и интерфейс потребовал, чтобы я по крайней мере заглушил остальные методы, чтобы вы могли игнорировать другие. Однако теперь у меня есть место, где я могу глобально изменять данные или состояние контекста сериализации всякий раз, когда у меня есть такая необходимость.

Надеюсь, это поможет кому-то еще.

...