Skip to content

Commit 5cbaeab

Browse files
lepikhinbreinink
andauthored
Add "always" props using new Inertia::always() wrapper (#627)
* `AlwaysProp` implementation * make `always` accept any param type * resolve bindings on `AlwaysProp` invoke * resolve callables in `AlwaysProp` * Update "always" types in facade * Update changelog --------- Co-authored-by: Jonathan Reinink <[email protected]>
1 parent 82f3dc6 commit 5cbaeab

11 files changed

+140
-124
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## [Unreleased](https://github.com/inertiajs/inertia-laravel/compare/v1.2.0...1.x)
44

5+
- Add "always" props using new `Inertia::always()` wrapper ([#627](https://github.com/inertiajs/inertia-laravel/pull/627))
6+
57
## [v1.2.0](https://github.com/inertiajs/inertia-laravel/compare/v1.1.0...v1.2.0) - 2024-05-17
68

79
* [1.x] Make commands lazy by [@timacdonald](https://github.com/timacdonald) in https://github.com/inertiajs/inertia-laravel/pull/601

src/AlwaysProp.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Inertia;
4+
5+
use Illuminate\Support\Facades\App;
6+
7+
class AlwaysProp
8+
{
9+
/** @var mixed */
10+
protected $value;
11+
12+
/**
13+
* @param mixed $value
14+
*/
15+
public function __construct($value)
16+
{
17+
$this->value = $value;
18+
}
19+
20+
public function __invoke()
21+
{
22+
return is_callable($this->value) ? App::call($this->value) : $this->value;
23+
}
24+
}

src/Inertia.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@
1212
* @method static void version(\Closure|string|null $version)
1313
* @method static string getVersion()
1414
* @method static \Inertia\LazyProp lazy(callable $callback)
15+
* @method static \Inertia\AlwaysProp always(mixed $value)
1516
* @method static \Inertia\Response render(string $component, array|\Illuminate\Contracts\Support\Arrayable $props = [])
1617
* @method static \Symfony\Component\HttpFoundation\Response location(string|\Symfony\Component\HttpFoundation\RedirectResponse $url)
1718
* @method static void macro(string $name, object|callable $macro)
1819
* @method static void mixin(object $mixin, bool $replace = true)
1920
* @method static bool hasMacro(string $name)
2021
* @method static void flushMacros()
21-
* @method static void persist(string|array|\Illuminate\Contracts\Support\Arrayable $props)
22-
* @method static array getPersisted()
23-
* @method static void flushPersisted()
2422
*
2523
* @see \Inertia\ResponseFactory
2624
*/

src/Middleware.php

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ class Middleware
1919
*/
2020
protected $rootView = 'app';
2121

22-
/**
23-
* The properties that should always be included on Inertia responses, regardless of "only" or "except" requests.
24-
*
25-
* @var array
26-
*/
27-
protected $persisted = [];
28-
2922
/**
3023
* Determines the current asset version.
3124
*
@@ -60,9 +53,7 @@ public function version(Request $request)
6053
public function share(Request $request)
6154
{
6255
return [
63-
'errors' => function () use ($request) {
64-
return $this->resolveValidationErrors($request);
65-
},
56+
'errors' => Inertia::always($this->resolveValidationErrors($request)),
6657
];
6758
}
6859

@@ -90,7 +81,6 @@ public function handle(Request $request, Closure $next)
9081
});
9182

9283
Inertia::share($this->share($request));
93-
Inertia::persist($this->persisted);
9484
Inertia::setRootView($this->rootView($request));
9585

9686
$response = $next($request);

src/Response.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,17 @@ class Response implements Responsable
2323

2424
protected $component;
2525
protected $props;
26-
protected $persisted;
2726
protected $rootView;
2827
protected $version;
2928
protected $viewData = [];
3029

3130
/**
3231
* @param array|Arrayable $props
3332
*/
34-
public function __construct(string $component, array $props, string $rootView = 'app', string $version = '', array $persisted = [])
33+
public function __construct(string $component, array $props, string $rootView = 'app', string $version = '')
3534
{
3635
$this->component = $component;
3736
$this->props = $props instanceof Arrayable ? $props->toArray() : $props;
38-
$this->persisted = $persisted;
3937
$this->rootView = $rootView;
4038
$this->version = $version;
4139
}
@@ -129,6 +127,8 @@ public function resolveProperties(Request $request, array $props): array
129127
$props = $this->resolveExcept($request, $props);
130128
}
131129

130+
$props = $this->resolveAlways($props);
131+
132132
$props = $this->resolvePropertyInstances($props, $request);
133133

134134
return $props;
@@ -164,10 +164,7 @@ public function resolveArrayableProperties(array $props, Request $request, bool
164164
*/
165165
public function resolveOnly(Request $request, array $props): array
166166
{
167-
$only = array_merge(
168-
array_filter(explode(',', $request->header(Header::PARTIAL_ONLY, ''))),
169-
$this->persisted
170-
);
167+
$only = array_filter(explode(',', $request->header(Header::PARTIAL_ONLY, '')));
171168

172169
$value = [];
173170

@@ -190,6 +187,21 @@ public function resolveExcept(Request $request, array $props): array
190187
return $props;
191188
}
192189

190+
/**
191+
* Resolve `always` properties that should always be included on all visits, regardless of "only" or "except" requests.
192+
*/
193+
public function resolveAlways(array $props): array
194+
{
195+
$always = array_filter($this->props, static function ($prop) {
196+
return $prop instanceof AlwaysProp;
197+
});
198+
199+
return array_merge(
200+
$always,
201+
$props
202+
);
203+
}
204+
193205
/**
194206
* Resolve all necessary class instances in the given props.
195207
*/
@@ -204,6 +216,10 @@ public function resolvePropertyInstances(array $props, Request $request): array
204216
$value = App::call($value);
205217
}
206218

219+
if ($value instanceof AlwaysProp) {
220+
$value = App::call($value);
221+
}
222+
207223
if ($value instanceof PromiseInterface) {
208224
$value = $value->wait();
209225
}

src/ResponseFactory.php

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ class ResponseFactory
2424
/** @var array */
2525
protected $sharedProps = [];
2626

27-
/** @var array */
28-
protected $persisted = [];
29-
3027
/** @var Closure|string|null */
3128
protected $version;
3229

@@ -69,30 +66,6 @@ public function flushShared(): void
6966
$this->sharedProps = [];
7067
}
7168

72-
/**
73-
* @param string|array|Arrayable $props
74-
*/
75-
public function persist($props): void
76-
{
77-
if (is_array($props)) {
78-
$this->persisted = array_merge($this->persisted, $props);
79-
} elseif ($props instanceof Arrayable) {
80-
$this->persisted = array_merge($this->persisted, $props->toArray());
81-
} else {
82-
$this->persisted[] = $props;
83-
}
84-
}
85-
86-
public function getPersisted(): array
87-
{
88-
return $this->persisted;
89-
}
90-
91-
public function flushPersisted(): void
92-
{
93-
$this->persisted = [];
94-
}
95-
9669
/**
9770
* @param Closure|string|null $version
9871
*/
@@ -115,6 +88,14 @@ public function lazy(callable $callback): LazyProp
11588
return new LazyProp($callback);
11689
}
11790

91+
/**
92+
* @param mixed $value
93+
*/
94+
public function always($value): AlwaysProp
95+
{
96+
return new AlwaysProp($value);
97+
}
98+
11899
/**
119100
* @param array|Arrayable $props
120101
*/
@@ -128,8 +109,7 @@ public function render(string $component, $props = []): Response
128109
$component,
129110
array_merge($this->sharedProps, $props),
130111
$this->rootView,
131-
$this->getVersion(),
132-
$this->persisted
112+
$this->getVersion()
133113
);
134114
}
135115

