Skip to content
Closed
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
8 changes: 8 additions & 0 deletions src/FirstLoad.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Inertia;

interface FirstLoad
{
//
}
20 changes: 20 additions & 0 deletions src/InitialProp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Inertia;

use Illuminate\Support\Facades\App;

class InitialProp implements FirstLoad
{
protected $callback;

Check failure on line 9 in src/InitialProp.php

View workflow job for this annotation

GitHub Actions / tests / Static Analysis

Property Inertia\InitialProp::$callback has no type specified.

public function __construct(callable $callback)
{
$this->callback = $callback;
}

public function __invoke()

Check failure on line 16 in src/InitialProp.php

View workflow job for this annotation

GitHub Actions / tests / Static Analysis

Method Inertia\InitialProp::__invoke() has no return type specified.
{
return App::call($this->callback);
}
}
25 changes: 24 additions & 1 deletion src/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
string $rootView = 'app',
string $version = '',
bool $encryptHistory = false,
?Closure $urlResolver = null
?Closure $urlResolver = null,
) {
$this->component = $component;
$this->props = $props;
Expand Down Expand Up @@ -188,6 +188,7 @@
$this->resolveMergeProps($request),
$this->resolveDeferredProps($request),
$this->resolveCacheDirections($request),
$this->resolveInitialProps($request),
);

if ($request->header(Header::INERTIA)) {
Expand All @@ -207,6 +208,7 @@
{
$props = $this->resolveInertiaPropsProviders($props, $request);
$props = $this->resolvePartialProperties($props, $request);
$props = $this->filterInitialProps($props);
$props = $this->resolveArrayableProperties($props, $request);
$props = $this->resolveAlways($props);
$props = $this->resolvePropertyInstances($props, $request);
Expand Down Expand Up @@ -416,6 +418,14 @@
return $props;
}

/**
* Filter initial properties from the props.
*/
public function filterInitialProps(array $props): array

Check failure on line 424 in src/Response.php

View workflow job for this annotation

GitHub Actions / tests / Static Analysis

Method Inertia\Response::filterInitialProps() return type has no value type specified in iterable type array.

Check failure on line 424 in src/Response.php

View workflow job for this annotation

GitHub Actions / tests / Static Analysis

Method Inertia\Response::filterInitialProps() has parameter $props with no value type specified in iterable type array.
{
return array_filter($props, static fn ($prop) => ! $prop instanceof InitialProp);
}

/**
* Resolve the cache directions for the response.
*
Expand Down Expand Up @@ -508,6 +518,19 @@
return $deferredProps->isNotEmpty() ? ['deferredProps' => $deferredProps->toArray()] : [];
}

public function resolveInitialProps(Request $request): array

Check failure on line 521 in src/Response.php

View workflow job for this annotation

GitHub Actions / tests / Static Analysis

Method Inertia\Response::resolveInitialProps() return type has no value type specified in iterable type array.
{
if ($request->header(Header::INERTIA)) {
return [];
}

$initialProps = collect($this->props)
->filter(fn ($prop) => $prop instanceof InitialProp)
->mapWithKeys(fn ($value, $key) => [$key => App::call($value)]);

return $initialProps->isNotEmpty() ? ['initialProps' => $initialProps->toArray()] : [];
}

/**
* Determine if the request is a partial request.
*/
Expand Down
8 changes: 8 additions & 0 deletions src/ResponseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,14 @@ public function optional(callable $callback): OptionalProp
return new OptionalProp($callback);
}

/**
* Create a initial property.
*/
public function initial(callable $callback): InitialProp
{
return new InitialProp($callback);
}

/**
* Create a deferred property.
*/
Expand Down
73 changes: 73 additions & 0 deletions tests/InitialPropTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Inertia\Tests;

use Illuminate\Http\Request;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use Inertia\InitialProp;
use Inertia\Tests\Stubs\ExampleMiddleware;

class InitialPropTest extends TestCase
{
public function test_initial_props_accessibility()

Check failure on line 14 in tests/InitialPropTest.php

View workflow job for this annotation

GitHub Actions / tests / Static Analysis

Method Inertia\Tests\InitialPropTest::test_initial_props_accessibility() has no return type specified.
{
Inertia::share([
'initial' => Inertia::initial(fn () => true),
'appName' => Inertia::initial(fn () => 'test'),
]);

$this->prepareMockEndpoint();

$response = $this->withoutExceptionHandling()->get('/');

$response->assertSuccessful();
$this->assertSame(
'<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>',
$response->content(),
);
}

public function test_initial_props_are_not_accessible()

Check failure on line 32 in tests/InitialPropTest.php

View workflow job for this annotation

GitHub Actions / tests / Static Analysis

Method Inertia\Tests\InitialPropTest::test_initial_props_are_not_accessible() has no return type specified.
{
Inertia::share([
'initial' => Inertia::initial(fn () => true),
'appName' => Inertia::initial(fn () => 'test'),
]);

$this->prepareMockEndpoint();

$response = $this->withoutExceptionHandling()->get('/', [
'X-Inertia' => 'true',
]);

$response->assertSuccessful();
$response->assertJsonMissingPath('initialProps');
}

public function test_can_invoke(): void
{
$initialProp = new InitialProp(function () {
return 'A initial value';
});

$this->assertSame('A initial value', $initialProp());
}

public function test_can_resolve_bindings_when_invoked(): void
{
$initialProp = new InitialProp(function (Request $request) {
return $request;
});

$this->assertInstanceOf(Request::class, $initialProp());
}

private function prepareMockEndpoint(): \Illuminate\Routing\Route
{
return Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () {
return Inertia::render('User/Edit');
});
}
}
11 changes: 11 additions & 0 deletions tests/ResponseFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Inertia\ComponentNotFoundException;
use Inertia\DeferProp;
use Inertia\Inertia;
use Inertia\InitialProp;
use Inertia\LazyProp;
use Inertia\MergeProp;
use Inertia\OptionalProp;
Expand Down Expand Up @@ -344,6 +345,16 @@ public function test_can_create_optional_prop(): void
$this->assertInstanceOf(OptionalProp::class, $optionalProp);
}

public function test_can_create_initial_prop(): void
{
$factory = new ResponseFactory;
$initialProp = $factory->initial(function () {
return 'An initial value';
});

$this->assertInstanceOf(InitialProp::class, $initialProp);
}

public function test_can_create_always_prop(): void
{
$factory = new ResponseFactory;
Expand Down
Loading