yii3/inertia

Inertia.js v3 server-side integration for Yii3.

Maintainers

Package info

github.com/yii3/inertia

pkg:composer/yii3/inertia

Transparency log

Statistics

Installs: 219

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

dev-main / 0.1.x-dev 2026-08-27 19:36 UTC

This package is auto-updated.

Last update: 2026-08-27 20:06:35 UTC


README

Yii Framework

Inertia for Yii3

PHPUnit Mutation Testing PHPStan Security

Connect Yii3 requests, responses, views, sessions, and redirects to the Inertia protocol

Server-side Inertia.js v3 integration for Yii3. The package uses constructor injection, PSR-7 responses, PSR-15 middleware, and Yii Config Plugin configuration. It does not expose a static facade or read from a service locator.

Architecture

The packages have deliberately separate responsibilities:

  • php-forge/inertia implements the framework-agnostic protocol, page model, prop resolution, headers, redirects, and result objects.
  • yii3/inertia adapts Yii3 request, response, session, and view services to that core.
  • php-forge/vite provides framework-agnostic Vite manifest and development server support for the initial document.

React and Vue remain application concerns; this adapter does not ship framework-specific JavaScript packages.

Requirements

  • PHP 8.3 or later.
  • A Yii3 application with PSR-17 response and stream factories.
  • yiisoft/session and yiisoft/csrf for flash data, validation errors, and the XSRF cookie flow.
  • yiisoft/request-body-parser for JSON form submissions.
  • yiisoft/view for rendering the initial HTML document through the application web view.
  • php-forge/inertia for the framework-neutral Inertia protocol and prop types.
  • php-forge/vite for framework-neutral asset resolution.

Installation

Applications should declare the adapter, the native PHP Forge packages they use, and Yii's request body parser as direct dependencies:

composer require yii3/inertia:^0.1 php-forge/inertia:^0.2 php-forge/vite:^0.2 yiisoft/request-body-parser:^1.2

For a local sibling checkout, add a Composer path repository:

{
    "repositories": [
        {
            "type": "path",
            "url": "../inertia",
            "options": {
                "symlink": true,
                "reference": "config"
            }
        }
    ],
    "require": {
        "yii3/inertia": "dev-main",
        "php-forge/inertia": "^0.2",
        "php-forge/vite": "^0.2",
        "yiisoft/request-body-parser": "^1.2"
    }
}

The Yii Config Plugin merges config/params.php and the web-only config/di-web.php automatically.

Middleware order

Place the middleware around the Yii3 web stack in this order:

use Yii3\Inertia\Middleware\CsrfTokenCookieMiddleware;
use Yii3\Inertia\Middleware\InertiaMiddleware;
use Yiisoft\Csrf\CsrfTokenMiddleware;
use Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
use Yiisoft\Request\Body\RequestBodyParser;
use Yiisoft\RequestProvider\RequestCatcherMiddleware;
use Yiisoft\Router\Middleware\Router;
use Yiisoft\Session\SessionMiddleware;

return [
    InertiaMiddleware::class,
    ErrorCatcher::class,
    SessionMiddleware::class,
    RequestBodyParser::class,
    CsrfTokenCookieMiddleware::class,
    CsrfTokenMiddleware::class,
    RequestCatcherMiddleware::class,
    Router::class,
];

This order ensures that:

  • Inertia headers are added to normal and error responses.
  • JSON form bodies are available before CSRF validation.
  • The session is open when the readable XSRF-TOKEN cookie is generated.
  • Mutable shared props are reset before and after every request, including failed requests.

The package configures Yii's CSRF validator to accept X-XSRF-TOKEN. Do not encrypt or sign the XSRF-TOKEN cookie with CookieMiddleware; the browser client must be able to read and return the masked token.

Configuration

Override the yii3/inertia parameter tree in application configuration:

<?php

declare(strict_types=1);

$manifest = dirname(__DIR__, 2) . '/public/build/.vite/manifest.json';

return [
    'yii3/inertia' => [
        'title' => 'My application',
        'version' => static function () use ($manifest): string|null {
            if (!is_file($manifest)) {
                return null;
            }

            $hash = hash_file('xxh128', $manifest);

            return $hash === false ? null : $hash;
        },
        'shared' => [
            'application' => ['name' => 'My application'],
        ],
        'csrf' => [
            // null enables HTTPS auto-detection. Use true only when trusted-proxy
            // middleware does not normalize the request URI scheme.
            'secure' => null,
        ],
    ],
];

The full parameter tree contains:

  • id, rootView, language, charset, and title for the initial document.
  • version, shared, and errorFlashKey for page construction.
  • csrf.cookieName, headerName, parameterName, path, domain, secure, and sameSite.

