freshheads/multi-site-bundle
A Symfony bundle for running multiple websites from one codebase, with per-site configuration, routing, and content isolation. Simplifies multi-site management without duplicating application logic.
Architecture fit — poor as a direct dependency, moderate as a reference implementation. The package remains a Symfony bundle (FHMultiSiteBundle), not a Laravel package. Release 1.3.0 adds Symfony 7 support, which confirms rather than softens this verdict: the bundle is explicitly tracking Symfony major versions, so its integration contract is a bundle class in bundles.php, a DI extension with a Configuration tree, compiler passes, and Symfony route loaders/listeners. None of that exists in Laravel. Laravel has its own container, service-provider lifecycle, and router — although Illuminate\Routing\Route extends Symfony\Component\Routing\Route, so a narrow slice of the routing surface is conceptually shared. The transferable value is still the design: a site registry, a resolver mapping an incoming request (host and/or path prefix) to a site, and route-registration strategies keyed by site.
Integration feasibility — low for composer require, moderate-to-high for a port. Unchanged. A 200–400 line spike remains sufficient to decide whether the resolver logic is worth lifting. The realistic outcomes are still (a) reimplement the resolver and site registry natively using Route::domain() groups plus a ResolveSite middleware, or (b) pull a non-Symfony core subset if one cleanly exists. The 2024–2025 activity does not change the estimate; if anything the Symfony 7 retarget makes the code less likely to be framework-agnostic, since it now leans on current Symfony DI and attribute conventions.
Technical risk — high, but the risk profile has shifted from "abandoned" to "maintained-but-idle."
@bart-van-amelsvoort). Read this correctly, though: it is a maintenance/tooling release with zero feature or API changes. Stars and dependents are still effectively nil, there is still no third-party security review, no SLA, and the contributor is doing housekeeping, not building a community. Treat it as "vendor responds to framework majors on their own schedule," not as "this is a safe upstream to depend on."symfony/framework-bundle at 7.x and PHP 8.2+. That is the same Symfony generation Laravel 11 draws components from — so the earlier worry ("component version mismatch inside Laravel") is now moot. The terminal problem is unchanged: a bundle requiring framework-bundle will never boot in Laravel regardless of version alignment. One thing to check: adding Symfony 7 in a 1.x minor is a constraint-level breaking change — diff composer.json across 1.2.1 → 1.3.0 to see whether Symfony 5.4/6.x support was dropped. For us this matters only as evidence of how tightly the site-registry configuration is welded to Symfony's config component.Key questions for the spike owner (revised):
framework-bundle?framework-bundle 7.x and PHP 8.2+. Confirm by reading composer.json and diffing against 1.2.1: specifically, were Symfony 5.4/6.x constraints dropped, and is the PHP floor now 8.2?RouteLoaderInterface, PHP attributes, a compiler pass, or a request listener? Can that be expressed as Laravel route groups? (The Symfony 7 retarget makes attribute-based registration more likely — check whether registration moved from YAML/XML to attributes, and whether that logic survives translation.)config/sites.php?route() output?Stack fit. Treat the bundle as a specification, not a dependency. 1.3.0 does not change the mapping:
| Bundle concept | Laravel equivalent |
|---|---|
| Site configuration tree | config/sites.php with a typed array schema, validated at boot |
| Site resolver / repository | Singleton SiteResolver bound in a service provider |
| Routing strategy per site | Route::domain() groups, or per-site RouteServiceProvider |
| Request-scoped site context | ResolveSite middleware + a CurrentSite scoped binding |
| Template/locale switching | Middleware-set locale and view namespace |
Migration path. Still no shim or adapter layer — the bootstrapping models are incompatible, and a shim would carry all the maintenance burden with none of the upstream benefit. Sequence, lightly revised:
config/sites.php — host list, path prefix, locale, asset/theme root, per-site feature flags. Decide static enumeration vs. database discovery.ResolveSite, bind a request-scoped CurrentSite, add a 404/fallback policy for unknown hosts. Test explicitly under Octane and queued jobs.route() and signed URLs resolve against the current site.Budget remains roughly 2–3 engineering weeks for a hardened port with tests; the spike alone is under a week.
Compatibility — materially clearer after 1.3.0. The bundle now targets Symfony 7 and therefore PHP 8.2+, and modernized DI conventions (autowiring, likely attributes) are closer in spirit to Laravel's container than the older service-alias style would have been. That is a modest win for readability, not for installability. Two concrete checks: (a) diff composer.json between 1.2.1 and 1.3.0 to confirm the dropped Symfony/PHP floors and to see whether symfony/framework-bundle is a hard require versus a suggest; (b) confirm the Laravel version in use ships a Symfony component generation we can reason about. Neither check changes the outcome — framework-bundle has no Laravel analogue to boot against.
Sequencing note. Unchanged and still the gating question. This work is only justified if the product genuinely requires per-site configuration divergence (locales, themes, feature flags), not merely multiple domains pointing at one app. If the requirement is "serve several hostnames from one codebase," Route::domain() plus a small host→tenant map covers it in a day, and neither this bundle nor a port of it adds anything.
Maintenance. We own it after porting, and 1.3.0 does not change the economics: no security advisories, no compatibility guarantees, no roadmap. A Symfony 7 PR in a 1.x minor is evidence they can move, not evidence they will move on our timeline — and given nil dependents, there is no ecosystem pressure forcing them to. Add the ported resolver and middleware to the internal ownership register with a named maintainer. The steady-state cost is low (small, stable logic), but the unowned dependency risk of installing a low-adoption Symfony bundle into a Laravel app remains severe enough to reject outright.
Support. MIT, no vendor SLA, documentation limited to the repository README. Any production incident traces to our own ported code, which is the favorable outcome — we can read and fix it. 1.3.0 adds a changelog-enforcer, which marginally improves release-note hygiene; it does not create a support channel. Keep no Composer entry, so nothing to cite in dependency inventories or vulnerability-scan exemptions.
Scaling. Resolution is O(1) against an in-memory config map and effectively free. The real scaling concerns are the ones the bundle likely leaves to the host application, and 1.3.0 touches none of them:
CurrentSite between jobs/requests — the single most likely production bug class in a Laravel port.config:cache; fine for tens of sites, reassess for hundreds.Failure modes to design against explicitly:
route()/url() emitting another site's domain, typically surfacing in emails and sitemaps. Test it.Ramp-up. Marginally improved. A Symfony-fluent engineer reads the 1.3.0 code in half a day, helped by PHPStan-passing, deprecation-cleaned, Symfony 7-era idioms. A Laravel-only team still spends 1–2 days mapping bundle conventions onto service-provider idioms before being productive. Keep the concept briefing short and the policy decisions long: the effort is not understanding the code but settling unknown-host behavior, per-site cache/session scoping, and where site context must be threaded through. Those are product-facing decisions and should be settled before the port begins, not discovered during it.
Recommendation — unchanged. Do not adopt. Use 1.3.0 as a design reference for a small, owned Laravel implementation, contingent on validating that per-site configuration divergence is a real requirement rather than a multi-domain routing need Laravel already satisfies. The release reduces the "dead upstream" concern but does not change a single line of the integration calculus: it is a Symfony bundle, we are a Laravel shop, and the port was always the plan.
How can I help you explore Laravel packages today?