Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions src/Http/InertiaResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,31 @@
use Tempest\Http\IsResponse;
use Tempest\Http\Request;
use Tempest\Http\Response;
use Tempest\Support\Arr\ImmutableArray;
use Tempest\Http\Session\Session;
use Tempest\Support\Arr\ArrayInterface;

use function Tempest\get;
use function Tempest\invoke;
use function Tempest\Support\arr;
use function Tempest\Support\str;

final class InertiaResponse implements Response
{
use IsResponse;

// @mago-expect maintainability/excessive-parameter-list
public function __construct(
readonly Request $request,
readonly string $page,
readonly string $component,
readonly array $props,
readonly string $rootView,
readonly string $version,
readonly bool $clearHistory = false,
readonly bool $encryptHistory = false,
) {
$deferredProps = self::resolvePropKeysThatShouldDefer(
props: $props,
request: $request,
component: $page,
component: $component,
);

$mergeProps = self::resolvePropKeysThatShouldMerge(
Expand All @@ -45,14 +49,16 @@ public function __construct(
// Build page data immutably
$pageData = array_merge(
[
'component' => $page,
'component' => $component,
'props' => self::composeProps(
props: $this->props,
request: $this->request,
component: $page,
props: $props,
request: $request,
component: $component,
),
'url' => $request->uri,
'version' => $version,
'clearHistory' => $clearHistory,
'encryptHistory' => $encryptHistory,
],
count($deferredProps) ? ['deferredProps' => $deferredProps] : [],
count($mergeProps) ? ['mergeProps' => $mergeProps] : [],
Expand Down Expand Up @@ -168,7 +174,7 @@ private static function evaluateProps(array $props, Request $request, bool $unpa
$evaluated = ($value instanceof Closure) ? invoke($value) : $value;
$evaluated =
$evaluated instanceof LazyProp || $evaluated instanceof AlwaysProp ? $evaluated() : $evaluated;
$evaluated = ($evaluated instanceof ImmutableArray) ? $evaluated->toArray() : $evaluated;
$evaluated = ($evaluated instanceof ArrayInterface) ? $evaluated->toArray() : $evaluated;
$evaluated = is_array($evaluated)
? self::evaluateProps($evaluated, $request, unpackDotProps: false)
: $evaluated;
Expand Down
27 changes: 27 additions & 0 deletions src/Http/Middleware/EncryptHistory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace NeoIsRecursive\Inertia\Http\Middleware;

use NeoIsRecursive\Inertia\Inertia;
use Tempest\Discovery\SkipDiscovery;
use Tempest\Http\Request;
use Tempest\Http\Response;
use Tempest\Router\HttpMiddleware;
use Tempest\Router\HttpMiddlewareCallable;

#[SkipDiscovery]
final readonly class EncryptHistory implements HttpMiddleware
{
public function __construct(
private Inertia $inertia,
) {}

public function __invoke(Request $request, HttpMiddlewareCallable $next): Response
{
$this->inertia->encryptHistory();

return $next($request);
}
}
42 changes: 38 additions & 4 deletions src/Inertia.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,73 @@
use Tempest\Http\Request;
use Tempest\Http\Response;
use Tempest\Http\Responses\Redirect;
use Tempest\Http\Session\Session;
use Tempest\Http\Status;

#[Singleton]
final class Inertia
{
public function __construct(
private Session $session,
private Container $container,
private InertiaConfig $config,
) {}

public function share(string|array $key, null|string $value = null): void
public function share(string|array $key, null|string $value = null): self
{
$this->config->share($key, $value);

return $this;
}

public function flushShared(): void
public function flushShared(): self
{
$this->config->flushSharedProps();

return $this;
}

public string $version {
get => $this->container->invoke($this->config->versionResolver->resolve(...));
}

public function render(string $page, array $props = []): InertiaResponse
public function render(string $component, array $props = []): InertiaResponse
{
return new InertiaResponse(
request: $this->container->get(Request::class),
page: $page,
component: $component,
props: array_merge($this->config->sharedProps, $props),
rootView: $this->config->rootView,
version: $this->version,
clearHistory: $this->session->get(
key: 'inertia.clear_history',
default: false,
),
encryptHistory: $this->session->get(
key: 'inertia.encrypt_history',
default: false,
),
);
}

public function encryptHistory(): self
{
$this->session->flash(
key: 'inertia.encrypt_history',
value: true,
);

return $this;
}

public function clearHistory(): self
{
$this->session->flash(
key: 'inertia.clear_history',
value: true,
);

return $this;
}

public function location(string|Redirect $url): Response
Expand Down
6 changes: 3 additions & 3 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
/**
* @return ($component is null ? Inertia : InertiaResponse)
*/
function inertia(string|null $page = null, array $props = []): InertiaResponse|Inertia
function inertia(string|null $component = null, array $props = []): InertiaResponse|Inertia
{
if ($page === null) {
if ($component === null) {
return get(Inertia::class);
}

return get(Inertia::class)->render($page, $props);
return get(Inertia::class)->render($component, $props);
}
}
66 changes: 51 additions & 15 deletions tests/Fixtures/TestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,83 @@
namespace NeoIsRecursive\Inertia\Tests\Fixtures;

use NeoIsRecursive\Inertia\Http\InertiaResponse;
use NeoIsRecursive\Inertia\Http\Middleware\EncryptHistory;
use NeoIsRecursive\Inertia\Inertia;
use NeoIsRecursive\Inertia\Props\AlwaysProp;
use Tempest\Http\Responses\Ok;
use Tempest\Http\Responses\Redirect;
use Tempest\Http\Session\Session;
use Tempest\Router\Get;

use function NeoIsRecursive\Inertia\inertia;
use function Tempest\uri;

final readonly class TestController
{
public function index(): InertiaResponse
{
return inertia(page: 'Index');
return inertia(component: 'Index');
}

#[Get(uri: '/non-inertia-page')]
public function nonInertiaPage(): Ok
{
return new Ok(body: [
'message' => 'This is a non-Inertia page.',
]);
}

#[Get(uri: '/can-share-props-from-any-where')]
public function testCanSharePropsFromAnyWhere(Inertia $inertia): InertiaResponse
{
$inertia->share(
key: 'foo',
value: 'bar',
);

$inertia->share([
'baz' => 'qux',
]);
$inertia
->share(
key: 'foo',
value: 'bar',
)
->share([
'baz' => 'qux',
]);

return inertia(page: 'User/Edit');
return inertia(component: 'User/Edit');
}

#[Get(uri: '/all-sorts-of-props')]
public function testAllSortsOfProps(Inertia $inertia): InertiaResponse
{
$inertia->share(
return $inertia->share(
key: 'foo',
value: 'bar',
);

return inertia(
page: 'User/Edit',
)->render(
component: 'User/Edit',
props: [
new AlwaysProp(fn() => 'baz'),
],
);
}

#[Get(uri: '/encrypted-history')]
public function testEncryptedHistory(Inertia $inertia): InertiaResponse
{
return $inertia->encryptHistory()->render(component: 'User/Edit');
}

#[Get(uri: '/encrypted-history-middleware', middleware: [EncryptHistory::class])]
public function testEncryptedHistoryWithMiddleware(Inertia $inertia): InertiaResponse
{
return $inertia->render(component: 'User/Edit');
}

#[Get(uri: '/cleared-history')]
public function testClearedHistory(Inertia $inertia): InertiaResponse
{
return $inertia->clearHistory()->render(component: 'User/Edit');
}

#[Get(uri: '/redirect-with-clear-history')]
public function testRedirectWithClearHistory(Inertia $inertia): Redirect
{
$inertia->clearHistory();
return new Redirect(to: uri([self::class, 'testCanSharePropsFromAnyWhere']));
}
}
2 changes: 1 addition & 1 deletion tests/Integration/HelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function test_the_helper_function_returns_an_instance_of_the_response_fac
public function test_the_helper_function_returns_a_response_instance(): void
{
static::assertInstanceOf(Response::class, inertia(
page: 'User/Edit',
component: 'User/Edit',
props: ['user' => ['name' => 'Jonathan']],
));
}
Expand Down
Loading