omnibridge / laravel
The Laravel host of omniscient/omnibase: its Foundation contracts (urls, translations, locales, access, parameters with the database settings laid over Laravel's config, clock, events...) answered by Laravel's services and seeded in Base\Contract\Runtime, Doctrine through omnibridge/doctrine, Twig t
Requires
- php: ^8.4
- doctrine/dbal: ^4.2
- doctrine/orm: ^3.4
- illuminate/auth: ^12.0|^13.0
- illuminate/config: ^12.0|^13.0
- illuminate/contracts: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/routing: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- omnibridge/doctrine: ^1.0
- omnibridge/twig: ^1.0
- omniscient/omnibase: ^4.0
- omniscient/omnibridge: ^1.0
- psr/clock: ^1.0
- psr/event-dispatcher: ^1.0
- symfony/cache: ^7.0|^8.0
- symfony/mailer: ^7.0|^8.0
- symfony/routing: ^7.0|^8.0
- symfony/translation: ^7.0|^8.0
- symfony/yaml: ^7.0|^8.0
- twig/twig: ^3.10
Requires (Dev)
- omniauth/google: 1.x-dev
- omniauth/oauth: 1.x-dev
- omniauth/passkey: 1.x-dev
- omniauth/totp: 1.x-dev
- omniscient/omniauth: 1.x-dev
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.5|^12.0
Suggests
- omniauth/google: Google sign-in through Omnibridge\Laravel\Auth\ (config/omniauth.php: oauth.providers.google; its GoogleFactory is used when it is installed)
- omniauth/oauth: Identity providers through Omnibridge\Laravel\Auth\ (config/omniauth.php: oauth), each provider a package of its own (omniauth/google)
- omniauth/passkey: Passkeys through Omnibridge\Laravel\Auth\ (config/omniauth.php: passkey)
- omniauth/totp: Authenticator applications through Omnibridge\Laravel\Auth\ (config/omniauth.php: totp)
- omniscient/omniauth: Omnibridge\Laravel\Auth\: Laravel's guard and user provider over omniauth, one controller for every way of signing in (password, sign-in link, e-mailed code, backup codes, trusted devices), the second factor's page, the routes; config/omnibridge.php 'auth' => true and config/omniauth.php (nothing of Auth\ without it)
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-21 13:12:33 UTC
README
composer config allow-plugins.omnibridge/composer true
composer require omniscient/omnibase:4.x-dev omnibridge/laravel:1.x-dev
php artisan vendor:publish --tag=omnibridge-config
That hosts omniscient/omnibase in a
Laravel application: the provider is discovered by Laravel, binds each contract of
omnibase's Foundation to Laravel's services, and hands Laravel's container to the
Foundation's registry, Base\Contract\Runtime (omniscient/omnibridge's
Omnibridge\Runtime with omnibase's accessors). The host's contracts are
omniscient/omnibridge's
(Omnibridge\Contract\*), bound under their own names; their former names
(Base\Contract\Urls..., omnibridge/twig's) are Laravel aliases of them until
omnibase 4's final pass, the same binding under either. omnibase's framework-free code -
an entity's link, its noun, a translatable's language, a screen's builder - then
runs under Laravel as it runs under Symfony:
use Base\Contract\Runtime; Runtime::urls()->path('article', ['slug' => 'le-fuji']); // Laravel's router Runtime::translations()->trans('@messages.menu.home'); // omnibase's ICU catalogues Runtime::parameters()->get('base.user.delay'); // Laravel's config, the database settings over it app(Omnibridge\Contract\Urls::class) === Runtime::urls(); // one object, also app(Base\Contract\Urls::class)
omnibase asks for PHP 8.4 and the extensions its own packages need (bcmath, intl, gd, exif, ftp, imagick, igbinary). omnibase stays on Doctrine for storage and Twig for its templates: this package opens Doctrine on one of Laravel's connections (omnibridge/doctrine) and Twig over the site's templates (omnibridge/twig).
What is bound
| Contract | Answered by | Class |
|---|---|---|
Omnibridge\Contract\Urls (formerly Base\Contract\Urls and omnibridge/twig's) |
Laravel's router (route()), the build's asset manifest; a route Laravel does not have may be answered elsewhere |
RouterUrls |
Omnibridge\Contract\Translations (formerly Base\Contract\Translations and omnibridge/twig's) |
the ICU catalogues of the folders configured, read by symfony/translation, in Laravel's current locale; exists() |
CatalogueTranslations |
Omnibridge\Contract\Locales (formerly Base\Contract\Locales) |
Laravel's locale (fr) as the site's locale (fr-FR), the default first |
Contract\AppLocales |
Base\Contract\Nouns |
omnibase's own rule (EntityNouns) on those catalogues |
- |
Omnibridge\Contract\Access (formerly Base\Contract\Access) |
the gate (Gate::allows()), the default guard's user |
Contract\GateAccess |
Omnibridge\Contract\Sessions (formerly Base\Contract\Sessions) |
the guard's logout() for the user signed in |
Contract\GuardSessions |
Omnibridge\Contract\Tokens (formerly Base\Contract\Tokens) |
the session's CSRF token (one for every intent) | Contract\SessionTokens |
Omnibridge\Contract\Environment (formerly Base\Contract\Environment) |
APP_ENV, app.debug, app.key |
Contract\AppEnvironment |
Omnibridge\Contract\Routes (formerly Base\Contract\Routes) |
a route's declared path, the route of an address; no icons | Contract\RouterRoutes |
Omnibridge\Contract\Files (formerly Base\Contract\Files) |
the disks (omnibase's storage names mapped to disks) | Contract\DiskFiles |
Base\Service\ParameterBagInterface |
Laravel's config, the settings linked to a parameter laid over it (omnibase's HotParameters) |
Parameters\ConfigParameters, Parameters\DatabaseSettings |
Psr\Clock\ClockInterface |
Laravel's dates (Date::setTestNow(), travel() move it) |
Contract\DateClock |
Psr\EventDispatcher\EventDispatcherInterface |
Laravel's dispatcher | Contract\DispatcherEvents |
Symfony\Component\Mailer\MailerInterface |
the default mailer's Symfony transport | Contract\TransportMailer |
Doctrine\DBAL\Connection, Doctrine\ORM\EntityManagerInterface |
the Laravel connection configured, omnibridge/doctrine's entity manager | Doctrine\Connections |
Twig\Environment |
the site's templates and namespaces, omnibridge/twig's contract (path(), url(), asset(), |trans), its AccessExtension (is_granted() on the gate, csrf_token() the session's token: the code a Symfony page asks too, omnibridge/symfony registering it there) and helpers |
View\Twig |
Base\Contract\Pictures |
|picture's rule: a public file by its thumbnail at the size asked (MediaService's, omnibridge.media on) or its path, an address as it is, else the build's asset; a stored picture where the application serves it (stored()) |
Screen\AddressPictures |
Base\Contract\Texts |
|wysiwyg and |wysiwyg_toc's passes (headings, links, every leaf a string, Editor.js's renderer or Quill's HTML) through omnibase's own views (@Base among the Twig paths, or on($twig)); a picture where the application serves it (images()) |
Screen\WysiwygTexts |
Base\Screen\ContextProvider |
a screen's frame: the locale as a Symfony request carries it (fr_FR), the site's settings, home, login, register, logout and each language's address, the guard's user, the colour scheme of the visitor's mode (omnibridge.theme), the session's messages |
Screen\ScreenContext |
With omnibridge.media on (see below): Base\Contract\Media (Media\ServiceMedia,
MediaService's answers), Base\Service\MediaService, Base\Service\ImageRoute, and
omnibase's image routes. Off (the default), none of them.
Screens. With those three, a screen of the core is built on Laravel as under Symfony, without code of the application's:
use Base\Contract\Runtime; use Base\Screen\Builder\Stories; $frame = app(Base\Screen\ContextProvider::class)->frame(['destination' => $destination]); $text = (new Stories(Runtime::texts(), Runtime::pictures()))->text($thread->getContent(), ['headings' => true]);
An application says where it serves its stored pictures, in a provider:
$this->app->extend(Base\Contract\Pictures::class, fn ($pictures) => $pictures->stored(fn (string $image) => /* its address, or null */)); $this->app->extend(Base\Contract\Texts::class, fn ($texts) => $texts->images(fn (string $source) => /* its address, or null */));
Actions. An action written once for every host (no Request, no Response: its inputs,
and a result of omnibase's - Base\Screen\Template, Json, Shell, File, a View, or
null for no such page) is a route here, answered by omnibase's Base\Screen\Negotiation
(HTML, JSON when the template allows it and the client prefers it, omnibridge/react's
protocol and its 409) through Screen\Responder, as Base\Bridge\Symfony\ScreenResponder
answers it under Symfony:
use Omnibridge\Laravel\Screen\Responder; Route::get('/{destination}/articles/{slug}', Responder::action(App\Action\Blog\Article::class))->name('app_article');
The action's parameters are the route's by name, $query the query string's values, the
rest the container's. The templates are rendered by the container's Twig; an application
whose pages carry more (a page context, what it adds once rendered) binds its own
Base\Screen\Negotiation, rendering Negotiation::PAGE (a page), PART (a value of a
JSON answer) and ALONE (a page whole, its own markup only) each its way.
Language. omnibase's language under Laravel, as its LocalizerSubscriber and
LocalizerController give it under Symfony: Http\Localize (the web group's middleware: the
LANG cookie, else the browser's language among omnibridge.locales.available, else
omnibridge.locales.default) and Http\SwitchLocale (Route::get('/locale/{_locale?}', SwitchLocale::class)->name('_switch_locale'): the choice kept as Symfony writes it, en_GB, and
back to the page it came from on the site). Leave LANG out of the encrypted cookies.
Parameters. Runtime::parameters() reads Laravel's config by the same dotted
path (app.name; base.user.delay for a site with config/base.php), and, when
omnibridge.parameters.hot is on (or the config's own
base.parameter_bag.use_hot_bag), the settings the back office links to a
parameter, read once in omnibase's tables (layoutSetting, layoutSettingIntl) on
the first call: a setting stored as false wins over the config's true, as under
Symfony. Laravel's config binding itself is not decorated: Laravel reads and
caches its configuration before any provider, everywhere, as an array; settings
read from a database have no place there.
Also here
The pieces an omnibase page asks of its framework, for an application that renders
omnibase's templates with Laravel: View\Encore (encore_entry_link_tags() and
encore_entry_script_tags() as omnibase prints them, with the breakpoints'
stylesheets), View\Breakpoints (the style omnibase puts before the first
stylesheet), Page\AppVariable and its parts (the app variable with Symfony's
words: app.request.getLocale(), app.request.attributes.get('_route'),
app.site, app.theme, app.session; Page\Theme is omnibase's ThemizerInterface too,
which its theme menus read: Base\Twig\Extension\MenuTwigExtension), Form\FormView and Form\FormRenderer
(a few simple forms in the markup of omnibase's form theme), and
RouterUrlGenerator (Symfony's UrlGeneratorInterface over the Urls contract, for
a library that asks for one).
Signing in through omniauth
// config/omnibridge.php 'auth' => true, // config/auth.php 'guards' => ['web' => ['driver' => 'omniauth', 'provider' => 'omnibase']], 'providers' => ['omnibase' => ['driver' => 'omniauth']],
With omnibridge.auth on and omniscient/omniauth
installed (it is only suggested), Auth\AuthServiceProvider wires omniauth's sign-in
under Laravel as omnibridge/symfony wires it under Symfony (plan "omniauth", ยง3.2, step
AU8), from config/omniauth.php (php artisan vendor:publish --tag=omniauth-config) -
the same keys as config/packages/omniauth.yaml there, so one site says the same thing
under both hosts: each method's key turns it on (the password, the sign-in link, the
e-mailed code, the backup codes, the trusted devices; passkeys, the authenticator
application and the identity providers with their package, omniauth/passkey,
omniauth/totp, omniauth/oauth and omniauth/google), the stores ("omnibase": the core's
Base\Auth\ on the entity manager - the user, userToken, userPasskey and userIdentity
tables -, or the container's bindings by key), the throttle on a Laravel cache store, the
messages.
Auth\OmniauthGuard(StatefulGuard, driveromniauth) keeps the account's handle in the session, reads the account back through omniauth'sAccountsat each request, renews the session's id at a sign-in, sets the signed remember-me cookie (Auth\RememberMe: the handle, the expiry, the password hash and the address, as Security'ssignature_properties) and forgets it at a sign-out;attempt()asks omniauth the password.Auth\OmniauthUserProvider(driveromniauth) answers Laravel'sUserProviderover the same stores, the passwords checked by symfony/password-hasher as under Symfony (>72-byte passwords included).- The account is Laravel's
AuthenticatablethroughAuth\AccountUser, a wrapper the contracts unwrap:Omnibridge\Contract\Access::getUser(), the screens' viewer and Twig'sapp.usergive the application's own object, as under Symfony. Auth\Controllers\SignInis every way in: the password form (and its page, the site'ssecurity/login.html.twigwith the form as omnibase's templates read it), the sign-in link, a passkey (web-auth's JSON), the second factor's code, an identity provider's return, and the sign-out (CSRF-checked as Security's logout withenable_csrf);Auth\Controllers\Ceremonythe second factor's page (scheb/2fa's variables: the site's template renders unchanged), a passkey's options, the trip out to a provider. The forms' CSRF tokens are checked through the Tokens contract (Laravel's session token); Laravel's own CSRF middleware is left off these routes.Auth\Routesdeclares them at the Symfony site's addresses and under its route names (security_login,2fa_login,2fa_login_check,oauth_google,oauth_google_check,security_logout,security_logoutRequest...), in the web group;omniauth.routesfalse to declare them yourself.Auth\Middleware\SecondFactorPending(appended to the web group, beforeauth) keeps a visitor between two factors on the second factor's page;Auth\Rolesanswers Security's attributes throughGate::before()-ROLE_*withomniauth.role_hierarchy,IS_AUTHENTICATED_FULLY,IS_AUTHENTICATED_REMEMBERED,IS_AUTHENTICATED_2FA_IN_PROGRESS,PUBLIC_ACCESS- sois_granted()and the Access contract answer as under Symfony.- The cookies the Symfony site shares (
trusted_devicein scheb/2fa's format, the remember-me) are left out of Laravel's cookie encryption;omniauth.secretis the Symfony site'skernel.secret, so the devices it trusted and the codes it sent are good here. An identity provider's return address is the path of its check route, completed with the host of each request (a long-running server keeps the providers).
With omnibase's stores, the core's Base\Auth\Listener\UpdateAccount brings the
account up to date at its sign-in (a role dropped, its time zone and language kept, its
kick lifted); Base\Auth\Policy decorates the second-factor rule where the
application binds omnibase's SecurityPolicy; a sign-in link or an e-mailed code needs
a Omniauth\Contract\Sender (omnibase's NotifierSender needs its Notifier).
Configuration
config/omnibridge.php: the site's locales, the catalogues' folders, the asset
manifest, Twig's folders and namespaces, the Laravel connection Doctrine opens and
the entities' folders, the parameters' overlay, the themes (the screens' colour scheme), the storages, the bundles' entity
namespaces. A route Laravel does not serve can be answered elsewhere:
$this->app->extend(RouterUrls::class, fn (RouterUrls $urls) => $urls->elsewhere( fn (string $name, array $parameters, string $locale) => $otherSite->url($name, $parameters, $locale), ));
omnibase's Doctrine mapping
// config/omnibridge.php 'doctrine' => [ 'connection' => 'mysql', 'entities' => [app_path('Entity')], 'omnibase' => ['project_dir' => base_path()], // or true; false (the default) leaves it off ],
With omnibridge.doctrine.omnibase on, the bound entity manager is omnibase's, as
under Symfony: built by omnibridge/doctrine with Base\Bridge\Doctrine\Mapping::configure()
(the repositories from omnibase's registry), over the core's entities beside the
application's, then Mapping::register() - the class convention (App\Entity\X is
Base\Entity\X where the application has none, an alias and not a subclass; an
application's own class always wins), the column types and enumerations (the
project's src/Enum), the naming strategy, the discriminator maps, #[Alias], the
translations, the listeners and the trash and vault filters. Its options are
Mapping::register()'s: project_dir (base_path()), environment (omnibase's
name, the vault's: prod, dev, test for Laravel's production, local,
testing), cache_dir, parameters (over Laravel's base config by full name -
the entities read base.uploader.storage...), types, enumerations,
attribute_paths, resolve_target_entities, entity_listeners. app(Mapping::class)
gives what it registered. OmnibaseMappingTest checks the metadata against those
omniscient/omnibase records from its Symfony harness, class by class.
omnibase's images
// config/omnibridge.php 'storages' => ['local.cache' => 'omnibase-images', 'local.uploads' => 'uploads'], // Laravel's disks 'media' => true, // or ['routes' => false, 'secret' => ...]; false (the default) leaves it off
With omnibridge.media on, omnibase's media rule runs under Laravel as under Symfony:
MediaService (thumbnails, formats, the image route's obfuscated addresses) built on
Laravel's router (Media\LaravelMediaRouter, the core's Base\Contract\MediaRouter),
omnibase's Obfuscator and Flysystem (its storages are Laravel's disks,
Media\DiskStorages: omnibridge.storages, else the disk of the storage's name;
local.cache, where the thumbnails are kept, is required) and Imagine (Imagick, else GD).
The image routes (/images/..., /contents/...) are declared under their Symfony names
in Symfony's order (Base\Service\ImageRoute::ROUTES) and answered by the core's
Base\Service\ImageRoute (Media\ImageController, a line per request): the same
addresses, thumbnails, formats, redirections and placeholder. Its parameters are the
config's base: base.images.* (max_quality, enable_webp, fallback, no_image...),
base.obfuscator.* (uuid, compression... and cache_dir, the map of the
identifiers: share the Symfony site's to read the addresses it wrote),
base.uploader.storage, base.twig.editor.storage; omnibase's defaults where it says
nothing. A file has the address Symfony gives it when it has the same path on both hosts
(the identifiers are made of it: the same project folder, the uploads where the Symfony
site's public/ links them).
With omnibase's mapping on as well, what a site's entities and repositories ask of
their host is answered here too: the attribute reader reads the stored files through
that Flysystem (#[Uploader]: an avatar, an article's audio, whose /contents/...
addresses ImageRoute serves), BaseTrait::getMediaService() is the bound
MediaService, the editor's pictures go through omnibase's MediaEnhancer
(MediaEnhancerInterface, the image route's address of each picture of a text, as
Symfony's |wysiwyg gives it), and a repository taking services beside the registry
(a site's CommentRepository, its cache pool first) is given them from Laravel's
container by type (Mapping::register()'s services). omnibase's cache pool
(Psr\Cache\CacheItemPoolInterface, Symfony's CacheInterface) is Symfony's cache
component in storage/framework/cache/omnibase-pool - not Laravel's store, which
unserializes no object (cache.serializable_classes).
First used by lesringostars' Laravel twin, which renders the Symfony site's blog and articles from the same database and templates.
Tests
docker compose run --rm test
PHPUnit on Orchestra Testbench (Laravel 13), PHP 8.4, omniscient/omnibase 4.x
installed from Packagist: every contract reached through Runtime and the
container as one object, each answer (routes, ICU messages and exists(), locales,
the gate, sign-out, the CSRF token, the clock under travel(), events, disks, the
parameters with a false setting over a true config), Doctrine on Laravel's SQLite
database in UTC, omnibase's mapping (an App\ class over a Base\ one, another only by
alias, the metadata of 94 classes equal to Symfony's), omnibase's images (a thumbnail's
address made and read back, redirected to its extension, served at its size, in webp and
without the local cache, a missing one a 404, Pictures' thumbnails; Imagick in the image),
the settings of the site, Encore tags, the breakpoints, a form.
Licence
MIT.