staudenmeir/eloquent-has-many-deep
Extended HasManyThrough for Laravel 5.5+ lets you define relationships with unlimited intermediate models, supporting many-to-many, polymorphic, and combined relationship types. Define deep relationships by concatenating existing ones or specifying keys manually; includes third-party package support...
Country → User → Post → Comment) without denormalizing tables or hand-writing joins. That removes a false trade-off between "clean schema" and "cheap reads," and lets us defer — or skip — a data-model migration project.User → Role → Permission), and multi-tenant scoping all depend on multi-hop traversal. This package turns those from custom query-layer tickets into one relationship method, which directly shrinks estimate size and scope.hasManyDeepFromRelations) or declared manually with explicit keys, we can ship a nested-data feature without first refactoring the models. That decouples feature delivery from platform cleanup.Adopt when:
whereHas, withCount, constraints), not just as a one-off report.MorphMany, MorphToMany, MorphedByMany, BelongsTo — or crosses third-party relationships (compoships, adjacency-list trees/graphs, JSON relations).WithConstraints variant).HasOneDeep semantics (e.g., "latest comment") without a separate query.Look elsewhere when:
hasManyThrough is sufficient and adds no dependency.dependents: 0 signal in our data should be verified against Packagist before we treat adoption breadth as evidence; do not cite it as social proof. Mitigate by pinning a version and keeping usage behind relationship methods so removal is a contained change.For executives (one paragraph): We can deliver a class of nested-data features — rollups, inherited permissions, cross-entity activity views — without a schema migration or a new internal query library. This is a free, MIT-licensed, widely used Laravel package that slots into our existing models with a one-line install and a few lines per relationship. It is low-commitment: it touches how we read data, not how we store it, and it can be removed with contained effort. The main risk is that it is maintained by a single author, so we will pin the version and isolate usage. Recommendation: pilot it on one feature, measure query cost, then standardize.
For engineering: Add staudenmeir/eloquent-has-many-deep via Composer and use the HasRelationships trait. Two modes: concatenate existing relationships (hasManyDeepFromRelations, with a WithConstraints variant if you need the intermediate where/withTrashed clauses carried through — and qualify column names, since they will now be ambiguous), or declare manually with explicit intermediate models, foreign keys, and local keys, using null placeholders for convention defaults. Pivot tables go in the intermediate array for many-to-many; polymorphic keys are arrays starting with the *_type column; swap foreign/local keys on the right side of a pivot; swap them for BelongsTo hops. It supports eager loading, intermediate/pivot data and constraints, table aliases, soft deletes, unique results, and relationship reversal, and is kept at PHPStan level 10 with CI coverage. The version matrix is documented per Laravel major, so pin to the matching release. Caveat to design around: each deep relationship is a multi-join query — benchmark it on the largest tables and keep the longest chains off hot list endpoints.
How can I help you explore Laravel packages today?