Skip to content

Commit 5fa58e9

Browse files
authored
Merge pull request #2627 from teohhanhui/fix/jsonapi-normalize
[jsonapi][jsonhal] Correct normalization of output class and non-resource
2 parents 5b7738e + 05afcae commit 5fa58e9

File tree

8 files changed

+248
-56
lines changed

8 files changed

+248
-56
lines changed

features/bootstrap/DoctrineContext.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,17 +1185,17 @@ public function thereIsAMaxDepthDummyWithLevelOfDescendants(int $level)
11851185
}
11861186

11871187
/**
1188-
* @Given there is a DummyCustomDto
1188+
* @Given there is a DummyDtoCustom
11891189
*/
1190-
public function thereIsADummyCustomDto()
1190+
public function thereIsADummyDtoCustom()
11911191
{
1192-
$this->thereAreNbDummyCustomDto(1);
1192+
$this->thereAreNbDummyDtoCustom(1);
11931193
}
11941194

11951195
/**
1196-
* @Given there are :nb DummyCustomDto
1196+
* @Given there are :nb DummyDtoCustom
11971197
*/
1198-
public function thereAreNbDummyCustomDto($nb)
1198+
public function thereAreNbDummyDtoCustom($nb)
11991199
{
12001200
for ($i = 0; $i < $nb; ++$i) {
12011201
$dto = $this->isOrm() ? new DummyDtoCustom() : new DummyDtoCustomDocument();

features/hal/input_output.feature

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
Feature: HAL DTO input and output
2+
In order to use a hypermedia API
3+
As a client software developer
4+
I need to be able to use DTOs on my resources as Input or Output objects.
5+
6+
Background:
7+
Given I add "Accept" header equal to "application/hal+json"
8+
9+
@createSchema
10+
Scenario: Get an item with a custom output
11+
Given there is a DummyDtoCustom
12+
When I send a "GET" request to "/dummy_dto_custom_output/1"
13+
Then the response status code should be 200
14+
And the response should be in JSON
15+
And the header "Content-Type" should be equal to "application/hal+json; charset=utf-8"
16+
And the JSON should be a superset of:
17+
"""
18+
{
19+
"_links": {
20+
"self": {
21+
"href": "/dummy_dto_customs/1"
22+
}
23+
},
24+
"foo": "test",
25+
"bar": 1
26+
}
27+
"""
28+
29+
@createSchema
30+
Scenario: Get a collection with a custom output
31+
Given there are 2 DummyDtoCustom
32+
When I send a "GET" request to "/dummy_dto_custom_output"
33+
Then the response status code should be 200
34+
And the response should be in JSON
35+
And the header "Content-Type" should be equal to "application/hal+json; charset=utf-8"
36+
And the JSON should be a superset of:
37+
"""
38+
{
39+
"_embedded": {
40+
"item": [
41+
{
42+
"_links": {
43+
"self": {
44+
"href": "/dummy_dto_customs/1"
45+
}
46+
},
47+
"foo": "test",
48+
"bar": 1
49+
},
50+
{
51+
"_links": {
52+
"self": {
53+
"href": "/dummy_dto_customs/2"
54+
}
55+
},
56+
"foo": "test",
57+
"bar": 2
58+
}
59+
]
60+
}
61+
}
62+
"""

features/jsonapi/input_output.feature

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
Feature: JSON API DTO input and output
2+
In order to use a hypermedia API
3+
As a client software developer
4+
I need to be able to use DTOs on my resources as Input or Output objects.
5+
6+
Background:
7+
Given I add "Accept" header equal to "application/vnd.api+json"
8+
And I add "Content-Type" header equal to "application/vnd.api+json"
9+
10+
@createSchema
11+
Scenario: Get an item with a custom output
12+
Given there is a DummyDtoCustom
13+
When I send a "GET" request to "/dummy_dto_custom_output/1"
14+
Then the response status code should be 200
15+
And the response should be in JSON
16+
And the header "Content-Type" should be equal to "application/vnd.api+json; charset=utf-8"
17+
And the JSON should be valid according to the JSON API schema
18+
And the JSON should be a superset of:
19+
"""
20+
{
21+
"data": {
22+
"id": "/dummy_dto_customs/1",
23+
"type": "DummyDtoCustom",
24+
"attributes": {
25+
"foo": "test",
26+
"bar": 1
27+
}
28+
}
29+
}
30+
"""
31+
32+
@createSchema
33+
Scenario: Get a collection with a custom output
34+
Given there are 2 DummyDtoCustom
35+
When I send a "GET" request to "/dummy_dto_custom_output"
36+
Then the response status code should be 200
37+
And the response should be in JSON
38+
And the header "Content-Type" should be equal to "application/vnd.api+json; charset=utf-8"
39+
And the JSON should be valid according to the JSON API schema
40+
And the JSON should be a superset of:
41+
"""
42+
{
43+
"data": [
44+
{
45+
"id": "/dummy_dto_customs/1",
46+
"type": "DummyDtoCustom",
47+
"attributes": {
48+
"foo": "test",
49+
"bar": 1
50+
}
51+
},
52+
{
53+
"id": "/dummy_dto_customs/2",
54+
"type": "DummyDtoCustom",
55+
"attributes": {
56+
"foo": "test",
57+
"bar": 2
58+
}
59+
}
60+
]
61+
}
62+
"""

features/main/input_output.feature

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Feature: DTO input and output
3030

3131
@createSchema
3232
Scenario: Get an item with a custom output
33-
Given there is a DummyCustomDto
33+
Given there is a DummyDtoCustom
3434
When I send a "GET" request to "/dummy_dto_custom_output/1"
3535
Then the response status code should be 200
3636
And the response should be in JSON
@@ -59,7 +59,7 @@ Feature: DTO input and output
5959

6060
@createSchema
6161
Scenario: Get a collection with a custom output
62-
Given there are 2 DummyCustomDto
62+
Given there are 2 DummyDtoCustom
6363
When I send a "GET" request to "/dummy_dto_custom_output"
6464
Then the response status code should be 200
6565
And the response should be in JSON
@@ -87,7 +87,7 @@ Feature: DTO input and output
8787
"""
8888

8989
@createSchema
90-
Scenario: Create a DummyCustomDto object without output
90+
Scenario: Create a DummyDtoCustom object without output
9191
When I add "Content-Type" header equal to "application/ld+json"
9292
And I send a "POST" request to "/dummy_dto_custom_post_without_output" with body:
9393
"""
@@ -192,30 +192,6 @@ Feature: DTO input and output
192192
}
193193
"""
194194

195-
@!mongodb
196-
@createSchema
197-
Scenario: Create a resource that has a non-resource DTO relation.
198-
When I add "Content-Type" header equal to "application/ld+json"
199-
And I send a "POST" request to "/non_relation_resources" with body:
200-
"""
201-
{"relation": {"foo": "test"}}
202-
"""
203-
Then the response status code should be 201
204-
And the response should be in JSON
205-
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
206-
And the JSON should be equal to:
207-
"""
208-
{
209-
"@context": "/contexts/NonRelationResource",
210-
"@id": "/non_relation_resources/1",
211-
"@type": "NonRelationResource",
212-
"relation": {
213-
"foo": "test"
214-
},
215-
"id": 1
216-
}
217-
"""
218-
219195
@createSchema
220196
Scenario: Retrieve an Output with GraphQl
221197
When I add "Content-Type" header equal to "application/ld+json"

features/main/non_resource.feature

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,27 @@ Feature: Non-resources handling
2828
}
2929
}
3030
"""
31+
32+
@!mongodb
33+
@createSchema
34+
Scenario: Create a resource that has a non-resource relation.
35+
When I add "Content-Type" header equal to "application/ld+json"
36+
And I send a "POST" request to "/non_relation_resources" with body:
37+
"""
38+
{"relation": {"foo": "test"}}
39+
"""
40+
Then the response status code should be 201
41+
And the response should be in JSON
42+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
43+
And the JSON should be equal to:
44+
"""
45+
{
46+
"@context": "/contexts/NonRelationResource",
47+
"@id": "/non_relation_resources/1",
48+
"@type": "NonRelationResource",
49+
"relation": {
50+
"foo": "test"
51+
},
52+
"id": 1
53+
}
54+
"""

src/Hal/Serializer/ItemNormalizer.php

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,40 @@ public function supportsNormalization($data, $format = null, array $context = []
4848
*/
4949
public function normalize($object, $format = null, array $context = [])
5050
{
51-
if ($this->handleNonResource || null !== $outputClass = $this->getOutputClass($this->getObjectClass($object), $context)) {
51+
if (!$this->handleNonResource && null !== $outputClass = $this->getOutputClass($this->getObjectClass($object), $context)) {
5252
return parent::normalize($object, $format, $context);
5353
}
5454

5555
if (!isset($context['cache_key'])) {
5656
$context['cache_key'] = $this->getHalCacheKey($format, $context);
5757
}
5858

59+
if ($this->handleNonResource) {
60+
if (isset($context['api_resource'])) {
61+
$originalResource = $context['api_resource'];
62+
unset($context['api_resource']);
63+
}
64+
65+
$rawData = parent::normalize($object, $format, $context);
66+
if (!\is_array($rawData)) {
67+
return $rawData;
68+
}
69+
70+
if (!isset($originalResource)) {
71+
return $rawData;
72+
}
73+
74+
$metadataData = [
75+
'_links' => [
76+
'self' => [
77+
'href' => $this->iriConverter->getIriFromItem($originalResource),
78+
],
79+
],
80+
];
81+
82+
return $metadataData + $rawData;
83+
}
84+
5985
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true);
6086
$context = $this->initContext($resourceClass, $context);
6187
$context['iri'] = $this->iriConverter->getIriFromItem($object);
@@ -66,12 +92,18 @@ public function normalize($object, $format = null, array $context = [])
6692
return $rawData;
6793
}
6894

69-
$data = ['_links' => ['self' => ['href' => $context['iri']]]];
95+
$metadataData = [
96+
'_links' => [
97+
'self' => [
98+
'href' => $context['iri'],
99+
],
100+
],
101+
];
70102
$components = $this->getComponents($object, $format, $context);
71-
$data = $this->populateRelation($data, $object, $format, $context, $components, 'links');
72-
$data = $this->populateRelation($data, $object, $format, $context, $components, 'embedded');
103+
$metadataData = $this->populateRelation($metadataData, $object, $format, $context, $components, 'links');
104+
$metadataData = $this->populateRelation($metadataData, $object, $format, $context, $components, 'embedded');
73105

74-
return $data + $rawData;
106+
return $metadataData + $rawData;
75107
}
76108

77109
/**

0 commit comments

Comments
 (0)