Skip to content

Commit c2183fc

Browse files
authored
Merge pull request #769 from inertiajs/provides-inertia-props
[2.x] Introduce ProvidesInertiaProps interface
2 parents 091daa7 + 3bf2443 commit c2183fc

File tree

6 files changed

+136
-4
lines changed

6 files changed

+136
-4
lines changed

src/ProvidesInertiaProperties.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Inertia;
4+
5+
interface ProvidesInertiaProperties
6+
{
7+
public function toInertiaProperties(RenderContext $context): iterable;
8+
}

src/RenderContext.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Inertia;
4+
5+
use Illuminate\Http\Request;
6+
7+
class RenderContext
8+
{
9+
public function __construct(
10+
public string $component,
11+
public Request $request
12+
) {
13+
//
14+
}
15+
}

src/Response.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,15 @@ public function __construct(
5959
}
6060

6161
/**
62-
* @param string|array $key
62+
* @param string|array|ProvidesInertiaProperties $key
6363
* @param mixed $value
6464
* @return $this
6565
*/
6666
public function with($key, $value = null): self
6767
{
68-
if (is_array($key)) {
68+
if ($key instanceof ProvidesInertiaProperties) {
69+
$this->props[] = $key;
70+
} elseif (is_array($key)) {
6971
$this->props = array_merge($this->props, $key);
7072
} else {
7173
$this->props[$key] = $value;
@@ -140,6 +142,7 @@ public function toResponse($request)
140142
*/
141143
public function resolveProperties(Request $request, array $props): array
142144
{
145+
$props = $this->resolveInertiaPropsProviders($props, $request);
143146
$props = $this->resolvePartialProperties($props, $request);
144147
$props = $this->resolveArrayableProperties($props, $request);
145148
$props = $this->resolveAlways($props);
@@ -148,13 +151,37 @@ public function resolveProperties(Request $request, array $props): array
148151
return $props;
149152
}
150153

154+
/**
155+
* Resolve the ProvidesInertiaProperties props.
156+
*/
157+
public function resolveInertiaPropsProviders(array $props, Request $request): array
158+
{
159+
$newProps = [];
160+
161+
$renderContext = new RenderContext($this->component, $request);
162+
163+
foreach ($props as $key => $value) {
164+
if (is_numeric($key) && $value instanceof ProvidesInertiaProperties) {
165+
// Pipe into a Collection to leverage Collection::getArrayableItems()
166+
$newProps = array_merge(
167+
$newProps,
168+
collect($value->toInertiaProperties($renderContext))->all()
169+
);
170+
} else {
171+
$newProps[$key] = $value;
172+
}
173+
}
174+
175+
return $newProps;
176+
}
177+
151178
/**
152179
* Resolve the `only` and `except` partial request props.
153180
*/
154181
public function resolvePartialProperties(array $props, Request $request): array
155182
{
156183
if (! $this->isPartial($request)) {
157-
return array_filter($this->props, static function ($prop) {
184+
return array_filter($props, static function ($prop) {
158185
return ! ($prop instanceof IgnoreFirstLoad);
159186
});
160187
}

src/ResponseFactory.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ protected function findComponentOrFail(string $component): void
170170
}
171171

172172
/**
173-
* @param array|Arrayable $props
173+
* @param array|Arrayable|ProvidesInertiaProperties $props
174174
*/
175175
public function render(string $component, $props = []): Response
176176
{
@@ -180,6 +180,9 @@ public function render(string $component, $props = []): Response
180180

181181
if ($props instanceof Arrayable) {
182182
$props = $props->toArray();
183+
} elseif ($props instanceof ProvidesInertiaProperties) {
184+
// Will be resolved in Response::resolveResponsableProperties()
185+
$props = [$props];
183186
}
184187

185188
return new Response(

tests/ResponseFactoryTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
use Inertia\LazyProp;
1919
use Inertia\MergeProp;
2020
use Inertia\OptionalProp;
21+
use Inertia\ProvidesInertiaProperties;
22+
use Inertia\RenderContext;
2123
use Inertia\ResponseFactory;
2224
use Inertia\Tests\Stubs\ExampleMiddleware;
2325

@@ -378,6 +380,30 @@ public function toArray()
378380
]);
379381
}
380382

383+
public function test_will_accept_instances_of_provides_inertia_props()
384+
{
385+
Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () {
386+
return Inertia::render('User/Edit', new class implements ProvidesInertiaProperties
387+
{
388+
public function toInertiaProperties(RenderContext $context): iterable
389+
{
390+
return [
391+
'foo' => 'bar',
392+
];
393+
}
394+
});
395+
});
396+
397+
$response = $this->withoutExceptionHandling()->get('/', ['X-Inertia' => 'true']);
398+
$response->assertSuccessful();
399+
$response->assertJson([
400+
'component' => 'User/Edit',
401+
'props' => [
402+
'foo' => 'bar',
403+
],
404+
]);
405+
}
406+
381407
public function test_will_throw_exception_if_component_does_not_exist_when_ensuring_is_enabled(): void
382408
{
383409
config()->set('inertia.ensure_pages_exist', true);

tests/ResponseTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Inertia\Inertia;
1818
use Inertia\LazyProp;
1919
use Inertia\MergeProp;
20+
use Inertia\ProvidesInertiaProperties;
21+
use Inertia\RenderContext;
2022
use Inertia\Response;
2123
use Inertia\Tests\Stubs\FakeResource;
2224
use Inertia\Tests\Stubs\MergeWithSharedProp;
@@ -822,6 +824,33 @@ public function test_always_props_are_included_on_partial_reload(): void
822824
$this->assertFalse(isset($page->props->user));
823825
}
824826

827+
public function test_inertia_responsable_objects(): void
828+
{
829+
$request = Request::create('/user/123', 'GET');
830+
831+
$response = new Response('User/Edit', [
832+
'foo' => 'bar',
833+
new class implements ProvidesInertiaProperties
834+
{
835+
public function toInertiaProperties(RenderContext $context): iterable
836+
{
837+
return collect([
838+
'baz' => 'qux',
839+
]);
840+
}
841+
},
842+
'quux' => 'corge',
843+
844+
], 'app', '123');
845+
$response = $response->toResponse($request);
846+
$view = $response->getOriginalContent();
847+
$page = $view->getData()['page'];
848+
849+
$this->assertSame('bar', $page['props']['foo']);
850+
$this->assertSame('qux', $page['props']['baz']);
851+
$this->assertSame('corge', $page['props']['quux']);
852+
}
853+
825854
public function test_inertia_response_type_prop(): void
826855
{
827856
$request = Request::create('/user/123', 'GET');
@@ -899,6 +928,30 @@ public function test_nested_dot_props_do_not_get_unpacked(): void
899928
$this->assertFalse(array_key_exists('can', $auth));
900929
}
901930

931+
public function test_props_can_be_added_using_the_with_method(): void
932+
{
933+
$request = Request::create('/user/123', 'GET');
934+
$response = new Response('User/Edit', [], 'app', '123');
935+
936+
$response->with(['foo' => 'bar', 'baz' => 'qux'])
937+
->with(['quux' => 'corge'])
938+
->with(new class implements ProvidesInertiaProperties
939+
{
940+
public function toInertiaProperties(RenderContext $context): iterable
941+
{
942+
return collect(['grault' => 'garply']);
943+
}
944+
});
945+
946+
$response = $response->toResponse($request);
947+
$view = $response->getOriginalContent();
948+
$page = $view->getData()['page'];
949+
950+
$this->assertSame('bar', $page['props']['foo']);
951+
$this->assertSame('qux', $page['props']['baz']);
952+
$this->assertSame('corge', $page['props']['quux']);
953+
}
954+
902955
public function test_responsable_with_invalid_key(): void
903956
{
904957
$request = Request::create('/user/123', 'GET');

0 commit comments

Comments
 (0)