Skip to content

Commit

Permalink
[1.x] Persistent properties (#621)
Browse files Browse the repository at this point in the history
* add persistent properties

* persist properties in middleware

* formatting

---------

Co-authored-by: Taylor Otwell <taylor@laravel.com>
  • Loading branch information
lepikhinb and taylorotwell committed May 17, 2024
1 parent e05a8bd commit 27fb7e8
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 6 deletions.
3 changes: 3 additions & 0 deletions src/Inertia.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
* @method static void mixin(object $mixin, bool $replace = true)
* @method static bool hasMacro(string $name)
* @method static void flushMacros()
* @method static void persist(string|array|\Illuminate\Contracts\Support\Arrayable $props)
* @method static array getPersisted()
* @method static void flushPersisted()
*
* @see \Inertia\ResponseFactory
*/
Expand Down
8 changes: 8 additions & 0 deletions src/Middleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ class Middleware
*/
protected $rootView = 'app';

/**
* The properties that should always be included on Inertia responses, regardless of "only" or "except" requests.
*
* @var array
*/
protected $persisted = [];

/**
* Determines the current asset version.
*
Expand Down Expand Up @@ -83,6 +90,7 @@ public function handle(Request $request, Closure $next)
});

Inertia::share($this->share($request));
Inertia::persist($this->persisted);
Inertia::setRootView($this->rootView($request));

$response = $next($request);
Expand Down
9 changes: 7 additions & 2 deletions src/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,19 @@ class Response implements Responsable

protected $component;
protected $props;
protected $persisted;
protected $rootView;
protected $version;
protected $viewData = [];

/**
* @param array|Arrayable $props
*/
public function __construct(string $component, $props, string $rootView = 'app', string $version = '')
public function __construct(string $component, array $props, string $rootView = 'app', string $version = '', array $persisted = [])
{
$this->component = $component;
$this->props = $props instanceof Arrayable ? $props->toArray() : $props;
$this->persisted = $persisted;
$this->rootView = $rootView;
$this->version = $version;
}
Expand Down Expand Up @@ -158,7 +160,10 @@ public function resolveArrayableProperties(array $props, Request $request, bool
*/
public function resolveOnly(Request $request, array $props): array
{
$only = array_filter(explode(',', $request->header(Header::PARTIAL_ONLY, '')));
$only = array_merge(
array_filter(explode(',', $request->header(Header::PARTIAL_ONLY, ''))),
$this->persisted
);

$value = [];

Expand Down
30 changes: 29 additions & 1 deletion src/ResponseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class ResponseFactory
/** @var array */
protected $sharedProps = [];

/** @var array */
protected $persisted = [];

/** @var Closure|string|null */
protected $version;

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

/**
* @param string|array|Arrayable $props
*/
public function persist($props): void
{
if (is_array($props)) {
$this->persisted = array_merge($this->persisted, $props);
} elseif ($props instanceof Arrayable) {
$this->persisted = array_merge($this->persisted, $props->toArray());
} else {
$this->persisted[] = $props;
}
}

public function getPersisted(): array
{
return $this->persisted;
}

public function flushPersisted(): void
{
$this->persisted = [];
}

/**
* @param Closure|string|null $version
*/
Expand Down Expand Up @@ -101,7 +128,8 @@ public function render(string $component, $props = []): Response
$component,
array_merge($this->sharedProps, $props),
$this->rootView,
$this->getVersion()
$this->getVersion(),
$this->persisted
);
}

Expand Down
33 changes: 31 additions & 2 deletions tests/MiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,39 @@ public function rootView(Request $request): string
$response->assertViewIs('welcome');
}

private function prepareMockEndpoint($version = null, $shared = [], $middleware = null): \Illuminate\Routing\Route
public function test_middleware_can_set_persisted_properties(): void
{
$shared = [
'shared' => [
'flash' => 'The user has been updated.'
]
];

$this->prepareMockEndpoint(null, $shared, null, ['shared']);

$response = $this->get('/', [
'X-Inertia' => 'true',
'X-Inertia-Partial-Component' => 'User/Edit',
'X-Inertia-Partial-Data' => 'user'
]);

$response->assertOk();
$response->assertJson([
'props' => [
'shared' => [
'flash' => 'The user has been updated.'
],
'user' => [
'name' => 'Jonathan',
]
]
]);
}

private function prepareMockEndpoint($version = null, $shared = [], $middleware = null, $persisted = []): \Illuminate\Routing\Route
{
if (is_null($middleware)) {
$middleware = new ExampleMiddleware($version, $shared);
$middleware = new ExampleMiddleware($version, $shared, $persisted);
}

return Route::middleware(StartSession::class)->get('/', function (Request $request) use ($middleware) {
Expand Down
16 changes: 16 additions & 0 deletions tests/ResponseFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,22 @@ public function test_can_flush_shared_data(): void
$this->assertSame([], Inertia::getShared());
}

public function test_can_persist_properties(): void
{
Inertia::persist('auth.user');
$this->assertSame(['auth.user'], Inertia::getPersisted());
Inertia::persist(['posts']);
$this->assertSame(['auth.user', 'posts'], Inertia::getPersisted());
}

public function test_can_flush_persisted_data(): void
{
Inertia::persist('auth.user');
$this->assertSame(['auth.user'], Inertia::getPersisted());
Inertia::flushPersisted();
$this->assertSame([], Inertia::getPersisted());
}

public function test_can_create_lazy_prop(): void
{
$factory = new ResponseFactory();
Expand Down
34 changes: 34 additions & 0 deletions tests/ResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,40 @@ public function test_lazy_props_are_included_in_partial_reload(): void
$this->assertSame('A lazy value', $page->props->lazy);
}

public function test_persist_props_on_partial_reload(): void
{
$request = Request::create('/user/123', 'GET');
$request->headers->add(['X-Inertia' => 'true']);
$request->headers->add(['X-Inertia-Partial-Component' => 'User/Edit']);
$request->headers->add(['X-Inertia-Partial-Data' => 'data']);

$props = [
'auth' => [
'user' => new LazyProp(function () {
return [
'name' => 'Jonathan Reinink',
'email' => 'jonathan@example.com',
];
}),
'token' => 'value',
],
'data' => [
'name' => 'Taylor Otwell',
'email' => 'taylor@example.com',
]
];

$response = new Response('User/Edit', $props, 'app', '123', ['auth.user']);
$response = $response->toResponse($request);
$page = $response->getData();

$this->assertFalse(isset($page->props->auth->token));
$this->assertSame('Jonathan Reinink', $page->props->auth->user->name);
$this->assertSame('jonathan@example.com', $page->props->auth->user->email);
$this->assertSame('Taylor Otwell', $page->props->data->name);
$this->assertSame('taylor@example.com', $page->props->data->email);
}

public function test_top_level_dot_props_get_unpacked(): void
{
$props = [
Expand Down
8 changes: 7 additions & 1 deletion tests/Stubs/ExampleMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@ class ExampleMiddleware extends Middleware
*/
protected $shared = [];

public function __construct($version = null, $shared = [])
/**
* @var array
*/
protected $persisted = [];

public function __construct($version = null, $shared = [], $persisted = [])
{
$this->version = $version;
$this->shared = $shared;
$this->persisted = $persisted;
}

/**
Expand Down

0 comments on commit 27fb7e8

Please sign in to comment.