Платформа API - onPreSerialize с резолвером URI MediaObject в группе нормализации - PullRequest
0 голосов
/ 10 октября 2019

У меня есть MediaObject, представленный в качестве подресурса в группе «модули» контекста нормализации:

/**
 * @ApiResource(
 *     attributes={"access_control"="is_granted('ROLE_ADMIN')"},
 *     collectionOperations={
 *          "get",
 *          "post",
 *          "allData"={
 *              "method"="GET",
 *              "path"="/appdata",
 *              "normalization_context"={"groups"={"modules"}},
 *              "access_control"="is_granted('IS_AUTHENTICATED_ANONYMOUSLY')"
 *          }
 *     }
 * )
 * @ORM\Entity(repositoryClass="App\Repository\LearningModuleRepository")
 * @UniqueEntity("identifier")
 *
 */
class LearningModule
/**
 * @ORM\Entity(
 *     repositoryClass="App\Repository\MediaObjectRepository"
 * )
 * @ApiResource(
 *     iri="http://schema.org/MediaObject",
 *     normalizationContext={
 *         "groups"={"media_object_read"},
 *     },
 *     attributes={"access_control"="is_granted('ROLE_ADMIN')"},
 *     collectionOperations={
 *         "post"={
 *             "controller"=CreateMediaObject::class,
 *             "deserialize"=false,
 *             "validation_groups"={"Default", "media_object_create"},
 *             "swagger_context"={
 *                 "consumes"={
 *                     "multipart/form-data",
 *                 },
 *                 "parameters"={
 *                     {
 *                         "in"="formData",
 *                         "name"="file",
 *                         "type"="file",
 *                         "description"="The file to upload",
 *                     },
 *                 },
 *             },
 *         },
 *         "get",
 *     },
 *     itemOperations={
 *         "get",
 *         "delete"
 *     },
 * )
 * @Vich\Uploadable
 */
class MediaObject


    /**
     * @var string|null
     *
     * @ApiProperty(iri="http://schema.org/contentUrl")
     * @Groups({"media_object_read", "modules"})
     */
    public $contentUrl;

    /**
     * @var string|null
     * @Groups({"modules"})
     * @ORM\Column(nullable=true)
     */
    public $filePath;

При отображении через группу нормализации я получаю только filePath, но не contentUrl. Я предполагаю, что проблема связана с ContentUrlSubscriber, как указано в официальных документах :

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::VIEW => ['onPreSerialize', EventPriorities::PRE_SERIALIZE],
        ];
    }

    public function onPreSerialize(GetResponseForControllerResultEvent $event): void
    {
        $controllerResult = $event->getControllerResult();
        $request = $event->getRequest();

        if ($controllerResult instanceof Response || !$request->attributes->getBoolean('_api_respond', true)) {
            return;
        }

        if (!($attributes = RequestAttributesExtractor::extractAttributes($request)) || !\is_a($attributes['resource_class'], MediaObject::class, true)) {
            return;
        }

        $mediaObjects = $controllerResult;

        if (!is_iterable($mediaObjects)) {
            $mediaObjects = [$mediaObjects];
        }

        foreach ($mediaObjects as $mediaObject) {
            if (!$mediaObject instanceof MediaObject) {
                continue;
            }

            $mediaObject->contentUrl = $this->storage->resolveUri($mediaObject, 'file');
        }
    }

Кто-нибудь знает, как обрабатывать preSerialization в этом случае?

Спасибо

1 Ответ

0 голосов
/ 10 октября 2019

Я нашел решение этой проблемы:

  • Обратный вызов на PRE_SERIALIZE прерван, поскольку объект LearningModule (не MediaObject) запустил сериализацию ($ attribute ['resource_class)'] === LearningModule).

  • Чтобы преодолеть это ограничение, следует использовать оформленный нормализатор следующим образом:

<?php

namespace App\Serializer;

use App\Entity\MediaObject;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Vich\UploaderBundle\Storage\StorageInterface;

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

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

        $this->decorated = $decorated;
        $this->storage = $storage;
    }

    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 ($object instanceof MediaObject) {
            $data['contentUrl'] = $this->storage->resolveUri( $object, 'file');
        }

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

Подробности реализации можно найти здесь: https://api -platform.com / документы / ядро ​​/ сериализации / # декорирования-а-сериалайзер-и добавляющие-экстра-данных

...