Skip to content

Commit 04414e4

Browse files
authored
fix(serializer): improve #7270 by reducing inconsistencies (#7346)
1 parent 2d501b3 commit 04414e4

File tree

2 files changed

+15
-16
lines changed

2 files changed

+15
-16
lines changed

src/Serializer/ItemNormalizer.php

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
/**
3333
* Generic item normalizer.
3434
*
35+
* TODO: do not hardcode "id"
36+
*
3537
* @author Kévin Dunglas <dunglas@gmail.com>
3638
*/
3739
class ItemNormalizer extends AbstractItemNormalizer
@@ -59,7 +61,9 @@ public function denormalize(mixed $data, string $class, ?string $format = null,
5961
}
6062

6163
if (isset($context['resource_class'])) {
62-
$this->updateObjectToPopulate($data, $context);
64+
if ($this->updateObjectToPopulate($data, $context)) {
65+
unset($data['id']);
66+
}
6367
} else {
6468
// See https://github.com/api-platform/core/pull/2326 to understand this message.
6569
$this->logger->warning('The "resource_class" key is missing from the context.', [
@@ -68,24 +72,15 @@ public function denormalize(mixed $data, string $class, ?string $format = null,
6872
}
6973
}
7074

71-
// See https://github.com/api-platform/core/pull/7270 - id may be an allowed attribute due to being added in the
72-
// overridden getAllowedAttributes below, in order to allow updating a nested item via ID. But in this case it
73-
// may not "really" be an allowed attribute, ie we don't want to actually use it in denormalization. In this
74-
// scenario it will not be present in parent::getAllowedAttributes
75-
if (isset($data['id'], $context['resource_class'])) {
76-
$parentAllowedAttributes = parent::getAllowedAttributes($class, $context, true);
77-
if (\is_array($parentAllowedAttributes) && !\in_array('id', $parentAllowedAttributes, true)) {
78-
unset($data['id']);
79-
}
80-
}
81-
8275
return parent::denormalize($data, $class, $format, $context);
8376
}
8477

85-
private function updateObjectToPopulate(array $data, array &$context): void
78+
private function updateObjectToPopulate(array $data, array &$context): bool
8679
{
8780
try {
8881
$context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getResourceFromIri((string) $data['id'], $context + ['fetch_data' => true]);
82+
83+
return true;
8984
} catch (InvalidArgumentException) {
9085
$operation = $this->resourceMetadataCollectionFactory?->create($context['resource_class'])->getOperation();
9186
if (
@@ -102,6 +97,8 @@ private function updateObjectToPopulate(array $data, array &$context): void
10297

10398
$context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getResourceFromIri($iri, $context + ['fetch_data' => true]);
10499
}
100+
101+
return false;
105102
}
106103

107104
private function getContextUriVariables(array $data, $operation, array $context): array
@@ -122,8 +119,9 @@ private function getContextUriVariables(array $data, $operation, array $context)
122119
protected function getAllowedAttributes(string|object $classOrObject, array $context, bool $attributesAsString = false): array|bool
123120
{
124121
$allowedAttributes = parent::getAllowedAttributes($classOrObject, $context, $attributesAsString);
125-
if (\is_array($allowedAttributes) && ($context['api_denormalize'] ?? false)) {
126-
$allowedAttributes = array_merge($allowedAttributes, ['id']);
122+
// id is a special case handled above it causes issues not allowing it
123+
if (\is_array($allowedAttributes) && ($context['api_denormalize'] ?? false) && !\in_array('id', $allowedAttributes, true)) {
124+
$allowedAttributes[] = 'id';
127125
}
128126

129127
return $allowedAttributes;

src/Serializer/Tests/ItemNormalizerTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,14 @@ public function testDenormalizeWithWrongId(): void
316316
$operation = new Get(uriVariables: ['id' => new Link(identifiers: ['id'], parameterName: 'id')]);
317317
$obj = new Dummy();
318318

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

323323
$propertyMetadata = (new ApiProperty())->withReadable(true)->withWritable(true);
324324
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
325325
$propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata)->shouldBeCalled();
326+
$propertyMetadataFactoryProphecy->create(Dummy::class, 'id', [])->willReturn((new ApiProperty())->withIdentifier(true))->shouldBeCalled();
326327

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

0 commit comments

Comments
 (0)