Skip to content

Commit 0aef20a

Browse files
committed
Merge branch 'release/4.1.0'
2 parents 013380f + b2e1012 commit 0aef20a

File tree

7 files changed

+124
-36
lines changed

7 files changed

+124
-36
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. This projec
55

66
## Unreleased
77

8+
## [4.1.0] - 2024-06-26
9+
10+
### Fixed
11+
12+
- [core#17](https://github.com/laravel-json-api/core/pull/17) Fix incorrect `self` link in related resource responses,
13+
and remove `related` link that should not exist. This has been incorrect for some time, but is definitely what
14+
the [spec defines here.](https://jsonapi.org/format/1.0/#document-top-level)
15+
- [eloquent#36](https://github.com/laravel-json-api/eloquent/pull/36) Support Eloquent dynamic relationships.
16+
817
## [4.0.0] - 2024-03-14
918

1019
### Changed

composer.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"require": {
2626
"php": "^8.2",
2727
"ext-json": "*",
28-
"laravel-json-api/core": "^4.0",
29-
"laravel-json-api/eloquent": "^4.0",
28+
"laravel-json-api/core": "^4.1",
29+
"laravel-json-api/eloquent": "^4.1",
3030
"laravel-json-api/encoder-neomerx": "^4.0",
3131
"laravel-json-api/exceptions": "^3.0",
3232
"laravel-json-api/spec": "^3.0",

tests/dummy/tests/Api/V1/Posts/ReadAuthorTest.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,11 @@ public function test(): void
4242
$response = $this
4343
->withoutExceptionHandling()
4444
->jsonApi('users')
45-
->get($related = url('/api/v1/posts', [$this->post, 'author']));
45+
->get($self = url('/api/v1/posts', [$this->post, 'author']));
4646

47-
$response->assertFetchedOneExact($expected)->assertLinks([
48-
'self' => url('/api/v1/posts', [$this->post, 'relationships', 'author']),
49-
'related' => $related,
50-
]);
47+
$response
48+
->assertFetchedOneExact($expected)
49+
->assertLinks(['self' => $self]);
5150
}
5251

5352
public function testFilterMatches(): void

tests/dummy/tests/Api/V1/Posts/ReadCommentsTest.php

+2-7
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,10 @@ public function test(): void
4848
$response = $this
4949
->withoutExceptionHandling()
5050
->jsonApi('comments')
51-
->get($related = url('/api/v1/posts', [$this->post, 'comments']));
52-
53-
$links = [
54-
'self' => url('/api/v1/posts', [$this->post, 'relationships', 'comments']),
55-
'related' => $related,
56-
];
51+
->get($self = url('/api/v1/posts', [$this->post, 'comments']));
5752

5853
$response->assertFetchedMany($expected)
59-
->assertLinks($links)
54+
->assertLinks(['self' => $self])
6055
->assertExactMeta(['count' => 3]);
6156
}
6257

tests/dummy/tests/Api/V1/Posts/ReadTagsTest.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ public function test(): void
4343

4444
$response = $this
4545
->jsonApi('tags')
46-
->get(url('/api/v1/posts', [$this->post, 'tags']));
46+
->get($self = url('/api/v1/posts', [$this->post, 'tags']));
4747

48-
$response->assertFetchedMany($expected)->assertExactMeta([
49-
'count' => count($expected)
50-
]);
48+
$response
49+
->assertFetchedMany($expected)
50+
->assertExactMeta(['count' => count($expected)])
51+
->assertLinks(['self' => $self]);
5152
}
5253

5354
public function testSort(): void

tests/lib/Acceptance/Relationships/ToManyLinksTest.php

+52-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use App\Models\Post;
1616
use App\Models\Tag;
1717
use Closure;
18+
use LaravelJsonApi\Core\Document\Links;
1819
use LaravelJsonApi\Core\Facades\JsonApi;
1920
use LaravelJsonApi\Laravel\Facades\JsonApiRoute;
2021
use LaravelJsonApi\Laravel\Http\Controllers\JsonApiController;
@@ -60,7 +61,7 @@ protected function setUp(): void
6061
/**
6162
* @return array[]
6263
*/
63-
public static function scenarioProvider(): array
64+
public static function relationshipProvider(): array
6465
{
6566
return [
6667
'hidden' => [
@@ -99,39 +100,81 @@ static function (PostSchema $schema, Post $post) {
99100
/**
100101
* @param Closure $scenario
101102
* @return void
102-
* @dataProvider scenarioProvider
103+
* @dataProvider relationshipProvider
103104
*/
104-
public function testRelated(Closure $scenario): void
105+
public function testRelationship(Closure $scenario): void
105106
{
106107
$expected = $scenario($this->schema, $this->post);
107108

108109
$response = $this
109110
->withoutExceptionHandling()
110111
->jsonApi('tags')
111-
->get(url('/api/v1/posts', [$this->post, 'tags']));
112+
->get(url('/api/v1/posts', [$this->post, 'relationships', 'tags']));
112113

113-
$response->assertFetchedMany([$this->tag]);
114+
$response->assertFetchedToMany([$this->tag]);
114115

115116
if (is_array($expected)) {
116117
$response->assertLinks($expected);
117118
}
118119
}
119120

121+
122+
/**
123+
* @return array[]
124+
*/
125+
public static function relatedProvider(): array
126+
{
127+
return [
128+
'hidden' => [
129+
static function (PostSchema $schema) {
130+
$schema->relationship('tags')->hidden();
131+
return null;
132+
},
133+
],
134+
'no links' => [
135+
static function (PostSchema $schema) {
136+
$schema->relationship('tags')->serializeUsing(
137+
static fn($relation) => $relation->withoutLinks()
138+
);
139+
return null;
140+
},
141+
],
142+
'no self link' => [
143+
static function (PostSchema $schema, Post $post) {
144+
$schema->relationship('tags')->serializeUsing(
145+
static fn($relation) => $relation->withoutSelfLink()
146+
);
147+
// related becomes self.
148+
return ['self' => url('/api/v1/posts', [$post, 'tags'])];
149+
},
150+
],
151+
'no related link' => [
152+
static function (PostSchema $schema, Post $post) {
153+
$schema->relationship('tags')->serializeUsing(
154+
static fn($relation) => $relation->withoutRelatedLink()
155+
);
156+
// related becomes self, but it's missing so we can't do that.
157+
return null;
158+
},
159+
],
160+
];
161+
}
162+
120163
/**
121164
* @param Closure $scenario
122165
* @return void
123-
* @dataProvider scenarioProvider
166+
* @dataProvider relatedProvider
124167
*/
125-
public function testSelf(Closure $scenario): void
168+
public function testRelated(Closure $scenario): void
126169
{
127170
$expected = $scenario($this->schema, $this->post);
128171

129172
$response = $this
130173
->withoutExceptionHandling()
131174
->jsonApi('tags')
132-
->get(url('/api/v1/posts', [$this->post, 'relationships', 'tags']));
175+
->get(url('/api/v1/posts', [$this->post, 'tags']));
133176

134-
$response->assertFetchedToMany([$this->tag]);
177+
$response->assertFetchedMany([$this->tag]);
135178

136179
if (is_array($expected)) {
137180
$response->assertLinks($expected);

tests/lib/Acceptance/Relationships/ToOneLinksTest.php

+50-9
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ protected function setUp(): void
5353
/**
5454
* @return array[]
5555
*/
56-
public static function scenarioProvider(): array
56+
public static function relationshipProvider(): array
5757
{
5858
return [
5959
'hidden' => [
@@ -92,39 +92,80 @@ static function (PostSchema $schema, Post $post) {
9292
/**
9393
* @param Closure $scenario
9494
* @return void
95-
* @dataProvider scenarioProvider
95+
* @dataProvider relationshipProvider
9696
*/
97-
public function testRelated(Closure $scenario): void
97+
public function testRelationship(Closure $scenario): void
9898
{
9999
$expected = $scenario($this->schema, $this->post);
100100

101101
$response = $this
102102
->withoutExceptionHandling()
103103
->jsonApi('users')
104-
->get(url('/api/v1/posts', [$this->post, 'author']));
104+
->get(url('/api/v1/posts', [$this->post, 'relationships', 'author']));
105105

106-
$response->assertFetchedOne($this->post->author);
106+
$response->assertFetchedToOne($this->post->author);
107107

108108
if (is_array($expected)) {
109109
$response->assertLinks($expected);
110110
}
111111
}
112112

113+
/**
114+
* @return array[]
115+
*/
116+
public static function relatedProvider(): array
117+
{
118+
return [
119+
'hidden' => [
120+
static function (PostSchema $schema) {
121+
$schema->relationship('author')->hidden();
122+
return null;
123+
},
124+
],
125+
'no links' => [
126+
static function (PostSchema $schema) {
127+
$schema->relationship('author')->serializeUsing(
128+
static fn($relation) => $relation->withoutLinks()
129+
);
130+
return null;
131+
},
132+
],
133+
'no self link' => [
134+
static function (PostSchema $schema, Post $post) {
135+
$schema->relationship('author')->serializeUsing(
136+
static fn($relation) => $relation->withoutSelfLink()
137+
);
138+
// related becomes self
139+
return ['self' => url('/api/v1/posts', [$post, 'author'])];
140+
},
141+
],
142+
'no related link' => [
143+
static function (PostSchema $schema, Post $post) {
144+
$schema->relationship('author')->serializeUsing(
145+
static fn($relation) => $relation->withoutRelatedLink()
146+
);
147+
// related becomes self but it's missing
148+
return null;
149+
},
150+
],
151+
];
152+
}
153+
113154
/**
114155
* @param Closure $scenario
115156
* @return void
116-
* @dataProvider scenarioProvider
157+
* @dataProvider relatedProvider
117158
*/
118-
public function testSelf(Closure $scenario): void
159+
public function testRelated(Closure $scenario): void
119160
{
120161
$expected = $scenario($this->schema, $this->post);
121162

122163
$response = $this
123164
->withoutExceptionHandling()
124165
->jsonApi('users')
125-
->get(url('/api/v1/posts', [$this->post, 'relationships', 'author']));
166+
->get(url('/api/v1/posts', [$this->post, 'author']));
126167

127-
$response->assertFetchedToOne($this->post->author);
168+
$response->assertFetchedOne($this->post->author);
128169

129170
if (is_array($expected)) {
130171
$response->assertLinks($expected);

0 commit comments

Comments
 (0)