Skip to content

Commit 30ffdaa

Browse files
committed
Laravel Resource Reducer
1 parent d8e9d35 commit 30ffdaa

File tree

8 files changed

+360
-6
lines changed

8 files changed

+360
-6
lines changed

src/Json/AnonymousResourceReducerCollection.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
66
use Illuminate\Http\Request;
77
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
8+
use Illuminate\Pagination\AbstractCursorPaginator;
9+
use Illuminate\Pagination\AbstractPaginator;
810
use Illuminate\Support\Collection;
911
use ShipSaasReducer\Helpers\Helper;
1012
use ShipSaasReducer\Json\Traits\HasRelation;
@@ -65,6 +67,10 @@ private function doEagerLoad(JsonReducerResource $reducerResource): void
6567

6668
public function toResponse($request)
6769
{
70+
if ($this->resource instanceof AbstractPaginator || $this->resource instanceof AbstractCursorPaginator) {
71+
return $this->preparePaginatedResponse($request);
72+
}
73+
6874
return (new ReducerResponse($this))->toResponse($request);
6975
}
7076
}

src/Json/JsonReducerResource.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ private function transformValue(mixed $retriever, string $requestedKey): mixed
127127
}
128128

129129
$relationName = $retriever->getRelationName();
130-
if (!$this->resource->relationLoaded($relationName)) {
130+
if (!$this->resource->relationLoaded($relationName) || $this->resource->{$relationName} === null) {
131131
return null;
132132
}
133133

tests/App/Http/Controllers/UserController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class UserController extends Controller
1313
public function index(Request $request): JsonResponse
1414
{
1515
$users = $request->has('pagination')
16-
? User::paginate(10)
16+
? User::paginate(2)
1717
: User::all();
1818

1919
return UserResource::collection($users)->response();

tests/Assertions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ trait Assertions
1212
{
1313
protected function withDbQueryLogEnabled(callable $handler): array
1414
{
15+
DB::flushQueryLog();
1516
DB::enableQueryLog();
1617

1718
call_user_func($handler);
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?php
2+
3+
namespace ShipSaasReducer\Tests\Features;
4+
5+
use Illuminate\Support\Facades\DB;
6+
use ShipSaasReducer\Tests\App\Models\User;
7+
use ShipSaasReducer\Tests\TestCase;
8+
9+
class UserControllerNormalIndexTest extends TestCase
10+
{
11+
public function testIndexReturnsAllUsersFirstLevel()
12+
{
13+
$adminUser = User::where('name', 'Admin')->first();
14+
$normalUser = User::where('name', 'User')->first();
15+
$inactivatedUser = User::where('name', 'Inactivated User')->first();
16+
17+
$res = null;
18+
$this->assertTotalQueries(1, function () use (&$res) {
19+
$res = $this->json('GET', "/users", [
20+
'_f' => [
21+
'id',
22+
'name',
23+
'email',
24+
],
25+
]);
26+
});
27+
28+
$res->assertOk()
29+
->assertJsonStructure([
30+
'data' => [
31+
'*' => [
32+
'id',
33+
'name',
34+
'email',
35+
],
36+
],
37+
])
38+
->assertJsonFragment([
39+
'name' => $adminUser->name,
40+
'email' => $adminUser->email,
41+
])
42+
->assertJsonFragment([
43+
'name' => $normalUser->name,
44+
'email' => $normalUser->email,
45+
])
46+
->assertJsonFragment([
47+
'name' => $inactivatedUser->name,
48+
'email' => $inactivatedUser->email,
49+
]);
50+
}
51+
52+
public function testIndexReturnsAllUsersSecondLevel()
53+
{
54+
$adminUser = User::where('name', 'Admin')->first();
55+
$normalUser = User::where('name', 'User')->first();
56+
$inactivatedUser = User::where('name', 'Inactivated User')->first();
57+
58+
$res = null;
59+
$this->assertTotalQueries(2, function () use (&$res) {
60+
$res = $this->json('GET', "/users", [
61+
'_f' => [
62+
'name',
63+
'role.id',
64+
'role.name',
65+
],
66+
]);
67+
});
68+
69+
$res->assertOk()
70+
->assertJsonFragment([
71+
'name' => $adminUser->name,
72+
'role' => [
73+
'id' => $adminUser->role_id,
74+
'name' => $adminUser->role->name,
75+
],
76+
])
77+
->assertJsonFragment([
78+
'name' => $normalUser->name,
79+
'role' => [
80+
'id' => $normalUser->role_id,
81+
'name' => $normalUser->role->name,
82+
],
83+
])
84+
->assertJsonFragment([
85+
'name' => $inactivatedUser->name,
86+
'role' => null,
87+
]);
88+
}
89+
90+
public function testIndexReturnsAllUsersThirdLevel()
91+
{
92+
$adminUser = User::where('name', 'Admin')->first();
93+
$normalUser = User::where('name', 'User')->first();
94+
$inactivatedUser = User::where('name', 'Inactivated User')->first();
95+
96+
$res = null;
97+
$this->assertTotalQueries(4, function () use (&$res) {
98+
$res = $this->json('GET', "/users", [
99+
'_f' => [
100+
'name',
101+
'role.id',
102+
'role.name',
103+
'role.permissions.name',
104+
'articles.title',
105+
],
106+
]);
107+
});
108+
109+
$res->assertOk()
110+
->assertJsonFragment([
111+
'name' => $adminUser->name,
112+
'role' => [
113+
'id' => $adminUser->role_id,
114+
'name' => $adminUser->role->name,
115+
'permissions' => [
116+
['name' => 'View User'],
117+
['name' => 'Create User'],
118+
['name' => 'Delete User'],
119+
],
120+
],
121+
'articles' => [
122+
['title' => 'The Laravel Resource Reducer'],
123+
['title' => 'Please start'],
124+
],
125+
])
126+
->assertJsonFragment([
127+
'name' => $normalUser->name,
128+
'role' => [
129+
'id' => $normalUser->role_id,
130+
'name' => $normalUser->role->name,
131+
'permissions' => [
132+
['name' => 'View User'],
133+
],
134+
],
135+
'articles' => [],
136+
])
137+
->assertJsonFragment([
138+
'name' => $inactivatedUser->name,
139+
'role' => null,
140+
'articles' => [],
141+
]);
142+
}
143+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
<?php
2+
3+
namespace ShipSaasReducer\Tests\Features;
4+
5+
use ShipSaasReducer\Tests\App\Models\User;
6+
use ShipSaasReducer\Tests\TestCase;
7+
8+
class UserControllerPaginatedIndexTest extends TestCase
9+
{
10+
public function testIndexPaginatedReturnsTwoUsersFirstLevel()
11+
{
12+
$adminUser = User::where('name', 'Admin')->first();
13+
$normalUser = User::where('name', 'User')->first();
14+
$inactivatedUser = User::where('name', 'Inactivated User')->first();
15+
16+
$res = null;
17+
18+
// 2 queries: listing & count (because of pagination)
19+
$this->assertTotalQueries(2, function () use (&$res) {
20+
$res = $this->json('GET', "/users", [
21+
'pagination' => 1,
22+
'_f' => [
23+
'id',
24+
'name',
25+
'email',
26+
],
27+
]);
28+
});
29+
30+
$res->assertOk()
31+
->assertJsonStructure([
32+
'data' => [
33+
'*' => [
34+
'id',
35+
'name',
36+
'email',
37+
],
38+
],
39+
'meta' => [
40+
'current_page',
41+
'from',
42+
'last_page',
43+
],
44+
])
45+
->assertJsonFragment([
46+
'name' => $adminUser->name,
47+
'email' => $adminUser->email,
48+
])
49+
->assertJsonFragment([
50+
'name' => $normalUser->name,
51+
'email' => $normalUser->email,
52+
])
53+
->assertJsonMissing([
54+
'name' => $inactivatedUser->name,
55+
'email' => $inactivatedUser->email,
56+
]);
57+
}
58+
59+
public function testIndexPaginatedReturnsTwoUsersSecondLevel()
60+
{
61+
$adminUser = User::where('name', 'Admin')->first();
62+
$normalUser = User::where('name', 'User')->first();
63+
$inactivatedUser = User::where('name', 'Inactivated User')->first();
64+
65+
$res = null;
66+
$this->assertTotalQueries(3, function () use (&$res) {
67+
$res = $this->json('GET', "/users", [
68+
'pagination' => 1,
69+
'_f' => [
70+
'name',
71+
'role.id',
72+
'role.name',
73+
],
74+
]);
75+
});
76+
77+
$res->assertOk()
78+
->assertJsonStructure([
79+
'meta' => [
80+
'current_page',
81+
'from',
82+
'last_page',
83+
],
84+
])
85+
->assertJsonFragment([
86+
'name' => $adminUser->name,
87+
'role' => [
88+
'id' => $adminUser->role_id,
89+
'name' => $adminUser->role->name,
90+
],
91+
])
92+
->assertJsonFragment([
93+
'name' => $normalUser->name,
94+
'role' => [
95+
'id' => $normalUser->role_id,
96+
'name' => $normalUser->role->name,
97+
],
98+
])
99+
->assertJsonMissing([
100+
'name' => $inactivatedUser->name,
101+
'role' => null,
102+
]);
103+
}
104+
105+
public function testIndexPaginatedReturnsTwoUsersThirdLevel()
106+
{
107+
$adminUser = User::where('name', 'Admin')->first();
108+
$normalUser = User::where('name', 'User')->first();
109+
$inactivatedUser = User::where('name', 'Inactivated User')->first();
110+
111+
$res = null;
112+
$this->assertTotalQueries(5, function () use (&$res) {
113+
$res = $this->json('GET', "/users", [
114+
'pagination' => 1,
115+
'_f' => [
116+
'name',
117+
'role.id',
118+
'role.name',
119+
'role.permissions.name',
120+
'articles.title',
121+
],
122+
]);
123+
});
124+
125+
$res->assertOk()
126+
->assertJsonStructure([
127+
'meta' => [
128+
'current_page',
129+
'from',
130+
'last_page',
131+
],
132+
])
133+
->assertJsonFragment([
134+
'name' => $adminUser->name,
135+
'role' => [
136+
'id' => $adminUser->role_id,
137+
'name' => $adminUser->role->name,
138+
'permissions' => [
139+
['name' => 'View User'],
140+
['name' => 'Create User'],
141+
['name' => 'Delete User'],
142+
],
143+
],
144+
'articles' => [
145+
['title' => 'The Laravel Resource Reducer'],
146+
['title' => 'Please start'],
147+
],
148+
])
149+
->assertJsonFragment([
150+
'name' => $normalUser->name,
151+
'role' => [
152+
'id' => $normalUser->role_id,
153+
'name' => $normalUser->role->name,
154+
'permissions' => [
155+
['name' => 'View User'],
156+
],
157+
],
158+
'articles' => [],
159+
])
160+
->assertJsonMissing([
161+
'name' => $inactivatedUser->name,
162+
]);
163+
164+
$secondRes = null;
165+
166+
// 2 queries for user & count
167+
// 1 for articles
168+
$this->assertTotalQueries(3, function () use (&$secondRes) {
169+
$secondRes = $this->json('GET', "/users", [
170+
'pagination' => 1,
171+
'page' => 2,
172+
'_f' => [
173+
'name',
174+
'role.id',
175+
'role.name',
176+
'role.permissions.name',
177+
'articles.title',
178+
],
179+
]);
180+
});
181+
182+
$secondRes->assertOk()
183+
->assertJsonStructure([
184+
'meta' => [
185+
'current_page',
186+
'from',
187+
'last_page',
188+
],
189+
])
190+
->assertJsonFragment([
191+
'name' => $inactivatedUser->name,
192+
'role' => null,
193+
'articles' => [],
194+
])
195+
->assertJsonMissing([
196+
'name' => $adminUser->name,
197+
]);
198+
}
199+
}

tests/Features/UserControllerTest.php renamed to tests/Features/UserControllerShowTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use ShipSaasReducer\Tests\App\Models\User;
77
use ShipSaasReducer\Tests\TestCase;
88

9-
class UserControllerTest extends TestCase
9+
class UserControllerShowTest extends TestCase
1010
{
1111
public function testShowReturnsSingleUserFirstLevel()
1212
{

0 commit comments

Comments
 (0)