staudenmeir/laravel-merged-relations
Merge multiple Laravel Eloquent relations into a single relation that can be queried and eager loaded as one. Combine hasMany, belongsToMany, and morph relations into a unified result set, simplifying complex relationship handling in your models.
Architecture fit: This package is a narrow, additive extension to Eloquent's relationship layer — a trait plus a relation-definition method on a model. There is no service provider to register, no config to publish, no migration, no queue, no new runtime component to operate, and no schema change implied. From a TPM's perspective that is the cheapest integration shape available: it cannot force a data-model decision, it adds no new failure domain beyond the SQL it generates, and it is removable by deleting a trait and a method. The scoping judgment that matters is that the value is real but bounded — it merges same-type relations that resolve to the same related model, not arbitrary cross-table queries. So the program question is not "does it fit?" (it fits any Eloquent codebase) but "do we own the specific read problem it solves, on a roadmap timeline?"
Integration feasibility: High. composer require, apply the trait, declare the merged relation — an engineer can complete a spike inside a day, and the documentation is short and example-driven. The highest-value integration is almost always a replacement, not an addition: hand-rolled UNION query-builder code, or several queries merged in PHP, that already mishandles pagination, withCount, or whereHas. Sizing that displacement is the fastest business case a TPM can produce. If the merged relation retires a few hundred lines of fragile custom query code, adoption is close to a no-brainer; if it replaces one clean hasMany, it's unnecessary dependency surface and should be declined.
Technical risk: Low-to-moderate, concentrated almost entirely in coupling to Eloquent internals. The package reaches into Relation, existence-query construction, and relationship query assembly — none of which is covered by Laravel's public API contract. v1.11 is the canonical illustration: a new Laravel major (13) required a compatibility-only patch. That means the package sits inside the blast radius of every Laravel major and must be carried as an explicit line item on the framework-upgrade critical path, not treated as inert vendor code. Secondary risks: single-maintainer concentration (~185 stars, 0 recorded dependents, one known maintainer in the Laravel ecosystem), a niche pattern that yields thin institutional knowledge and no internal peer reviewers, and generated SQL that is more complex than plain relations — so performance must be measured rather than assumed. The failure mode to plan for is not a crash but a silently plausible wrong result set; that is a test-coverage obligation we own, not a library defect.
Key questions:
activities table with this package? If yes, what explicit date or metric reopens that decision, and who owns it?Stack fit: Laravel + PHP, Composer-managed, zero runtime services, no infrastructure to provision. The only meaningful compatibility surface is the Laravel version constraint; package-to-package conflict risk is negligible. It coexists cleanly with other Eloquent extensions, which matters if we already consume sibling Staudenmeir utilities — that consolidates into one maintainer relationship and one upgrade cadence to track rather than several.
Migration path: Treat as greenfield with no prior state to reconcile. Sequence: (1) composer require staudenmeir/laravel-merged-relations; (2) apply the trait to a single model with a genuine multi-source read requirement; (3) port one existing hand-written union or in-PHP merge into a declarative merged relation and diff the generated SQL against the incumbent implementation. Constrain to ^1.11 only if Laravel 13 is actually in scope; otherwise pin to the release matching the framework we run today.
Compatibility: v1.11 is a constraint-widening patch — no API changes, no deprecations, no behavioral change — the lowest-risk class of release that exists. Two gates before adoption, both checklist items rather than research projects: confirm the rest of the dependency tree is Laravel 13-ready (the package being ready does not make the stack ready), and verify the PHP floor implied by Laravel 13 against our runtime images.
Sequencing:
EXPLAIN on production-sized data.withCount, whereHas) before any wider rollout — this is the guardrail against silent wrong-SQL.Maintenance: Our in-repo footprint is trivial — a trait and a handful of relation definitions. The real burden is external and predictable: expect a version bump to be required with each Laravel major. Budget that explicitly in upgrade planning instead of carrying it as zero cost. Pin the minor version, upgrade deliberately, and keep the package's release notes in the same review as framework-version changes so the coupling is visible to whoever owns the upgrade.
Support: There is no vendor support contract and one maintainer. The mitigation is structural, not contractual: isolate the package behind an internal interface, keep constituent relations clean and independently usable, and document why each merged relation exists and what it replaced. Without that note, a future maintainer cannot tell whether the merged relation is load-bearing or vestigial and will not know if it is safe to delete. Where the same read requirement could be met by a database view or an existing search index, prefer the option the team already operates — every additional moving part is support surface we fund forever.
Scaling: Behavior under load is a function of the SQL generated, not the package's execution model, so scaling risk is measurable rather than speculative. Establish a baseline query plan on production-sized data during the spike, then watch high-traffic merged relations for N+1s and plan regressions as data grows. Set a threshold in advance — query latency or row count — at which the read path moves to a database view, materialized table, or search index. If sources ever span multiple database connections or non-relational stores, this package is the wrong tool and the merge belongs upstream in a search index or warehouse; capture that as a stated boundary now so it isn't rediscovered under pressure.
Failure modes: Rank them by likelihood-times-detection-difficulty, and note that only one of the three is genuinely dangerous.
Ramp-up: The package itself has a shallow learning curve — one trait, one method, standard relations — and an engineer can be productive in an afternoon. The genuine ramp-up cost is organizational: institutional knowledge on merged-relation patterns will be thin, so designate one or two owners, require a short written rationale for each merged relation, and add a README note on the wrapper convention. Assume a one-day spike plus tests for the first integration and a per-model review cadence thereafter; that is the realistic envelope to carry into planning, not a program of work.
How can I help you explore Laravel packages today?