diff --git a/src/JsonApi/Serializer/ItemNormalizer.php b/src/JsonApi/Serializer/ItemNormalizer.php index 4d9d6e225c..b97c1411dc 100644 --- a/src/JsonApi/Serializer/ItemNormalizer.php +++ b/src/JsonApi/Serializer/ItemNormalizer.php @@ -278,22 +278,9 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope return $this->iriConverter->getResourceFromIri($value['id'], $context); } - $targetClass = null; - $nativeType = $propertyMetadata->getNativeType(); - - if ($nativeType) { - $nativeType->isSatisfiedBy(function (Type $type) use (&$targetClass): bool { - return $type instanceof ObjectType && $this->resourceClassResolver->isResourceClass($targetClass = $type->getClassName()); - }); - } - - if (null === $targetClass) { - throw new ItemNotFoundException(\sprintf('Cannot determine target class for property "%s".', $attributeName)); - } - /** @var HttpOperation $getOperation */ - $getOperation = $this->resourceMetadataCollectionFactory->create($targetClass)->getOperation(httpOperation: true); - $iri = $this->reconstructIri($targetClass, (string) $value['id'], $getOperation); + $getOperation = $this->resourceMetadataCollectionFactory->create($className)->getOperation(httpOperation: true); + $iri = $this->reconstructIri($className, (string) $value['id'], $getOperation); return $this->iriConverter->getResourceFromIri($iri, $context); } catch (ItemNotFoundException $e) { diff --git a/src/JsonApi/Tests/Serializer/ItemNormalizerTest.php b/src/JsonApi/Tests/Serializer/ItemNormalizerTest.php index 683ed89cd3..fd4b2ea12e 100644 --- a/src/JsonApi/Tests/Serializer/ItemNormalizerTest.php +++ b/src/JsonApi/Tests/Serializer/ItemNormalizerTest.php @@ -314,6 +314,67 @@ public function testDenormalize(): void $this->assertInstanceOf(Dummy::class, $normalizer->denormalize($data, Dummy::class, ItemNormalizer::FORMAT)); } + // https://github.com/api-platform/core/pull/7938 + public function testDenormalizeRelationUsesClassNameArgument(): void + { + $relatedDummy = new RelatedDummy(); + $relatedDummy->setId(1); + + $propertyMetadata = (new ApiProperty()) + ->withNativeType(Type::collection(Type::object(ArrayCollection::class), Type::object(RelatedDummy::class), Type::int())) + ->withReadable(false)->withWritable(true) + ->withReadableLink(false)->withWritableLink(false); + + $iriConverter = $this->createStub(IriConverterInterface::class); + $iriConverter->method('getIriFromResource')->willReturn('/related_dummies/1'); + $iriConverter->method('getResourceFromIri')->willReturn($relatedDummy); + + $resourceClassResolver = $this->createStub(ResourceClassResolverInterface::class); + $resourceClassResolver->method('isResourceClass')->willReturnMap([ + [RelatedDummy::class, true], + [ArrayCollection::class, false], + ]); + + $resourceMetadataCollectionFactory = $this->createMock(ResourceMetadataCollectionFactoryInterface::class); + $resourceMetadataCollectionFactory->expects($this->once()) + ->method('create') + ->with(RelatedDummy::class) + ->willReturn(new ResourceMetadataCollection(RelatedDummy::class, [ + (new ApiResource())->withOperations(new Operations([ + new Get(name: 'get', uriTemplate: '/related_dummies/{id}', uriVariables: ['id' => new Link(fromClass: RelatedDummy::class, identifiers: ['id'])]), + ])), + ])); + + $normalizer = new ItemNormalizer( + $this->createStub(PropertyNameCollectionFactoryInterface::class), + $this->createStub(PropertyMetadataFactoryInterface::class), + $iriConverter, + $resourceClassResolver, + null, + new ReservedAttributeNameConverter(), + null, + [], + $resourceMetadataCollectionFactory, + null, + null, + null, + null, + false, + ); + + $result = (new \ReflectionMethod(ItemNormalizer::class, 'denormalizeRelation'))->invoke( + $normalizer, + 'relatedDummies', + $propertyMetadata, + RelatedDummy::class, + ['type' => 'related-dummy', 'id' => '1'], + null, + [] + ); + + $this->assertSame($relatedDummy, $result); + } + public function testDenormalizeUpdateOperationNotAllowed(): void { $this->expectException(NotNormalizableValueException::class);