Configurable services keep constructors to at most four dependencies. Yii's DI definitions apply package parameters through immutable with*() methods, so each configured instance is cloned instead of mutated.

The configured root-view alias is resolved with Yiisoft\Aliases\Aliases and rendered by the application's Yiisoft\View\WebView. Custom root views therefore use Yii's configured renderers, themes, common parameters, and render events instead of a package-owned PHP file loader.

Vite integration

The application owns its Vite mode and entrypoints. Define the native PHPForge\Vite\Vite service directly; the package injects it into RootViewRenderer, which renders the resulting assets with the native stateless HtmlRenderer.

Production example:

<?php

declare(strict_types=1);

use PHPForge\Vite\Configuration\ProductionConfiguration;
use PHPForge\Vite\Vite;

return [
    Vite::class => static fn(): Vite => Vite::create(
        ProductionConfiguration::create(
            manifestPath: dirname(__DIR__, 2) . '/public/build/.vite/manifest.json',
            assetBaseUrl: '/build',
        ),
        entrypoints: ['resources/js/app.ts'],
    ),
];

During development, register the native development service:

<?php

declare(strict_types=1);

use PHPForge\Vite\Configuration\DevelopmentConfiguration;
use PHPForge\Vite\Vite;

return [
    Vite::class => static fn(): Vite => Vite::create(
        DevelopmentConfiguration::create('http://localhost:5173'),
        entrypoints: ['resources/js/app.ts'],
    ),
];

React applications may pass an application-owned InlineModuleProviderInterface implementation to DevelopmentConfiguration::create() for the React Refresh preamble. Vue applications do not need a preamble.

Rendering pages

Inject Yii3\Inertia\Inertia into an action and return its PSR-7 response. Use the native PHP Forge prop factories; this package does not duplicate them.

use PHPForge\Inertia\Prop\Prop;
use PHPForge\Inertia\Prop\ScrollMetadata;
use Psr\Http\Message\ResponseInterface;
use Yii3\Inertia\Inertia;

final readonly class DashboardAction
{
    public function __construct(private Inertia $inertia) {}

    public function __invoke(): ResponseInterface
    {
        $this->inertia->share('auth.user', ['id' => 42, 'name' => 'Ada']);

        return $this->inertia->render('Dashboard', [
            'summary' => static fn(): array => ['projects' => 12],
            'activity' => Prop::defer(static fn(): array => loadActivity(), 'dashboard', rescue: true),
            'audit' => Prop::optional(static fn(): array => loadAudit())->once(),
            'permissions' => Prop::always(['projects.read']),
            'users' => Prop::merge(loadUsers())->append('data', matchOn: 'id'),
            'messages' => Prop::merge(loadMessages())->prepend(),
            'settings' => Prop::merge(loadSettings())->deepMerge(),
            'countries' => Prop::once(static fn(): array => loadCountries())
                ->as('country-list')
                ->until(3600),
            'feed' => Prop::scroll(
                loadFeed(),
                new ScrollMetadata('page', previousPage: null, nextPage: 2, currentPage: 1),
            ),
        ]);
    }
}

Plain page, shared, and version closures are invoked without arguments, matching the PHP Forge core contract. Resolve request-dependent values explicitly in the action or capture the request in a zero-argument closure. Scroll metadata closures are the exception: the core passes them the resolved scroll value.

Page props replace shared props at the top-level key, matching the official adapter behavior. The response exposes the top-level shared keys through sharedProps, allowing Inertia v3 instant visits to retain shared application data. Session flash data is emitted only in the page-level flash field so it cannot replay from browser-history props.

Public API

Yii3\Inertia\Inertia exposes:

  • render(), location(), isInertiaRequest(), getVersion(), and normalizeResponse().
  • share(), getShared(), flushShared(), and reset().
  • Immutable with*() methods for service configuration.

All page and prop value objects come directly from php-forge/inertia. Vite configuration, resolution, and HTML asset rendering come directly from php-forge/vite; there is no Yii-specific Vite facade or metadata wrapper.

Adapter-owned exception text is centralized in Yii3\Inertia\Exception\Message. Exceptions from php-forge/inertia, Yii View, and other dependencies retain their native types and messages.

Debug and telemetry packages may implement ResolvedPageObserverInterface. The observer receives the resolved core Page synchronously and must keep captured request data request-scoped. Observation is skipped when no implementation is bound.

See the protocol notes for header and payload details.

Documentation

For detailed configuration options and advanced usage.

Package information

PHP Yii3 Inertia.js 3

Project status

PHPStan Level Max Quality ECS Dependencies

Community

Follow on X Yii Forum Join on Telegram

License

License