silarhi / turbo-bundle
Framework-agnostic Hotwire Turbo frame-redirect following and turbo_frame Twig filter for Symfony — the PHP companion to @silarhi/turbo
Requires
- php: >=8.2
- symfony/config: ^6.4 || ^7.0 || ^8.0
- symfony/dependency-injection: ^6.4 || ^7.0 || ^8.0
- symfony/event-dispatcher: ^6.4 || ^7.0 || ^8.0
- symfony/http-foundation: ^6.4 || ^7.0 || ^8.0
- symfony/http-kernel: ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.54.0
- friendsofphp/php-cs-fixer: ^3.95.27
- phpstan/extension-installer: ^1.4.3
- phpstan/phpstan: ^2.3.1
- phpstan/phpstan-strict-rules: ^2.1.0
- phpstan/phpstan-symfony: ^2.1.0
- phpunit/phpunit: ^11.5.57 || ^12.5.38 || ^13.4.1
- rector/rector: ^2.7.0
- symfony/error-handler: ^6.4 || ^7.0 || ^8.0
- twig/twig: ^3.0
Suggests
- symfony/framework-bundle: Register Silarhi\TurboBundle\SilarhiTurboBundle for zero-config service wiring (optional — the classes also work standalone)
- twig/twig: Enables the `turbo_frame` Twig filter (auto-registered by SilarhiTurboBundle when present)
Provides
None
Conflicts
None
Replaces
None
README
Turbo Bundle
Two small, framework-agnostic Hotwire Turbo helpers.
A TypeScript lifecycle orchestrator for the browser and a Symfony-components frame-redirect listener for the server — each usable on its own.
The two halves solve different problems and only meet on redirect following (the server escalates a frame redirect to a
Turbo-Location header, the browser handler follows it):
@silarhi/turbo(JS/TS): aTurboHandlerthat runs a single pair ofonMount/onUnmountcallbacks across every Turbo Drive, Frame and Stream render.silarhi/turbo-bundle(PHP): a listener that turns a redirect issued inside a Turbo Frame into a full Drive visit, plus theturbo_frameTwig filter. Symfony components only, nosymfony/framework-bundlerequired.
Features
- One lifecycle hook pair:
onMount/onUnmountrun on Drive renders, frame loads and Stream mutations alike - Morph-aware: Stream renders are diffed per node; Drive and Frame morphs can opt into per-element refresh
- Frame-redirect following: a redirect inside a Turbo Frame becomes a full Drive visit,
DELETEredirects too turbo_frameTwig filter: extend a lean frame template only when the request targets a matching frame- Framework-optional: the bundle gives zero-config wiring; the classes also work standalone
Requirements
- PHP 8.2+ and Symfony components 6.4, 7.x or 8.x
@hotwired/turbo7.1+ or 8.x for@silarhi/turbo(followingDELETEredirects outside a frame needs Turbo 8)
Installation
composer require silarhi/turbo-bundle # PHP half pnpm add @silarhi/turbo # JS half
// config/bundles.php return [ // ... Silarhi\TurboBundle\SilarhiTurboBundle::class => ['all' => true], ];
Quick start
import { TurboHandler } from '@silarhi/turbo' new TurboHandler({ onMount: (container) => app.mount(container), onUnmount: (container) => app.unmount(container), }).start()
Your widgets now mount and unmount on every Turbo render, and a redirect answered to a frame request becomes a full
page visit. Render a lean layout inside frames with {% extends 'base.html.twig'|turbo_frame('main') %}, after
creating that layout in templates/base-frame.html.twig (see the
quick start).
Documentation
Everything else is on turbo-bundle.silarhi.dev:
- Installation and quick start
- JavaScript:
TurboHandler, stream mutations, morph mutations, frame responses without a matching frame, keeping a redirect in its frame - PHP: frame-redirect following, the
turbo_frameTwig filter, without the framework - Reference: configuration,
TurboHandleroptions, PHP API, HTTP headers
Contributing
See CONTRIBUTING.md. Release notes are in CHANGELOG.md.
License
Released under the MIT License.