tests/AlwaysPropTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Inertia\Tests;
4+
5+
use Illuminate\Http\Request;
6+
use Inertia\AlwaysProp;
7+
8+
class AlwaysPropTest extends TestCase
9+
{
10+
public function test_can_invoke(): void
11+
{
12+
$alwaysProp = new AlwaysProp(function () {
13+
return 'An always value';
14+
});
15+
16+
$this->assertSame('An always value', $alwaysProp());
17+
}
18+
19+
public function test_can_accept_scalar_values(): void
20+
{
21+
$alwaysProp = new AlwaysProp('An always value');
22+
23+
$this->assertSame('An always value', $alwaysProp());
24+
}
25+
26+
public function test_can_accept_callables(): void
27+
{
28+
$callable = new class {
29+
public function __invoke() {
30+
return 'An always value';
31+
}
32+
};
33+
34+
$alwaysProp = new AlwaysProp($callable);
35+
36+
$this->assertSame('An always value', $alwaysProp());
37+
}
38+
39+
public function test_can_resolve_bindings_when_invoked(): void
40+
{
41+
$alwaysProp = new AlwaysProp(function (Request $request) {
42+
return $request;
43+
});
44+
45+
$this->assertInstanceOf(Request::class, $alwaysProp());
46+
}
47+
}

