Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Eloquent Power Joins Laravel Package

kirschbaum-development/eloquent-power-joins

Eloquent Power Joins brings Laravel's magic to joins: define joins using your relationship methods, use model scopes in any context, query relationship existence via joins instead of where exists, and sort by related columns or aggregates with less code.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Build vs. buy on query-layer plumbing. The core value is not a feature your users see — it's removing a recurring category of hand-written SQL from the codebase. Every join('posts', 'posts.user_id', '=', 'users.id') scattered across controllers and repositories is a place where a relationship change (renamed FK, added polymorphic type, new soft-delete requirement) silently breaks. This package makes joins derive from relationship definitions, so the schema contract lives in one place — the model. That is a maintainability decision you can justify on reduced regression surface, not on lines of code saved.
  • Roadmap input: list/filter/sort features on related data. Features like "sort customers by lifetime value," "sort posts by comment count," "filter orders by shipping city," and "show authors with more than 3 published posts" are all one-liners here (orderByPowerJoinsCount, orderByPowerJoinsAvg, joinRelationship('posts.comments'), powerJoinHas). This directly changes what you can put in a sprint. Requests that previously required a reporting table, a denormalized counter column, or a hand-rolled query builder chain become ticket-sized. Expect a backlog of "nice to have" sorting/filtering asks to become newly cheap — re-triage them.
  • Performance work as a scoped, low-risk initiative. has() / whereHas() compile to where exists, which on large tables with poor index coverage can be markedly slower than a join. powerJoinHas / powerJoinWhereHas give you a drop-in alternative. This is a lever for a specific class of slow endpoint — typically admin panels, exports, and any listing where the correlated subquery is evaluated per row. Frame it as an option, not a default: it is a targeted optimization, not a global policy.
  • Reporting and admin surfaces specifically. The alias support (joinRelationshipUsingAlias, ->as('alias')) exists because you need to join the same table twice — exactly the shape of reporting queries (category + parent category, assignee + reporter, billing + shipping address). Without aliasing, engineers either write raw SQL or duplicate models. This is where the package earns its keep fastest.
  • Deciding where not to invest. If your team's reporting needs are genuinely analytical (multi-dimensional aggregation, wide date ranges, cross-domain joins), do not stretch Eloquent for it. The honest PM decision is: use this package for app-level listing/sorting/filtering, and budget a real warehouse/read-model for analytics. The package makes Eloquent better at what it does; it does not turn Eloquent into a BI tool.
  • Hiring and onboarding signal (small but real). ~1,570 GitHub stars, MIT license, Composer-installable, active Laravel 11/12/13 support, and a sponsor with a public blog post explaining the problem. That is a low-friction addition for a Laravel team — a new hire who knows Eloquent can read User::joinRelationship('posts.comments') on day one. Compare against a bespoke query-builder abstraction that only your two senior engineers understand.

When to Consider This Package

Adopt when:

  • You are on a supported Laravel version (11.x / 12.x / 13.x per the badge; older majors require pinned versions — 3.* for Laravel < 10, 2.* for < 8). Confirm your actual version before committing; this is the first gate.
  • Your product has meaningful relational list, sort, and filter surface: admin dashboards, internal tools, exports, search results, API index endpoints. If a nontrivial share of your controllers contain hand-written ->join(...) chains against related tables, the payoff is immediate.
  • You have polymorphic relationships you join against. The automatic imageable_type condition is a correctness feature, not a convenience one — hand-written polymorphic joins are a classic source of silent duplicate-row bugs.
  • You rely on SoftDeletes. Auto-applied deleted_at is null on every join removes a whole class of "why is this count wrong" tickets.
  • You have slow endpoints where whereHas is the suspected culprit and a join is semantically acceptable. Prototype one endpoint, measure, decide.
  • Your team is Laravel-fluent and already reasons in relationships and scopes. The learning curve is close to zero; scopes usable inside join callbacks is the feature most likely to change how your engineers write queries.

