Skip to content

Commit 60d69d0

Browse files
refactor: page data (#13)
1 parent 7b239f2 commit 60d69d0

File tree

14 files changed

+187
-82
lines changed

14 files changed

+187
-82
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ If you use the default config, a view called `app.view.php` is required. That vi
4444
(think of this like laravels `@inertia` directive)
4545

4646
```php
47-
<?= $this->renderInertiaElement(id: 'app') ?>
47+
<?= $this->page->render(id: 'app') ?>
4848
```
4949

5050
#### Frontend

mago.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ excludes = [
1414
print_width = 120
1515
tab_width = 4
1616
use_tabs = false
17+
null_type_hint = "Question"
1718

1819
[linter]
1920
default_plugins = true
@@ -62,4 +63,4 @@ level = "off"
6263

6364
[[linter.rules]]
6465
name = "maintainability/cyclomatic-complexity"
65-
level = "off"
66+
level = "off"

src/Http/InertiaResponse.php

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Closure;
88
use NeoIsRecursive\Inertia\Contracts\CallableProp;
99
use NeoIsRecursive\Inertia\Contracts\MergeableProp;
10+
use NeoIsRecursive\Inertia\PageData;
1011
use NeoIsRecursive\Inertia\Props\AlwaysProp;
1112
use NeoIsRecursive\Inertia\Props\DeferProp;
1213
use NeoIsRecursive\Inertia\Props\LazyProp;
@@ -34,45 +35,38 @@ public function __construct(
3435
readonly bool $clearHistory = false,
3536
readonly bool $encryptHistory = false,
3637
) {
37-
$deferredProps = self::resolvePropKeysThatShouldDefer(
38-
props: $props,
39-
request: $request,
38+
$pageData = new PageData(
4039
component: $component,
41-
);
42-
43-
$mergeProps = self::resolvePropKeysThatShouldMerge(
44-
props: $props,
45-
request: $request,
46-
);
47-
48-
// Build page data immutably
49-
$pageData = array_merge(
50-
[
51-
'component' => $component,
52-
'props' => self::composeProps(
53-
props: $props,
54-
request: $request,
55-
component: $component,
56-
),
57-
'url' => $request->uri,
58-
'version' => $version,
59-
'clearHistory' => $clearHistory,
60-
'encryptHistory' => $encryptHistory,
61-
],
62-
count($deferredProps) ? ['deferredProps' => $deferredProps] : [],
63-
count($mergeProps) ? ['mergeProps' => $mergeProps] : [],
40+
props: self::composeProps(
41+
props: $props,
42+
request: $request,
43+
component: $component,
44+
),
45+
url: $request->uri,
46+
version: $version,
47+
clearHistory: $clearHistory,
48+
encryptHistory: $encryptHistory,
49+
propKeysToDefer: self::resolvePropKeysThatShouldDefer(
50+
props: $props,
51+
request: $request,
52+
component: $component,
53+
),
54+
propsKeysToMerge: self::resolvePropKeysThatShouldMerge(
55+
props: $props,
56+
request: $request,
57+
),
6458
);
6559

6660
$this->body = $request->headers->has(Header::INERTIA)
6761
? (function () use ($pageData) {
6862
// side effect to set Inertia header
6963
$this->addHeader(Header::INERTIA, value: 'true');
7064

71-
return $pageData;
65+
return $pageData->toArray();
7266
})()
7367
: new InertiaBaseView(
74-
view: $rootView,
75-
pageData: $pageData,
68+
path: $rootView,
69+
page: $pageData,
7670
);
7771
}
7872

@@ -128,36 +122,37 @@ private static function resolvePartialProps(Request $request, string $component,
128122
return array_filter($filtered, static fn($key) => !in_array($key, $except, strict: true), ARRAY_FILTER_USE_KEY);
129123
}
130124

131-
private static function resolvePropKeysThatShouldDefer(array $props, Request $request, string $component): array
125+
private static function resolvePropKeysThatShouldDefer(array $props, Request $request, string $component): ?array
132126
{
133127
if (static::isPartial($request, $component)) {
134-
return [];
128+
return null;
135129
}
136130

137-
return arr($props)
138-
->filter(function ($prop) {
139-
return $prop instanceof DeferProp;
140-
})
141-
->map(fn(DeferProp $prop, string $key) => [
131+
$propKeysToMerge = arr($props)
132+
->filter(static fn($prop) => $prop instanceof DeferProp)
133+
->map(static fn(DeferProp $prop, string $key) => [
142134
'group' => $prop->group,
143135
'key' => $key,
144136
])
145-
->groupBy(fn(array $prop) => $prop['group'])
146-
->map(fn(array $group) => arr($group)->pluck(value: 'key')->toArray())
147-
->toArray();
137+
->groupBy(static fn(array $prop) => $prop['group'])
138+
->map(static fn(array $group) => arr($group)->pluck(value: 'key')->toArray());
139+
140+
return $propKeysToMerge->isEmpty() ? null : $propKeysToMerge->toArray();
148141
}
149142

150-
private static function resolvePropKeysThatShouldMerge(array $props, Request $request): array
143+
private static function resolvePropKeysThatShouldMerge(array $props, Request $request): ?array
151144
{
152145
$resetProps = arr(explode(
153146
separator: ',',
154147
string: $request->headers->get(Header::RESET) ?? '',
155148
));
156-
return arr($props)
149+
150+
$propKeysToMerge = arr($props)
157151
->filter(fn($prop) => $prop instanceof MergeableProp && $prop->shouldMerge)
158152
->filter(fn($_, $key) => !$resetProps->contains($key))
159-
->keys()
160-
->toArray();
153+
->keys();
154+
155+
return $propKeysToMerge->isEmpty() ? null : $propKeysToMerge->toArray();
161156
}
162157

163158
/**

src/Http/Middleware.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ public function __invoke(Request $request, HttpMiddlewareCallable $next): Respon
3737
return $response;
3838
}
3939

40-
$versionHeaderValue = $request->headers->get(Header::VERSION) ?? '';
40+
$clientVersion = $request->headers->get(Header::VERSION) ?? '';
4141

42-
if ($request->method === Method::GET && $versionHeaderValue !== $this->inertia->version) {
42+
if ($request->method === Method::GET && $clientVersion !== $this->inertia->version) {
4343
$this->session->reflash();
4444

4545
return $this->inertia->location($request->uri);

src/Installer/app.view.stub

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<?php /** @var NeoIsRecursive\Inertia\Views\InertiaBaseView $this */ ?>
2+
13
<!DOCTYPE html>
24
<html lang="en">
35

@@ -9,7 +11,7 @@
911
</head>
1012

1113
<body>
12-
<?= $this->renderInertiaElement(id: 'app'); ?>
14+
<?= $this->page->render(id: 'app'); ?>
1315
</body>
1416

1517
</html>

src/ManifestVersionResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
final readonly class ManifestVersionResolver implements InertiaVersionResolver
1313
{
1414
public function __construct(
15-
public null|string $manifestPath = null,
15+
public ?string $manifestPath = null,
1616
) {}
1717

1818
public function resolve(Container $container): string

src/PageData.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NeoIsRecursive\Inertia;
6+
7+
use JsonSerializable;
8+
use Tempest\Support\Html\HtmlString;
9+
10+
final readonly class PageData implements JsonSerializable
11+
{
12+
// @mago-expect maintainability/excessive-parameter-list
13+
public function __construct(
14+
public string $component,
15+
public array $props,
16+
public string $url,
17+
public string $version,
18+
public bool $clearHistory,
19+
public bool $encryptHistory,
20+
public ?array $propKeysToDefer = null,
21+
public ?array $propsKeysToMerge = null,
22+
) {}
23+
24+
public function toArray(): array
25+
{
26+
$data = [
27+
'component' => $this->component,
28+
'props' => $this->props,
29+
'url' => $this->url,
30+
'version' => $this->version,
31+
'clearHistory' => $this->clearHistory,
32+
'encryptHistory' => $this->encryptHistory,
33+
];
34+
35+
if ($this->propKeysToDefer !== null) {
36+
$data['deferredProps'] = $this->propKeysToDefer;
37+
}
38+
39+
if ($this->propsKeysToMerge !== null) {
40+
$data['mergeProps'] = $this->propsKeysToMerge;
41+
}
42+
43+
return $data;
44+
}
45+
46+
public function jsonSerialize(): array
47+
{
48+
return $this->toArray();
49+
}
50+
51+
public function render(string $id): HtmlString
52+
{
53+
return HtmlString::createTag(
54+
tag: 'div',
55+
attributes: [
56+
'id' => $id,
57+
'data-page' => htmlentities(json_encode($this, JSON_THROW_ON_ERROR)),
58+
],
59+
);
60+
}
61+
}

src/Views/InertiaBaseView.php

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace NeoIsRecursive\Inertia\Views;
66

7+
use NeoIsRecursive\Inertia\PageData;
78
use Tempest\View\IsView;
89
use Tempest\View\View;
910

@@ -12,20 +13,7 @@ final class InertiaBaseView implements View
1213
use IsView;
1314

1415
public function __construct(
15-
private string $view,
16-
private array $pageData,
17-
) {
18-
$this->path = $view;
19-
}
20-
21-
public function renderInertiaElement(string $id): string
22-
{
23-
$pageData = htmlentities(json_encode($this->pageData));
24-
25-
$template = <<<HTML
26-
<div id="{$id}" data-page="{$pageData}"></div>
27-
HTML;
28-
29-
return $template;
30-
}
16+
public string $path,
17+
public PageData $page,
18+
) {}
3119
}

src/functions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
/**
1212
* @return ($component is null ? Inertia : InertiaResponse)
1313
*/
14-
function inertia(string|null $component = null, array $props = []): InertiaResponse|Inertia
14+
function inertia(?string $component = null, array $props = []): InertiaResponse|Inertia
1515
{
1616
if ($component === null) {
1717
return get(Inertia::class);

tests/Fixtures/TestController.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use NeoIsRecursive\Inertia\Http\Middleware\EncryptHistory;
99
use NeoIsRecursive\Inertia\Inertia;
1010
use NeoIsRecursive\Inertia\Props\AlwaysProp;
11+
use NeoIsRecursive\Inertia\Props\LazyProp;
1112
use Tempest\Http\Responses\Ok;
1213
use Tempest\Http\Responses\Redirect;
1314
use Tempest\Router\Get;
@@ -105,4 +106,16 @@ public function testPutWithRedirect(): Redirect
105106
{
106107
return new Redirect(to: uri([static::class, 'index']));
107108
}
109+
110+
#[Get(uri: '/test-can-merge-props')]
111+
public function testCanMergeProps(Inertia $inertia): InertiaResponse
112+
{
113+
return $inertia->render(
114+
component: 'test',
115+
props: [
116+
'foo' => new AlwaysProp(fn() => 'bar')->merge(),
117+
'baz' => new LazyProp(fn() => 'qux')->merge(),
118+
],
119+
);
120+
}
108121
}

0 commit comments

Comments
 (0)