tests/MiddlewareTest.php

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace Inertia\Tests;
44

5-
use Closure;
65
use LogicException;
76
use Inertia\Inertia;
87
use Inertia\Middleware;
@@ -13,6 +12,7 @@
1312
use Illuminate\Support\Facades\Session;
1413
use Inertia\Tests\Stubs\ExampleMiddleware;
1514
use Illuminate\Session\Middleware\StartSession;
15+
use Inertia\AlwaysProp;
1616

1717
class MiddlewareTest extends TestCase
1818
{
@@ -125,7 +125,7 @@ public function test_it_will_instruct_inertia_to_reload_on_a_version_mismatch():
125125
public function test_validation_errors_are_registered_as_of_default(): void
126126
{
127127
Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () {
128-
$this->assertInstanceOf(Closure::class, Inertia::getShared('errors'));
128+
$this->assertInstanceOf(AlwaysProp::class, Inertia::getShared('errors'));
129129
});
130130

131131
$this->withoutExceptionHandling()->get('/');
@@ -239,39 +239,10 @@ public function rootView(Request $request): string
239239
$response->assertViewIs('welcome');
240240
}
241241

242-
public function test_middleware_can_set_persisted_properties(): void
243-
{
244-
$shared = [
245-
'shared' => [
246-
'flash' => 'The user has been updated.'
247-
]
248-
];
249-
250-
$this->prepareMockEndpoint(null, $shared, null, ['shared']);
251-
252-
$response = $this->get('/', [
253-
'X-Inertia' => 'true',
254-
'X-Inertia-Partial-Component' => 'User/Edit',
255-
'X-Inertia-Partial-Data' => 'user'
256-
]);
257-
258-
$response->assertOk();
259-
$response->assertJson([
260-
'props' => [
261-
'shared' => [
262-
'flash' => 'The user has been updated.'
263-
],
264-
'user' => [
265-
'name' => 'Jonathan',
266-
]
267-
]
268-
]);
269-
}
270-
271-
private function prepareMockEndpoint($version = null, $shared = [], $middleware = null, $persisted = []): \Illuminate\Routing\Route
242+
private function prepareMockEndpoint($version = null, $shared = [], $middleware = null): \Illuminate\Routing\Route
272243
{
273244
if (is_null($middleware)) {
274-
$middleware = new ExampleMiddleware($version, $shared, $persisted);
245+
$middleware = new ExampleMiddleware($version, $shared);
275246
}
276247

277248
return Route::middleware(StartSession::class)->get('/', function (Request $request) use ($middleware) {

tests/ResponseFactoryTest.php

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Illuminate\Session\Middleware\StartSession;
1616
use Illuminate\Session\NullSessionHandler;
1717
use Illuminate\Session\Store;
18+
use Inertia\AlwaysProp;
1819

1920
class ResponseFactoryTest extends TestCase
2021
{
@@ -150,22 +151,6 @@ public function test_can_flush_shared_data(): void
150151
$this->assertSame([], Inertia::getShared());
151152
}
152153

153-
public function test_can_persist_properties(): void
154-
{
155-
Inertia::persist('auth.user');
156-
$this->assertSame(['auth.user'], Inertia::getPersisted());
157-
Inertia::persist(['posts']);
158-
$this->assertSame(['auth.user', 'posts'], Inertia::getPersisted());
159-
}
160-
161-
public function test_can_flush_persisted_data(): void
162-
{
163-
Inertia::persist('auth.user');
164-
$this->assertSame(['auth.user'], Inertia::getPersisted());
165-
Inertia::flushPersisted();
166-
$this->assertSame([], Inertia::getPersisted());
167-
}
168-
169154
public function test_can_create_lazy_prop(): void
170155
{
171156
$factory = new ResponseFactory();
@@ -176,6 +161,16 @@ public function test_can_create_lazy_prop(): void
176161
$this->assertInstanceOf(LazyProp::class, $lazyProp);
177162
}
178163

164+
public function test_can_create_always_prop(): void
165+
{
166+
$factory = new ResponseFactory();
167+
$alwaysProp = $factory->always(function () {
168+
return 'An always value';
169+
});
170+
171+
$this->assertInstanceOf(AlwaysProp::class, $alwaysProp);
172+
}
173+
179174
public function test_will_accept_arrayabe_props()
180175
{
181176
Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () {

0 commit comments

Comments
 (0)