Skip to content

Commit 2e223f4

Browse files
committed
Correctly parse @id referenced entities in API
Fixes issue #1370
1 parent 0da5bef commit 2e223f4

2 files changed

Lines changed: 34 additions & 4 deletions

File tree

src/Serializer/APIPlatform/SkippableItemNormalizer.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,15 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
6363
// check (line 271). For abstract resource classes with a discriminator map (e.g. Attachment), this
6464
// fails because the array has no _type key. Fix by resolving IRI strings directly.
6565
// See: https://github.com/Part-DB/Part-DB-server/issues/1370
66-
if (is_string($data)) {
66+
if (is_string($data) || (is_array($data) && isset($data['@id']) && is_string($data['@id']))) {
67+
if (is_array($data)) {
68+
$iri = $data['@id'];
69+
} else {
70+
$iri = $data;
71+
}
72+
6773
try {
68-
return $this->iriConverter->getResourceFromIri($data, $context + ['fetch_data' => true]);
74+
return $this->iriConverter->getResourceFromIri($iri, $context + ['fetch_data' => true]);
6975
} catch (ItemNotFoundException $e) {
7076
if (false === ($context['denormalize_throw_on_relation_not_found'] ?? true)) {
7177
return null;
@@ -76,7 +82,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
7682
throw NotNormalizableValueException::createForUnexpectedDataType($e->getMessage(), $data, [$type], $context['deserialization_path'] ?? null, true, $e->getCode(), $e);
7783
} catch (InvalidArgumentException $e) {
7884
if (!isset($context['not_normalizable_value_exceptions'])) {
79-
throw new UnexpectedValueException(sprintf('Invalid IRI "%s".', $data), $e->getCode(), $e);
85+
throw new UnexpectedValueException(sprintf('Invalid IRI "%s".', $iri), $e->getCode(), $e);
8086
}
8187
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Invalid IRI "%s".', $data), $data, [$type], $context['deserialization_path'] ?? null, true, $e->getCode(), $e);
8288
}

tests/API/Endpoints/PartEndpointTest.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function testDeleteItem(): void
7070
$this->_testDeleteItem(1);
7171
}
7272

73-
public function testAttachmentPatchWithIRI(): void
73+
public function testMasterPictureAttachmentPatchWithIRI(): void
7474
{
7575
$client = static::createAuthenticatedClient();
7676

@@ -93,4 +93,28 @@ public function testAttachmentPatchWithIRI(): void
9393
self::assertResponseIsSuccessful();
9494
self::assertJsonContains(['master_picture_attachment' => ['@id' => $attachmentIri]]);
9595
}
96+
97+
public function testMasterPictureAttachmentPatchWithArray(): void
98+
{
99+
$client = static::createAuthenticatedClient();
100+
101+
// Create a new attachment with a picture URL for Part 1
102+
$response = $client->request('POST', '/api/attachments', ['json' => [
103+
'name' => 'Test Picture',
104+
'url' => 'http://example.com/test.jpg',
105+
'_type' => 'Part',
106+
'element' => '/api/parts/1',
107+
'attachment_type' => '/api/attachment_types/1',
108+
]]);
109+
self::assertResponseIsSuccessful();
110+
$attachmentIri = $response->toArray()['@id'];
111+
112+
// Now PATCH Part 1 to set master_picture_attachment
113+
$client->request('PATCH', '/api/parts/1', [
114+
'json' => ['master_picture_attachment' => ['@id' => $attachmentIri, '_type' => 'Part']],
115+
'headers' => ['Content-Type' => 'application/merge-patch+json'],
116+
]);
117+
self::assertResponseIsSuccessful();
118+
self::assertJsonContains(['master_picture_attachment' => ['@id' => $attachmentIri]]);
119+
}
96120
}

0 commit comments

Comments
 (0)