Skip to content

Commit fcef2c6

Browse files
committed
Fix form submit @id without breaking success handler entity results
item_uri_template on the submit operations polluted the normalization context when a success handler replaced the Form result with a different entity (e.g. User on registration), producing wrong @type/@id for that entity. Instead: remove item_uri_template and strip the /submit suffix from @id in onPostRespond, which only affects the @id field and leaves the result entity unchanged. Registration test restored to expect the User entity.
1 parent fddfe5b commit fcef2c6

3 files changed

Lines changed: 27 additions & 9 deletions

File tree

features/user/register_form.feature

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,19 @@ Feature: Register process via a form
2727
And the response status code should be 201
2828
And the response should be in JSON
2929
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
30-
And the JSON should be valid according to the schema file "form.schema.json"
30+
And the JSON should be a superset of:
31+
"""
32+
{
33+
"@context": "/contexts/User",
34+
"@type": "User",
35+
"username": "new_user",
36+
"emailAddress": "user@example.com",
37+
"_metadata": {
38+
"persisted": true
39+
}
40+
}
41+
"""
42+
And the JSON should be valid according to the schema file "user.schema.json"
3143
And I should get a "user_welcome" email sent
3244

3345
Scenario Outline: Submit a duplicate user registration form

src/Entity/Component/Form.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
write: false,
5353
serialize: true,
5454
requirements: ['id' => '[^/]+'],
55-
normalizationContext: ['item_uri_template' => '/forms/{id}{._format}'],
5655
),
5756
new Post(
5857
name: '_api_/forms/{id}/submit{._format}_post',
@@ -63,7 +62,6 @@
6362
write: false,
6463
serialize: true,
6564
requirements: ['id' => '[^/]+'],
66-
normalizationContext: ['item_uri_template' => '/forms/{id}{._format}'],
6765
),
6866
]
6967
)]

src/EventListener/Api/FormApiEventListener.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,7 @@ private function handleFormData(ViewEvent $event): void
6868

6969
if ($data->formView->getForm()->isValid()) {
7070
$result = $this->formSubmitHelper->handleSuccess($data);
71-
// Only replace the Form with the result if it is an explicit Response object
72-
// (e.g. a 404 from PasswordUpdateListener). Entity results (e.g. the created User
73-
// from registration) are intentionally ignored — the submit endpoint always returns
74-
// the Form entity so @type and @id remain stable regardless of side-effects.
75-
if ($result instanceof Response) {
71+
if ($result) {
7672
$data = $result;
7773
}
7874
}
@@ -103,13 +99,25 @@ public function onPostRespond(ResponseEvent $event): void
10399
return;
104100
}
105101

102+
$response = $event->getResponse();
103+
106104
if ($formView = $data->formView) {
107105
$form = $formView->getForm();
108-
$response = $event->getResponse();
109106
if (!$form->isValid()) {
110107
$response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
111108
}
112109
}
110+
111+
// AP4 uses the submit operation's uriTemplate to generate @id, giving /{uuid}/submit.
112+
// Strip the suffix so @id always points to the canonical resource IRI.
113+
$content = $response->getContent();
114+
if ($content && str_contains($content, '\/submit"')) {
115+
$decoded = json_decode($content, true);
116+
if (isset($decoded['@id']) && str_ends_with($decoded['@id'], '/submit')) {
117+
$decoded['@id'] = substr($decoded['@id'], 0, -\strlen('/submit'));
118+
$response->setContent(json_encode($decoded));
119+
}
120+
}
113121
}
114122

115123
private function getData(Request $request): ?Form

0 commit comments

Comments
 (0)