Skip to content

Introduce PHPStan + improve DocBlocks #768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Aug 12, 2025
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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
/tests export-ignore
/CHANGELOG.md export-ignore
/README.md export-ignore
/phpstan.neon export-ignore
2 changes: 1 addition & 1 deletion .github/workflows/facade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
php-version: 8.2
tools: composer:v2
coverage: none

Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: static analysis

on:
push:
branches:
- "2.x"
pull_request:

permissions:
contents: read

jobs:
tests:
uses: laravel/.github/.github/workflows/static-analysis.yml@main
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ jobs:
tools: composer:v2
coverage: none

- name: Remove PHPStan on PHP 8.1 and Laravel 10
run: composer remove --dev larastan/larastan
if: matrix.php == 8.1 || matrix.laravel == 10

- name: Set Minimum PHP 8.1 Versions
uses: nick-fields/retry@v3
with:
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"orchestra/testbench": "^8.0|^9.2|^10.0",
"mockery/mockery": "^1.3.3",
"phpunit/phpunit": "^10.4|^11.5",
"laravel/pint": "^1.16"
"laravel/pint": "^1.16",
"larastan/larastan": "^3.0"
},
"suggest": {
"ext-pcntl": "Recommended when running the Inertia SSR server via the `inertia:start-ssr` artisan command."
Expand All @@ -53,4 +54,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
17 changes: 17 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
includes:
- vendor/larastan/larastan/extension.neon

parameters:
level: 6
paths:
- src
- tests
excludePaths:
- src/Testing/Concerns
ignoreErrors:
- '#Call to an undefined method.*TestResponse.*::assertInertia\(\)#'
- '#Call to an undefined method.*TestResponse.*::inertiaPage\(\)#'
- '#Call to an undefined method.*TestResponse.*::inertiaProps\(\)#'
- '#Call to an undefined.*method.*Request::inertia\(\)#'
- '#Call to an undefined.*method.*Route::inertia\(\)#'

17 changes: 16 additions & 1 deletion src/AlwaysProp.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,32 @@

class AlwaysProp
{
/** @var mixed */
/**
* The property value.
*
* Always included in Inertia responses, bypassing partial reload filtering.
*
* @var mixed
*/
protected $value;

/**
* Create a new always property instance. Always properties are included
* in every Inertia response, even during partial reloads when only
* specific props are requested.
*
* @param mixed $value
*/
public function __construct($value)
{
$this->value = $value;
}

/**
* Resolve the property value.
*
* @return mixed
*/
public function __invoke()
{
return is_callable($this->value) ? App::call($this->value) : $this->value;
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/CheckSsr.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class CheckSsr extends Command
protected $description = 'Check the Inertia SSR server health status';

/**
* check the SSR server via a Node process.
* Check the Inertia SSR server health status.
*/
public function handle(Gateway $gateway): int
{
Expand Down
4 changes: 4 additions & 0 deletions src/Commands/CreateMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ protected function getDefaultNamespace($rootNamespace): string

/**
* Get the console command arguments.
*
* @return array<int, array<int, mixed>>
*/
protected function getArguments(): array
{
Expand All @@ -60,6 +62,8 @@ protected function getArguments(): array

/**
* Get the console command options.
*
* @return array<int, array<int, mixed>>
*/
protected function getOptions(): array
{
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/StartSsr.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class StartSsr extends Command
protected $description = 'Start the Inertia SSR server';

/**
* Start the SSR server via a Node process.
* Start the Inertia SSR server.
*/
public function handle(): int
{
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/StopSsr.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class StopSsr extends Command
protected $description = 'Stop the Inertia SSR server';

/**
* Stop the SSR server.
* Stop the Inertia SSR server.
*/
public function handle(): int
{
Expand Down
4 changes: 4 additions & 0 deletions src/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

class Controller
{
/**
* Handle the incoming request and render the Inertia response.
* Renders the component and props defined in the route defaults.
*/
public function __invoke(Request $request): Response
{
return Inertia::render(
Expand Down
29 changes: 29 additions & 0 deletions src/DeferProp.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,50 @@ class DeferProp implements IgnoreFirstLoad, Mergeable
{
use MergesProps;

/**
* The callback to resolve the property.
*
* Loaded asynchronously after initial page render for performance.
*
* @var callable
*/
protected $callback;

/**
* The defer group.
*
* @var string|null
*/
protected $group;

/**
* Create a new deferred property instance. Deferred properties are excluded
* from the initial page load and only evaluated when requested by the
* frontend, improving initial page performance.
*/
public function __construct(callable $callback, ?string $group = null)
{
$this->callback = $callback;
$this->group = $group;
}

/**
* Get the defer group for this property. Properties with the same group
* are loaded together in a single request, allowing for efficient
* batching of related deferred data.
*
* @return string|null
*/
public function group()
{
return $this->group;
}

/**
* Resolve the property value.
*
* @return mixed
*/
public function __invoke()
{
return App::call($this->callback);
Expand Down
8 changes: 6 additions & 2 deletions src/Directive.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
class Directive
{
/**
* Compiles the "@inertia" directive.
* Compile the "@inertia" Blade directive. This directive renders the
* Inertia root element with the page data, handling both client-side
* rendering and SSR fallback scenarios.
*
* @param string $expression
*/
Expand All @@ -30,7 +32,9 @@ public static function compile($expression = ''): string
}

/**
* Compiles the "@inertiaHead" directive.
* Compile the "@inertiaHead" Blade directive. This directive renders the
* head content for SSR responses, including meta tags, title, and other
* head elements from the server-side render.
*
* @param string $expression
*/
Expand Down
7 changes: 4 additions & 3 deletions src/EncryptHistoryMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EncryptHistoryMiddleware
{
/**
* Handle the incoming request.
* Handle the incoming request and enable history encryption. This middleware
* enables encryption of the browser history state, providing additional
* security for sensitive data in Inertia responses.
*
* @return Response
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle(Request $request, Closure $next)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Inertia.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

/**
* @method static void setRootView(string $name)
* @method static void share(string|array|\Illuminate\Contracts\Support\Arrayable $key, mixed $value = null)
* @method static void share(string|array<array-key, mixed>|\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|\Inertia\ProvidesInertiaProperties $key, mixed $value = null)
* @method static mixed getShared(string|null $key = null, mixed $default = null)
* @method static void clearHistory()
* @method static void encryptHistory($encrypt = true)
Expand All @@ -20,7 +20,7 @@
* @method static \Inertia\AlwaysProp always(mixed $value)
* @method static \Inertia\MergeProp merge(mixed $value)
* @method static \Inertia\MergeProp deepMerge(mixed $value)
* @method static \Inertia\Response render(string $component, array|\Illuminate\Contracts\Support\Arrayable $props = [])
* @method static \Inertia\Response render(string $component, array<array-key, mixed>|\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|\Inertia\ProvidesInertiaProperties $props = [])
* @method static \Symfony\Component\HttpFoundation\Response location(string|\Symfony\Component\HttpFoundation\RedirectResponse $url)
* @method static void macro(string $name, object|callable $macro)
* @method static void mixin(object $mixin, bool $replace = true)
Expand Down
16 changes: 16 additions & 0 deletions src/LazyProp.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,31 @@

use Illuminate\Support\Facades\App;

/**
* @deprecated Use OptionalProp instead for clearer semantics.
*/
class LazyProp implements IgnoreFirstLoad
{
/**
* The callback to resolve the property.
*
* @var callable
*/
protected $callback;

/**
* Create a new lazy property instance.
*/
public function __construct(callable $callback)
{
$this->callback = $callback;
}

/**
* Resolve the property value.
*
* @return mixed
*/
public function __invoke()
{
return App::call($this->callback);
Expand Down
17 changes: 16 additions & 1 deletion src/MergeProp.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ class MergeProp implements Mergeable
{
use MergesProps;

/** @var mixed */
/**
* The property value.
*
* Merged with existing client-side data during partial reloads.
*
* @var mixed
*/
protected $value;

/**
* Create a new merge property instance. Merge properties are combined
* with existing client-side data during partial reloads instead of
* completely replacing the property value.
*
* @param mixed $value
*/
public function __construct($value)
Expand All @@ -20,6 +30,11 @@ public function __construct($value)
$this->merge = true;
}

/**
* Resolve the property value.
*
* @return mixed
*/
public function __invoke()
{
return is_callable($this->value) ? App::call($this->value) : $this->value;
Expand Down
24 changes: 24 additions & 0 deletions src/Mergeable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,31 @@

interface Mergeable
{
/**
* Mark the property for merging.
*
* @return static
*/
public function merge();

/**
* Determine if the property should be merged.
*
* @return bool
*/
public function shouldMerge();

/**
* Determine if the property should be deep merged.
*
* @return bool
*/
public function shouldDeepMerge();

/**
* Get the properties to match on for merging.
*
* @return array<int, string>
*/
public function matchesOn();
}
Loading