Skip to content

Commit

Permalink
fix(serializer): concat context on wrong id (#6050)
Browse files Browse the repository at this point in the history
  • Loading branch information
anoziere committed Dec 19, 2023
1 parent aae0dbf commit 9660a19
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 5 deletions.
12 changes: 7 additions & 5 deletions src/Serializer/ItemNormalizer.php
Expand Up @@ -76,18 +76,20 @@ private function updateObjectToPopulate(array $data, array &$context): void
try {
$context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getResourceFromIri((string) $data['id'], $context + ['fetch_data' => true]);
} catch (InvalidArgumentException) {
$operation = $this->resourceMetadataCollectionFactory->create($context['resource_class'])->getOperation();
$operation = $this->resourceMetadataCollectionFactory?->create($context['resource_class'])->getOperation();
if (
null !== ($context['uri_variables'] ?? null)
&& $operation instanceof HttpOperation
&& \count($operation->getUriVariables() ?? []) > 1
!$operation || (
null !== ($context['uri_variables'] ?? null)
&& $operation instanceof HttpOperation
&& \count($operation->getUriVariables() ?? []) > 1
)
) {
throw new InvalidArgumentException('Cannot find object to populate, use JSON-LD or specify an IRI at path "id".');
}
$uriVariables = $this->getContextUriVariables($data, $operation, $context);
$iri = $this->iriConverter->getIriFromResource($context['resource_class'], UrlGeneratorInterface::ABS_PATH, $operation, ['uri_variables' => $uriVariables]);

$context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getResourceFromIri($iri, ['fetch_data' => true]);
$context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getResourceFromIri($iri, $context + ['fetch_data' => true]);
}
}

Expand Down
83 changes: 83 additions & 0 deletions tests/Serializer/ItemNormalizerTest.php
Expand Up @@ -15,10 +15,17 @@

use ApiPlatform\Api\IriConverterInterface;
use ApiPlatform\Api\ResourceClassResolverInterface;
use ApiPlatform\Api\UrlGeneratorInterface;
use ApiPlatform\Exception\InvalidArgumentException;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Metadata\Property\PropertyNameCollection;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
use ApiPlatform\Serializer\ItemNormalizer;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -283,4 +290,80 @@ public function testDenormalizeWithIdAndNoResourceClass(): void
$this->assertSame('42', $object->getId());
$this->assertSame('hello', $object->getName());
}

public function testDenormalizeWithWrongIdAndNoResourceMetadataFactory(): void
{
$this->expectException(InvalidArgumentException::class);
$context = ['resource_class' => Dummy::class, 'api_allow_update' => true];

$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);

$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);

$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
$iriConverterProphecy->getResourceFromIri('fail', $context + ['fetch_data' => true])->willThrow(new InvalidArgumentException());

$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->getResourceClass(null, Dummy::class)->willReturn(Dummy::class);
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);

$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());

$this->assertInstanceOf(Dummy::class, $normalizer->denormalize(['name' => 'hello', 'id' => 'fail'], Dummy::class, null, $context));
}

public function testDenormalizeWithWrongId(): void
{
$context = ['resource_class' => Dummy::class, 'api_allow_update' => true];
$operation = new Get(uriVariables: ['id' => new Link(identifiers: ['id'], parameterName: 'id')]);
$obj = new Dummy();

$propertyNameCollection = new PropertyNameCollection(['name']);
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
$propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection)->shouldBeCalled();

$propertyMetadata = (new ApiProperty())->withReadable(true)->withWritable(true);
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
$propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata)->shouldBeCalled();

$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
$iriConverterProphecy->getResourceFromIri('fail', $context + ['fetch_data' => true])->willThrow(new InvalidArgumentException());
$iriConverterProphecy->getIriFromResource(Dummy::class, UrlGeneratorInterface::ABS_PATH, $operation, ['uri_variables' => ['id' => 'fail']])->willReturn('/dummies/fail');
$iriConverterProphecy->getResourceFromIri('/dummies/fail', $context + ['fetch_data' => true])->willReturn($obj);

$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->getResourceClass(null, Dummy::class)->willReturn(Dummy::class);
$resourceClassResolverProphecy->getResourceClass($obj, Dummy::class)->willReturn(Dummy::class);
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);

$resourceMetadataCollectionFactory = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class);
$resourceMetadataCollectionFactory->create(Dummy::class)->willReturn(new ResourceMetadataCollection(Dummy::class, [
new ApiResource(operations: [$operation]),
]));

$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
null,
null,
null,
null,
$resourceMetadataCollectionFactory->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());

$this->assertInstanceOf(Dummy::class, $normalizer->denormalize(['name' => 'hello', 'id' => 'fail'], Dummy::class, null, $context));
}
}

0 comments on commit 9660a19

Please sign in to comment.