Skip to content

Commit dd31985

Browse files
Add initial props resolver to Inertia
1 parent a355007 commit dd31985

File tree

6 files changed

+128
-1
lines changed

6 files changed

+128
-1
lines changed

src/Inertia.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* @method static void version(\Closure|string|null $version)
1515
* @method static string getVersion()
1616
* @method static void resolveUrlUsing(\Closure|null $urlResolver = null)
17+
* @method static void resolveInitialProps(\Closure|null $initialPropsResolver = null)
1718
* @method static \Inertia\OptionalProp optional(callable $callback)
1819
* @method static \Inertia\LazyProp lazy(callable $callback)
1920
* @method static \Inertia\DeferProp defer(callable $callback, string $group = 'default')

src/Middleware.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ public function urlResolver()
7575
return null;
7676
}
7777

78+
/**
79+
* Defines the initial props that are shared by default.
80+
*
81+
* @return \Closure|null
82+
*/
83+
public function initialPropsResolver()
84+
{
85+
return null;
86+
}
87+
7888
/**
7989
* Handle the incoming request.
8090
*
@@ -93,6 +103,10 @@ public function handle(Request $request, Closure $next)
93103
Inertia::resolveUrlUsing($urlResolver);
94104
}
95105

106+
if ($initialPropsResolver = $this->initialPropsResolver()) {
107+
Inertia::resolveInitialPropsUsing($initialPropsResolver);
108+
}
109+
96110
$response = $next($request);
97111
$response->headers->set('Vary', Header::INERTIA);
98112

src/Response.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ class Response implements Responsable
8181
*/
8282
protected ?Closure $urlResolver = null;
8383

84+
/**
85+
* The initial props resolver callback.
86+
*/
87+
protected ?Closure $initialPropsResolver = null;
88+
8489
/**
8590
* Create a new Inertia response instance.
8691
*
@@ -92,7 +97,8 @@ public function __construct(
9297
string $rootView = 'app',
9398
string $version = '',
9499
bool $encryptHistory = false,
95-
?Closure $urlResolver = null
100+
?Closure $urlResolver = null,
101+
?Closure $initialPropsResolver = null,
96102
) {
97103
$this->component = $component;
98104
$this->props = $props;
@@ -101,6 +107,7 @@ public function __construct(
101107
$this->clearHistory = session()->pull('inertia.clear_history', false);
102108
$this->encryptHistory = $encryptHistory;
103109
$this->urlResolver = $urlResolver;
110+
$this->initialPropsResolver = $initialPropsResolver;
104111
}
105112

106113
/**
@@ -188,6 +195,7 @@ public function toResponse($request)
188195
$this->resolveMergeProps($request),
189196
$this->resolveDeferredProps($request),
190197
$this->resolveCacheDirections($request),
198+
$this->resolveInitialProps($request),
191199
);
192200

193201
if ($request->header(Header::INERTIA)) {
@@ -508,6 +516,26 @@ public function resolveDeferredProps(Request $request): array
508516
return $deferredProps->isNotEmpty() ? ['deferredProps' => $deferredProps->toArray()] : [];
509517
}
510518

519+
/**
520+
* Resolve initial props.
521+
*
522+
* @return array<string, mixed>
523+
*/
524+
public function resolveInitialProps(Request $request): array
525+
{
526+
if ($request->header(Header::INERTIA)) {
527+
return [];
528+
}
529+
530+
if ($this->initialPropsResolver === null) {
531+
return [];
532+
}
533+
534+
$initialProps = App::call($this->initialPropsResolver, ['request' => $request]);
535+
536+
return empty($initialProps) ? [] : ['initialProps' => $initialProps];
537+
}
538+
511539
/**
512540
* Determine if the request is a partial request.
513541
*/

src/ResponseFactory.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ class ResponseFactory
6161
*/
6262
protected $urlResolver;
6363

64+
/**
65+
* The initial props resolver callback.
66+
*
67+
* @var Closure|null
68+
*/
69+
protected $initialPropsResolver;
70+
6471
/**
6572
* Set the root view template for Inertia responses. This template
6673
* serves as the HTML wrapper that contains the Inertia root element
@@ -149,6 +156,14 @@ public function resolveUrlUsing(?Closure $urlResolver = null): void
149156
$this->urlResolver = $urlResolver;
150157
}
151158

159+
/**
160+
* Set the initial props resolver.
161+
*/
162+
public function resolveInitialPropsUsing(?Closure $initialPropsResolver = null): void
163+
{
164+
$this->initialPropsResolver = $initialPropsResolver;
165+
}
166+
152167
/**
153168
* Clear the browser history on the next visit.
154169
*/
@@ -262,6 +277,7 @@ public function render(string $component, $props = []): Response
262277
$this->getVersion(),
263278
$this->encryptHistory ?? config('inertia.history.encrypt', false),
264279
$this->urlResolver,
280+
$this->initialPropsResolver,
265281
);
266282
}
267283

tests/InitialPropTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Inertia\Tests;
4+
5+
use Illuminate\Session\Middleware\StartSession;
6+
use Illuminate\Support\Facades\Route;
7+
use Inertia\Inertia;
8+
use Inertia\Tests\Stubs\CustomInitialPropsResolverMiddleware;
9+
use Inertia\Tests\Stubs\ExampleMiddleware;
10+
11+
class InitialPropTest extends TestCase
12+
{
13+
public function test_initial_props_accessibility()
14+
{
15+
$this->prepareMockEndpoint();
16+
17+
$response = $this->withoutExceptionHandling()->get('/');
18+
19+
$response->assertSuccessful();
20+
$this->assertSame(
21+
'<div id="app" data-page="{&quot;component&quot;:&quot;User\/Edit&quot;,&quot;props&quot;:{&quot;errors&quot;:{}},&quot;url&quot;:&quot;\/&quot;,&quot;version&quot;:&quot;&quot;,&quot;clearHistory&quot;:false,&quot;encryptHistory&quot;:false,&quot;initialProps&quot;:{&quot;initial&quot;:true,&quot;appName&quot;:&quot;test&quot;}}"></div>',
22+
$response->content(),
23+
);
24+
}
25+
26+
public function test_initial_props_are_not_accessible()
27+
{
28+
$this->prepareMockEndpoint();
29+
30+
$response = $this->withoutExceptionHandling()->get('/', [
31+
'X-Inertia' => 'true',
32+
]);
33+
34+
$response->assertSuccessful();
35+
$response->assertJsonMissingPath('initialProps');
36+
}
37+
38+
private function prepareMockEndpoint(): \Illuminate\Routing\Route
39+
{
40+
return Route::middleware([StartSession::class, ExampleMiddleware::class, CustomInitialPropsResolverMiddleware::class])->get('/', function () {
41+
return Inertia::render('User/Edit');
42+
});
43+
}
44+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Inertia\Tests\Stubs;
4+
5+
use Illuminate\Http\Request;
6+
use Illuminate\Routing\ResponseFactory;
7+
use Inertia\Middleware;
8+
use PHPUnit\Framework\Assert;
9+
10+
class CustomInitialPropsResolverMiddleware extends Middleware
11+
{
12+
public function initialPropsResolver()
13+
{
14+
return function ($request, ResponseFactory $otherDependency) {
15+
Assert::assertInstanceOf(Request::class, $request);
16+
Assert::assertInstanceOf(ResponseFactory::class, $otherDependency);
17+
18+
return [
19+
'initial' => true,
20+
'appName' => 'test',
21+
];
22+
};
23+
}
24+
}

0 commit comments

Comments
 (0)