From a07efa7c178fd3f678eef485bcc1aaeb97457818 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Mon, 4 Mar 2019 17:02:37 +0100 Subject: [PATCH 1/4] Create specific normalizers for data transformations and context initialization --- src/Serializer/AddResourceClassNormalizer.php | 111 ++++++++++++++++++ src/Serializer/ApiItemNormalizer.php | 7 ++ src/Serializer/DataTransformerNormalizer.php | 104 ++++++++++++++++ tests/Hydra/Serializer/ItemNormalizerTest.php | 1 + 4 files changed, 223 insertions(+) create mode 100644 src/Serializer/AddResourceClassNormalizer.php create mode 100644 src/Serializer/ApiItemNormalizer.php create mode 100644 src/Serializer/DataTransformerNormalizer.php diff --git a/src/Serializer/AddResourceClassNormalizer.php b/src/Serializer/AddResourceClassNormalizer.php new file mode 100644 index 00000000000..a34cd1e92f1 --- /dev/null +++ b/src/Serializer/AddResourceClassNormalizer.php @@ -0,0 +1,111 @@ +normalizer = $normalizer; + $this->resourceClassResolver = $resourceClassResolver; + $this->iriConverter = $iriConverter; + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + $context['api_denormalize'] = true; + $context['resource_class'] = $class; + + return $this->normalizer->denormalize($data, $class, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + if (ElasticsearchItemNormalizer::FORMAT === $format) { + return false; + } + + return $this->normalizer->supportsDenormalization($data, $type, $format); + } + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = []) + { + try { + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); + } catch (InvalidArgumentException $e) { + $context = $this->initContext(\get_class($object), $context); + $context['api_normalize'] = true; + + return $this->normalizer->normalize($object, $format, $context); + } + + $context = $this->initContext($resourceClass, $context); + $context['api_normalize'] = true; + + if (isset($context['resources'])) { + $resource = $context['iri'] ?? $this->iriConverter->getIriFromItem($object); + $context['resources'][$resource] = $resource; + } + + return $this->normalizer->normalize($object, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + if (!\is_object($data) || $data instanceof \Traversable) { + return false; + } + + return $this->normalizer->supportsNormalization($data, $format); + } + + /** + * {@inheritdoc} + */ + public function hasCacheableSupportsMethod(): bool + { + if ($this->normalizer instanceof CacheableSupportsMethodInterface) { + return $this->normalizer->hasCacheableSupportsMethod(); + } + + return false; + } +} diff --git a/src/Serializer/ApiItemNormalizer.php b/src/Serializer/ApiItemNormalizer.php new file mode 100644 index 00000000000..834cc9bf047 --- /dev/null +++ b/src/Serializer/ApiItemNormalizer.php @@ -0,0 +1,7 @@ +normalizer = $normalizer; + $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->dataTransformers = $dataTransformers; + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + $inputClass = $this->getInputClass($class, $context); + + if (null !== $inputClass && null !== $dataTransformer = $this->getDataTransformer($data, $class, $context)) { + $data = $dataTransformer->transform( + $this->normalizer->denormalize($data, $inputClass, $format, ['resource_class' => $inputClass] + $context), + $class, + $context + ); + } + + return $this->normalizer->denormalize($data, $class, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return $this->normalizer->supportsDenormalization($data, $type, $format); + } + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = []) + { + return $this->normalizer->normalize($object, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return $this->normalizer->supportsNormalization($data, $format); + } + + /** + * {@inheritdoc} + */ + public function hasCacheableSupportsMethod(): bool + { + if ($this->normalizer instanceof CacheableSupportsMethodInterface) { + return $this->normalizer->hasCacheableSupportsMethod(); + } + + return false; + } + + /** + * Finds the first supported data transformer if any. + */ + private function getDataTransformer($object, string $to, array $context = []): ?DataTransformerInterface + { + foreach ($this->dataTransformers as $dataTransformer) { + if ($dataTransformer->supportsTransformation($object, $to, $context)) { + return $dataTransformer; + } + } + + return null; + } +} diff --git a/tests/Hydra/Serializer/ItemNormalizerTest.php b/tests/Hydra/Serializer/ItemNormalizerTest.php index e8953638811..423ffaa6082 100644 --- a/tests/Hydra/Serializer/ItemNormalizerTest.php +++ b/tests/Hydra/Serializer/ItemNormalizerTest.php @@ -23,6 +23,7 @@ use ApiPlatform\Core\Metadata\Property\PropertyNameCollection; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Resource\ResourceMetadata; +use ApiPlatform\Core\Serializer\ApiItemNormalizer; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; use PHPUnit\Framework\TestCase; use Prophecy\Argument; From e8328b692b2896c32ac456a0500a7d5609ec30d4 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Sun, 24 Mar 2019 11:56:17 +0100 Subject: [PATCH 2/4] Rewrite Hydra Normalizer --- src/Hal/Serializer/HalItemNormalizer.php | 72 +++++++++ .../Serializer/JsonApiItemNormalizer.php | 76 +++++++++ src/JsonLd/Serializer/ItemNormalizer.php | 153 ++++++++++++------ .../Serializer/JsonLdItemNormalizer.php | 106 ++++++++++++ src/Serializer/ObjectClassResolver.php | 15 ++ ...alizer.php => ResourceClassNormalizer.php} | 16 +- tests/Hydra/Serializer/ItemNormalizerTest.php | 3 +- 7 files changed, 380 insertions(+), 61 deletions(-) create mode 100644 src/Hal/Serializer/HalItemNormalizer.php create mode 100644 src/JsonApi/Serializer/JsonApiItemNormalizer.php create mode 100644 src/JsonLd/Serializer/JsonLdItemNormalizer.php create mode 100644 src/Serializer/ObjectClassResolver.php rename src/Serializer/{AddResourceClassNormalizer.php => ResourceClassNormalizer.php} (86%) diff --git a/src/Hal/Serializer/HalItemNormalizer.php b/src/Hal/Serializer/HalItemNormalizer.php new file mode 100644 index 00000000000..8100aed3551 --- /dev/null +++ b/src/Hal/Serializer/HalItemNormalizer.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Hal\Serializer; + +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +final class HalItemNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface +{ + private $normalizer; + + public function __construct(NormalizerInterface $normalizer) + { + if (!$normalizer instanceof DenormalizerInterface) { + throw new \TypeError(''); + } + + $this->normalizer = $normalizer; + } + + /** + * {@inheritdoc} + */ + public function hasCacheableSupportsMethod(): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + return $this->normalizer->denormalize($data, $class, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return $this->normalizer->supportsDenormalization($data, $type, $format); + } + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = []) + { + return $this->normalizer->normalize($object, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return $this->normalizer->supportsNormalization($data, $format); + } +} diff --git a/src/JsonApi/Serializer/JsonApiItemNormalizer.php b/src/JsonApi/Serializer/JsonApiItemNormalizer.php new file mode 100644 index 00000000000..c55e9f5c9db --- /dev/null +++ b/src/JsonApi/Serializer/JsonApiItemNormalizer.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\JsonApi\Serializer; + +use Symfony\Component\Serializer\Exception\BadMethodCallException; +use Symfony\Component\Serializer\Exception\CircularReferenceException; +use Symfony\Component\Serializer\Exception\ExceptionInterface; +use Symfony\Component\Serializer\Exception\ExtraAttributesException; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\LogicException; +use Symfony\Component\Serializer\Exception\RuntimeException; +use Symfony\Component\Serializer\Exception\UnexpectedValueException; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +class JsonApiItemNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface +{ + private $normalizer; + + public function __construct(NormalizerInterface $normalizer) + { + $this->normalizer = $normalizer; + } + + /** + * {@inheritdoc} + */ + public function hasCacheableSupportsMethod(): bool + { + // TODO: Implement hasCacheableSupportsMethod() method. + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + // TODO: Implement denormalize() method. + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + // TODO: Implement supportsDenormalization() method. + } + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = []) + { + // TODO: Implement normalize() method. + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + // TODO: Implement supportsNormalization() method. + } +} diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php index a2a80c6d984..22558ea432e 100644 --- a/src/JsonLd/Serializer/ItemNormalizer.php +++ b/src/JsonLd/Serializer/ItemNormalizer.php @@ -20,33 +20,77 @@ use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; -use ApiPlatform\Core\Serializer\AbstractItemNormalizer; -use ApiPlatform\Core\Serializer\ContextTrait; -use ApiPlatform\Core\Util\ClassInfoTrait; +use ApiPlatform\Core\Serializer\ObjectClassResolver; +use ApiPlatform\Core\Serializer\ResourceClassNormalizer; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\SerializerAwareInterface; +use Symfony\Component\Serializer\SerializerInterface; /** * Converts between objects and array including JSON-LD and Hydra metadata. * * @author Kévin Dunglas */ -final class ItemNormalizer extends AbstractItemNormalizer +final class ItemNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface, SerializerAwareInterface { - use ClassInfoTrait; - use ContextTrait; - use JsonLdContextTrait; +// use ClassInfoTrait; +// use ContextTrait; +// use JsonLdContextTrait; const FORMAT = 'jsonld'; - private $contextBuilder; +// private $contextBuilder; + + private $objectNormalizer; + + private $normalizer; public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, ContextBuilderInterface $contextBuilder, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ClassMetadataFactoryInterface $classMetadataFactory = null, array $defaultContext = [], iterable $dataTransformers = [], bool $handleNonResource = false) { - parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory, null, false, $defaultContext, $dataTransformers, $resourceMetadataFactory, $handleNonResource); +// parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory, null, false, $defaultContext, $dataTransformers, $resourceMetadataFactory, $handleNonResource); + +// $this->contextBuilder = $contextBuilder; + $this->objectNormalizer = new ObjectNormalizer( + $classMetadataFactory, + $nameConverter, + $propertyAccessor, + null, + null, + new ObjectClassResolver(), + $defaultContext + ); + + $jsonLdItemNormalizer = new JsonLdItemNormalizer( + $this->objectNormalizer, + $iriConverter, + $resourceMetadataFactory, + $contextBuilder + ); + + $resourceClassNormalizer = new ResourceClassNormalizer( + $jsonLdItemNormalizer, + $resourceClassResolver, + $iriConverter + ); + + $this->normalizer = $resourceClassNormalizer; + } - $this->contextBuilder = $contextBuilder; + public function setSerializer(SerializerInterface $serializer) + { + $this->objectNormalizer->setSerializer($serializer); + } + + + public function hasCacheableSupportsMethod(): bool + { + return $this->normalizer->hasCacheableSupportsMethod(); } /** @@ -54,7 +98,7 @@ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFa */ public function supportsNormalization($data, $format = null, array $context = []) { - return self::FORMAT === $format && parent::supportsNormalization($data, $format, $context); + return $this->normalizer->supportsNormalization($data, $format, $context); } /** @@ -62,37 +106,38 @@ public function supportsNormalization($data, $format = null, array $context = [] */ public function normalize($object, $format = null, array $context = []) { - if ($this->handleNonResource && ($context['api_normalize'] ?? false) || null !== $outputClass = $this->getOutputClass($this->getObjectClass($object), $context)) { - if (isset($outputClass)) { - $object = $this->transformOutput($object, $context); - } - - $data = $this->createJsonLdContext($this->contextBuilder, $object, $context); - $rawData = parent::normalize($object, $format, $context); - if (!\is_array($rawData)) { - return $rawData; - } - - return $data + $rawData; - } - - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); - $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); - $data = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context); - - // Use resolved resource class instead of given resource class to support multiple inheritance child types - $context['resource_class'] = $resourceClass; - $context['iri'] = $this->iriConverter->getIriFromItem($object); - - $rawData = parent::normalize($object, $format, $context); - if (!\is_array($rawData)) { - return $rawData; - } - - $data['@id'] = $context['iri']; - $data['@type'] = $resourceMetadata->getIri() ?: $resourceMetadata->getShortName(); - - return $data + $rawData; + return $this->normalizer->normalize($object, $format, $context); +// if ($this->handleNonResource && ($context['api_normalize'] ?? false) || null !== $outputClass = $this->getOutputClass($this->getObjectClass($object), $context)) { +// if (isset($outputClass)) { +// $object = $this->transformOutput($object, $context); +// } +// +// $data = $this->createJsonLdContext($this->contextBuilder, $object, $context); +// $rawData = parent::normalize($object, $format, $context); +// if (!\is_array($rawData)) { +// return $rawData; +// } +// +// return $data + $rawData; +// } +// +// $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); +// $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); +// $data = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context); +// +// // Use resolved resource class instead of given resource class to support multiple inheritance child types +// $context['resource_class'] = $resourceClass; +// $context['iri'] = $this->iriConverter->getIriFromItem($object); +// +// $rawData = parent::normalize($object, $format, $context); +// if (!\is_array($rawData)) { +// return $rawData; +// } +// +// $data['@id'] = $context['iri']; +// $data['@type'] = $resourceMetadata->getIri() ?: $resourceMetadata->getShortName(); +// +// return $data + $rawData; } /** @@ -100,7 +145,8 @@ public function normalize($object, $format = null, array $context = []) */ public function supportsDenormalization($data, $type, $format = null, array $context = []) { - return self::FORMAT === $format && parent::supportsDenormalization($data, $type, $format, $context); + return $this->normalizer->supportsDenormalization($data, $type, $format, $context); +// return self::FORMAT === $format && parent::supportsDenormalization($data, $type, $format, $context); } /** @@ -110,15 +156,16 @@ public function supportsDenormalization($data, $type, $format = null, array $con */ public function denormalize($data, $class, $format = null, array $context = []) { - // Avoid issues with proxies if we populated the object - if (isset($data['@id']) && !isset($context[self::OBJECT_TO_POPULATE])) { - if (isset($context['api_allow_update']) && true !== $context['api_allow_update']) { - throw new InvalidArgumentException('Update is not allowed for this operation.'); - } - - $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri($data['@id'], $context + ['fetch_data' => true]); - } - - return parent::denormalize($data, $class, $format, $context); + return $this->normalizer->denormalize($data, $class, $format, $context); +// // Avoid issues with proxies if we populated the object +// if (isset($data['@id']) && !isset($context[self::OBJECT_TO_POPULATE])) { +// if (isset($context['api_allow_update']) && true !== $context['api_allow_update']) { +// throw new InvalidArgumentException('Update is not allowed for this operation.'); +// } +// +// $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri($data['@id'], $context + ['fetch_data' => true]); +// } +// +// return parent::denormalize($data, $class, $format, $context); } } diff --git a/src/JsonLd/Serializer/JsonLdItemNormalizer.php b/src/JsonLd/Serializer/JsonLdItemNormalizer.php new file mode 100644 index 00000000000..5cea5aa50fb --- /dev/null +++ b/src/JsonLd/Serializer/JsonLdItemNormalizer.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\JsonLd\Serializer; + +use ApiPlatform\Core\Api\IriConverterInterface; +use ApiPlatform\Core\JsonLd\ContextBuilderInterface; +use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +class JsonLdItemNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface +{ + use JsonLdContextTrait; + + const FORMAT = 'jsonld'; + + private $normalizer; + + private $iriConverter; + + private $resourceMetadataFactory; + + private $contextBuilder; + + public function __construct(NormalizerInterface $normalizer, IriConverterInterface $iriConverter, ResourceMetadataFactoryInterface $resourceMetadataFactory, ContextBuilderInterface $contextBuilder) + { + $this->normalizer = $normalizer; + $this->iriConverter = $iriConverter; + $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->contextBuilder = $contextBuilder; + } + + /** + * {@inheritdoc} + */ + public function hasCacheableSupportsMethod(): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + return $this->normalizer->denormalize($data, $class, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null, array $context = []) + { + return self::FORMAT === $format && $this->normalizer->supportsDenormalization($data, $type, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = []) + { + $rawData = $this->normalizer->normalize($object, $format, $context); + + if (!\is_array($rawData)) { + return $rawData; + } + + $resourceClass = $context['resource_class'] ?? null; + + if (!\is_string($resourceClass)) { + return $this->normalizer->normalize($object, $format, $context); + } + + $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); + $data = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context); + + if (!isset($context['iri'])) { + $context['iri'] = $this->iriConverter->getIriFromItem($object); + } + + $data['@id'] = $context['iri']; + $data['@type'] = $resourceMetadata->getIri() ?: $resourceMetadata->getShortName(); + + return array_merge($data, $rawData); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null, array $context = []) + { + return self::FORMAT === $format && $this->normalizer->supportsNormalization($data, $format, $context); + } +} diff --git a/src/Serializer/ObjectClassResolver.php b/src/Serializer/ObjectClassResolver.php new file mode 100644 index 00000000000..62e9b7a4724 --- /dev/null +++ b/src/Serializer/ObjectClassResolver.php @@ -0,0 +1,15 @@ +getObjectClass($object); + } +} diff --git a/src/Serializer/AddResourceClassNormalizer.php b/src/Serializer/ResourceClassNormalizer.php similarity index 86% rename from src/Serializer/AddResourceClassNormalizer.php rename to src/Serializer/ResourceClassNormalizer.php index a34cd1e92f1..8ef7bb6e893 100644 --- a/src/Serializer/AddResourceClassNormalizer.php +++ b/src/Serializer/ResourceClassNormalizer.php @@ -14,7 +14,7 @@ /** * Add resource class to the context */ -final class AddResourceClassNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface +final class ResourceClassNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface { use ContextTrait; use ClassInfoTrait; @@ -26,6 +26,8 @@ final class AddResourceClassNormalizer implements NormalizerInterface, Denormali private $iriConverter; + private $localCache = []; + public function __construct(NormalizerInterface $normalizer, ResourceClassResolverInterface $resourceClassResolver, IriConverterInterface $iriConverter) { if (!$normalizer instanceof DenormalizerInterface) { @@ -53,11 +55,7 @@ public function denormalize($data, $class, $format = null, array $context = []) */ public function supportsDenormalization($data, $type, $format = null) { - if (ElasticsearchItemNormalizer::FORMAT === $format) { - return false; - } - - return $this->normalizer->supportsDenormalization($data, $type, $format); + return $this->localCache[$type] ?? $this->localCache[$type] = $this->resourceClassResolver->isResourceClass($type); } /** @@ -94,7 +92,11 @@ public function supportsNormalization($data, $format = null) return false; } - return $this->normalizer->supportsNormalization($data, $format); + return + $this->resourceClassResolver->isResourceClass($this->getObjectClass($data)) + && + $this->normalizer->supportsNormalization($data, $format) + ; } /** diff --git a/tests/Hydra/Serializer/ItemNormalizerTest.php b/tests/Hydra/Serializer/ItemNormalizerTest.php index 423ffaa6082..a87f87e5999 100644 --- a/tests/Hydra/Serializer/ItemNormalizerTest.php +++ b/tests/Hydra/Serializer/ItemNormalizerTest.php @@ -46,12 +46,13 @@ public function testDontSupportDenormalization() $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); $contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class); + $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(false); $resourceClassResolverProphecy->getResourceClass(['dummy'], 'Dummy')->willReturn(Dummy::class); $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn(new PropertyNameCollection(['name' => 'name'])); $normalizer = new ItemNormalizer($resourceMetadataFactoryProphecy->reveal(), $propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $contextBuilderProphecy->reveal()); - $this->assertFalse($normalizer->supportsDenormalization('foo', ItemNormalizer::FORMAT)); + $this->assertFalse($normalizer->supportsDenormalization('foo', Dummy::class, ItemNormalizer::FORMAT)); $this->assertTrue($normalizer->hasCacheableSupportsMethod()); } From 4698b00c8653af16dd84f8a4a82bc3adf7bc2b4a Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Sun, 24 Mar 2019 12:09:09 +0100 Subject: [PATCH 3/4] Add data transformer normalizer to the chain --- src/JsonLd/Serializer/ItemNormalizer.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php index 22558ea432e..f6b0691615e 100644 --- a/src/JsonLd/Serializer/ItemNormalizer.php +++ b/src/JsonLd/Serializer/ItemNormalizer.php @@ -20,6 +20,7 @@ use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; +use ApiPlatform\Core\Serializer\DataTransformerNormalizer; use ApiPlatform\Core\Serializer\ObjectClassResolver; use ApiPlatform\Core\Serializer\ResourceClassNormalizer; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -66,8 +67,14 @@ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFa $defaultContext ); - $jsonLdItemNormalizer = new JsonLdItemNormalizer( + $dataTransformerNormalizer = new DataTransformerNormalizer( $this->objectNormalizer, + $resourceMetadataFactory, + $dataTransformers + ); + + $jsonLdItemNormalizer = new JsonLdItemNormalizer( + $dataTransformerNormalizer, $iriConverter, $resourceMetadataFactory, $contextBuilder From 3e7ad05d8d2060110da70a294fb575b1cd85f37f Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Wed, 27 Mar 2019 21:32:16 +0100 Subject: [PATCH 4/4] Update symfony version to fix bug about class resolver --- composer.json | 2 +- src/JsonLd/Serializer/ItemNormalizer.php | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index bb606055d4b..b85e4d673e1 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "symfony/http-kernel": "^3.4 || ^4.0", "symfony/property-access": "^3.4 || ^4.0", "symfony/property-info": "^3.4 || ^4.0", - "symfony/serializer": "^4.1", + "symfony/serializer": "4.2.x-dev", "symfony/web-link": "^4.1", "willdurand/negotiation": "^2.0.3" }, diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php index f6b0691615e..591a0f608f9 100644 --- a/src/JsonLd/Serializer/ItemNormalizer.php +++ b/src/JsonLd/Serializer/ItemNormalizer.php @@ -89,12 +89,17 @@ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFa $this->normalizer = $resourceClassNormalizer; } + /** + * {@inheritdoc} + */ public function setSerializer(SerializerInterface $serializer) { $this->objectNormalizer->setSerializer($serializer); } - + /** + * {@inheritdoc} + */ public function hasCacheableSupportsMethod(): bool { return $this->normalizer->hasCacheableSupportsMethod();