culturegr/custom-relation
Easily define custom relationships between Eloquent models, like connecting users to permissions through roles. Includes an Artisan generator and full support for eager-loading, making complex multi-table joins clean and reusable.
hasManyThrough, a manual join in a repository method, or adopting a full permissions package. This package is a fourth, lighter option: keep Eloquent semantics, no new data model, no vendor lock-in — but accept that you own the join logic.CustomRelation classes and the existing code still works.whereHas, withCount, constrained eager loading, or paginated relation results, this tool is off the table and the roadmap must budget for a proper query layer or a vendor permissions package instead.NOASSERTION, the product plan must place legal clearance before engineering spikes. This is a real calendar dependency, not a formality, and should be tracked as such.Consider it when:
hasManyThrough and pivot belongsToMany cannot express cleanly — the README's User → Role → Permission ACL traversal is the canonical case.addEagerConstraints / match implementation rather than cargo-culting the README.Look elsewhere when:
whereHas, has, withCount, constrained with(['x' => fn ($q) => ...]), or pagination. These are unsupported or untested, and this is the most likely path from "nice idea" to "rewrite."hasManyThrough/pivot relations rather than covering the residue they cannot express.match() implementation (per-parent filtering over a fully hydrated collection) would be O(parents × results) in PHP.To executives: This is a small, cheap, reversible tool that lets us ship "who can see what" features without buying or building a permissions platform. It costs a day to evaluate and can be removed model-by-model if it disappoints. Two caveats need executive awareness: the open-source license is currently ambiguous and must clear legal before we use it, and the project is maintained by effectively one person with no support guarantee — so we should only adopt it with a named owner for a fallback fork. Total exposure is low because the package is a thin convention layer, not infrastructure.
To engineering: It fills a real gap — relationships requiring a multi-hop join with bespoke filtering that Eloquent's native relations cannot express. Integration is a trait on one model plus one class per relation, with full eager-loading support and an Artisan generator. The trade-offs are explicit: no whereHas, withCount, or constrained eager loading; the README's match() example is a performance and correctness hazard if copied verbatim, so we write and review our own reference implementation; and it hooks Laravel's internal relation lifecycle, which is stable but not a public contract. Proposed plan: legal clearance first, then a one-relation spike on a single model, route only new call sites through it, and prove equivalence against the existing query with a fixed fixture set before replacing anything. Pin the version, commit the lockfile, and add it to the framework-upgrade checklist.
How can I help you explore Laravel packages today?