Skip to content

Commit 56e12cd

Browse files
authored
Fixes #298 (#342)
* Fixes #298
1 parent 4931fb7 commit 56e12cd

File tree

2 files changed

+98
-28
lines changed

2 files changed

+98
-28
lines changed

src/Response.php

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Contracts\Support\Arrayable;
88
use Illuminate\Contracts\Support\Responsable;
99
use Illuminate\Http\JsonResponse;
10+
use Illuminate\Http\Request;
1011
use Illuminate\Http\Resources\Json\JsonResource;
1112
use Illuminate\Http\Resources\Json\ResourceResponse;
1213
use Illuminate\Support\Arr;
@@ -93,34 +94,7 @@ public function toResponse($request)
9394
return ! ($prop instanceof LazyProp);
9495
});
9596

96-
array_walk_recursive($props, static function (&$prop) use ($request) {
97-
if ($prop instanceof LazyProp) {
98-
$prop = App::call($prop);
99-
}
100-
101-
if ($prop instanceof Closure) {
102-
$prop = App::call($prop);
103-
}
104-
105-
if ($prop instanceof PromiseInterface) {
106-
$prop = $prop->wait();
107-
}
108-
109-
if ($prop instanceof ResourceResponse || $prop instanceof JsonResource) {
110-
$prop = $prop->toResponse($request)->getData(true);
111-
}
112-
113-
if ($prop instanceof Arrayable) {
114-
$prop = $prop->toArray();
115-
}
116-
});
117-
118-
foreach ($props as $key => $value) {
119-
if (str_contains($key, '.')) {
120-
data_set($props, $key, $value);
121-
unset($props[$key]);
122-
}
123-
}
97+
$props = $this->resolvePropertyInstances($props, $request);
12498

12599
$page = [
126100
'component' => $this->component,
@@ -138,4 +112,44 @@ public function toResponse($request)
138112

139113
return ResponseFactory::view($this->rootView, $this->viewData + ['page' => $page]);
140114
}
115+
116+
/**
117+
* Resolve all necessary class instances in the given props.
118+
*
119+
* @param array $props
120+
* @param \Illuminate\Http\Request $request
121+
* @return array
122+
*/
123+
public function resolvePropertyInstances(array $props, Request $request): array
124+
{
125+
foreach ($props as $key => $value) {
126+
if ($value instanceof Closure) {
127+
$value = App::call($value);
128+
}
129+
130+
if ($value instanceof LazyProp) {
131+
$value = App::call($value);
132+
}
133+
134+
if ($value instanceof PromiseInterface) {
135+
$value = $value->wait();
136+
}
137+
138+
if ($value instanceof ResourceResponse || $value instanceof JsonResource) {
139+
$value = $value->toResponse($request)->getData(true);
140+
}
141+
142+
if ($value instanceof Arrayable) {
143+
$value = $value->toArray();
144+
}
145+
146+
if (is_array($value)) {
147+
$value = $this->resolvePropertyInstances($value, $request);
148+
}
149+
150+
Arr::set($props, $key, $value);
151+
}
152+
153+
return $props;
154+
}
141155
}

tests/ResponseTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,62 @@ public function test_lazy_resource_response(): void
136136
});
137137
}
138138

139+
public function test_nested_lazy_resource_response(): void
140+
{
141+
$request = Request::create('/users', 'GET', ['page' => 1]);
142+
$request->headers->add(['X-Inertia' => 'true']);
143+
144+
$users = Collection::make([
145+
new Fluent(['name' => 'Jonathan']),
146+
new Fluent(['name' => 'Taylor']),
147+
new Fluent(['name' => 'Jeffrey']),
148+
]);
149+
150+
$callable = static function () use ($users) {
151+
$page = new LengthAwarePaginator($users->take(2), $users->count(), 2);
152+
153+
// nested array with ResourceCollection to resolve
154+
return [
155+
'users' => new class($page, JsonResource::class) extends ResourceCollection {},
156+
];
157+
};
158+
159+
$response = new Response('User/Index', ['something' => $callable], 'app', '123');
160+
$response = $response->toResponse($request);
161+
$page = $response->getData();
162+
163+
$expected = [
164+
'users' => [
165+
'data' => $users->take(2),
166+
'links' => [
167+
'first' => '/?page=1',
168+
'last' => '/?page=2',
169+
'prev' => null,
170+
'next' => '/?page=2',
171+
],
172+
'meta' => [
173+
'current_page' => 1,
174+
'from' => 1,
175+
'last_page' => 2,
176+
'path' => '/',
177+
'per_page' => 2,
178+
'to' => 2,
179+
'total' => 3,
180+
],
181+
],
182+
];
183+
184+
$this->assertInstanceOf(JsonResponse::class, $response);
185+
$this->assertSame('User/Index', $page->component);
186+
$this->assertSame('/users?page=1', $page->url);
187+
$this->assertSame('123', $page->version);
188+
tap($page->props->something->users, function ($users) use ($expected) {
189+
$this->assertSame(json_encode($expected['users']['data']), json_encode($users->data));
190+
$this->assertSame(json_encode($expected['users']['links']), json_encode($users->links));
191+
$this->assertSame('/', $users->meta->path);
192+
});
193+
}
194+
139195
public function test_arrayable_prop_response(): void
140196
{
141197
$request = Request::create('/user/123', 'GET');

0 commit comments

Comments
 (0)