Look elsewhere, or do not adopt, when:

  • Your engineers cannot articulate the difference between where exists and join semantics. The package documentation is explicit about this: results will not always match has()/whereHas(), because a join multiplies parent rows per child. If you sort or paginate on a joined one-to-many, you need distinct or grouping, and pagination counts can shift. This is a real footgun and it is a knowledge problem, not a library problem. Do not hand this to a team that will treat powerJoinHas as a literal rename for has.
  • You need raw SQL portability or a query abstraction that outlives Laravel. This is deeply Eloquent-coupled by design.
  • You want it to fix N+1. It does not. Eager loading (with()) is still the answer for hydration; this package is about filtering and sorting in the database. Conflating the two will produce a bad rollout.
  • MorphTo joins are central to your model. Only one morphable type per query is supported. If you need to join across multiple morph targets in one result set, this will not carry you — plan a union or separate queries.
  • Your models carry heavy global scopes. They are opt-in (withGlobalScopes()), and scopes cannot type-hint Eloquent\Builder in apply() or you get errors. Audit your scope definitions before rollout; this is the most likely source of a surprise.
  • You need vendor-backed SLAs or a commercial support contract. MIT, one primary maintainer, sponsor-funded. There is no support agreement to point at in a procurement review. Mitigate by pinning versions and treating it as an easily-replaceable dependency (it is — the fallback is hand-written joins).
  • You are pre-product-market-fit with unstable schema. The whole premise is that relationships are stable enough to be the source of truth. If your data model churns weekly, the abstraction buys you less.

Note on the "0 dependents" figure. Treat that as a data artifact rather than a signal — a package with this download volume and star count in the Laravel ecosystem is not actually unused. Do not let that number drive a rejection; validate against Packagist download counts and your own spike instead.

How to Pitch It (Stakeholders)

To executives (one paragraph): We can cut a recurring class of database query code out of our Laravel application by adopting a small, free, open-source package. It lets engineers express joins through the model relationships we already maintain, instead of hand-writing SQL table names and foreign keys in every controller. Practically, this means: fewer production bugs when schema changes, faster delivery on the "sort and filter by related data" requests that keep landing in the backlog, and a targeted fix available for slow admin and reporting screens currently using a less efficient query pattern. Cost is a Composer dependency and roughly one sprint of adoption work; risk is contained because the fallback is the code we already write today, and it is MIT-licensed with no vendor lock-in.

To engineering leadership: This is a developer-experience and correctness play, not an architecture change. It replaces error-prone manual join construction with relationship-derived joins — including automatic polymorphic type conditions, automatic soft-delete handling, and support for relationship-level constraints. It also exposes a join-based alternative to whereHas for the specific slow queries where correlated subqueries underperform, plus first-class ordering by related columns and aggregates (COUNT/SUM/AVG/MIN/MAX), which currently require bespoke query builder code. Notable constraints to plan around: join semantics differ from where exists (row multiplication, so distinct/grouping discipline is required), MorphTo supports one morphable type per query, global scopes are opt-in and cannot type-hint Eloquent\Builder, and the package targets Laravel 11/12/13 (pinned majors for older versions). None of these are blockers; all of them are things a short internal style note resolves.

To engineering (the honest version): It will make the common case dramatically more readable — User::joinRelationship('posts.comments') instead of a two-table join chain — and it will let you call model scopes inside join callbacks, which is the feature you'll actually reach for. It will not save you from thinking about whether a join is the right tool. If you join a hasMany and paginate, you own the duplicate-row consequences. Adopt it deliberately in one area first — I'd suggest a single reporting or admin surface where the query is already complex — and let the pattern spread from a working example rather than a mandate.

Suggested adoption motion: Spike one slow or gnarly endpoint (one that already joins two-plus tables, or joins the same table twice and needs an alias). Measure before/after on query time and code volume. If it lands, write a two-paragraph internal convention covering join-vs-where exists semantics and global-scope type-hinting, then open it up. Re-review the backlog afterward — several deferred "sort by related field" items likely just became cheap.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console