Skip to content

Commit 66a49fd

Browse files
committed
fix: wrong resource iri
1 parent 42a866b commit 66a49fd

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

features/main/standard_put.feature

+14
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ Feature: Spec-compliant PUT support
5252
}
5353
"""
5454

55+
Scenario: Fails to create a new resource with the wrong JSON-LD @id
56+
When I add "Content-Type" header equal to "application/ld+json"
57+
And I send a "PUT" request to "/standard_puts/7" with body:
58+
"""
59+
{
60+
"@id": "/dummies/6",
61+
"@context": "/contexts/StandardPut",
62+
"@type": "StandardPut",
63+
"foo": "a",
64+
"bar": "b"
65+
}
66+
"""
67+
Then the response status code should be 400
68+
5569
Scenario: Replace an existing resource
5670
When I add "Content-Type" header equal to "application/ld+json"
5771
And I send a "PUT" request to "/standard_puts/5" with body:

src/JsonLd/Serializer/ItemNormalizer.php

+25-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,29 @@ final class ItemNormalizer extends AbstractItemNormalizer
4949
use JsonLdContextTrait;
5050

5151
public const FORMAT = 'jsonld';
52+
public const JSONLD_KEYWORDS = [
53+
'@context',
54+
'@direction',
55+
'@graph',
56+
'@id',
57+
'@import',
58+
'@included',
59+
'@index',
60+
'@json',
61+
'@language',
62+
'@list',
63+
'@nest',
64+
'@none',
65+
'@prefix',
66+
'@propagate',
67+
'@protected',
68+
'@reverse',
69+
'@set',
70+
'@type',
71+
'@value',
72+
'@version',
73+
'@vocab',
74+
];
5275

5376
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface|LegacyIriConverterInterface $iriConverter, ResourceClassResolverInterface|LegacyResourceClassResolverInterface $resourceClassResolver, private readonly ContextBuilderInterface $contextBuilder, ?PropertyAccessorInterface $propertyAccessor = null, ?NameConverterInterface $nameConverter = null, ?ClassMetadataFactoryInterface $classMetadataFactory = null, array $defaultContext = [], ?ResourceAccessCheckerInterface $resourceAccessChecker = null, protected ?TagCollectorInterface $tagCollector = null)
5477
{
@@ -151,7 +174,7 @@ public function denormalize(mixed $data, string $class, ?string $format = null,
151174
}
152175

153176
try {
154-
$context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getResourceFromIri($data['@id'], $context + ['fetch_data' => true]);
177+
$context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getResourceFromIri($data['@id'], $context + ['fetch_data' => true], $context['operation'] ?? null);
155178
} catch (ItemNotFoundException $e) {
156179
$operation = $context['operation'] ?? null;
157180
if (!($operation instanceof Put && ($operation->getExtraProperties()['standard_put'] ?? false))) {
@@ -167,7 +190,7 @@ protected function getAllowedAttributes(string|object $classOrObject, array $con
167190
{
168191
$allowedAttributes = parent::getAllowedAttributes($classOrObject, $context, $attributesAsString);
169192
if (\is_array($allowedAttributes) && ($context['api_denormalize'] ?? false)) {
170-
$allowedAttributes = array_merge($allowedAttributes, ['@id', '@type', '@context']);
193+
$allowedAttributes = array_merge($allowedAttributes, self::JSONLD_KEYWORDS);
171194
}
172195

173196
return $allowedAttributes;

src/Symfony/Routing/IriConverter.php

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ public function getResourceFromIri(string $iri, array $context = [], ?Operation
7878
throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
7979
}
8080

81+
if ($operation && $operation->getClass() !== $parameters['_api_resource_class']) {
82+
throw new InvalidArgumentException(sprintf('The iri "%s" does not reference the correct resource.', $iri));
83+
}
84+
8185
$operation = $parameters['_api_operation'] = $this->resourceMetadataCollectionFactory->create($parameters['_api_resource_class'])->getOperation($parameters['_api_operation_name']);
8286

8387
if ($operation instanceof CollectionOperationInterface) {

0 commit comments

Comments
 (0)