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

Laravel Wherehasin Laravel Package

dcat/laravel-wherehasin

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. dcat/laravel-wherehasin is a thin, additive extension to Eloquent's query builder. It registers whereHasIn, orWhereHasIn, and whereDoesntHaveIn macros that rewrite the correlated exists (select ...) clause generated by whereHas into an uncorrelated where <foreign_key> in (select <id> from ... where ...) form. For a TPM, this is attractive because it is a drop-in at the call site: no schema changes, no new services, no changes to models, relationships, or the repository/query-object layer beyond swapping one method name. It sits entirely inside the persistence layer and does not leak into domain code, so it is reversible per call site and can be adopted incrementally.

Integration feasibility. Composer-only install; the only real friction is version compatibility. The package's release history stops at 2021-07-30, and its supported Illuminate range targets Laravel 5.5 through 8.x. On Laravel 9+/PHP 8.1+ installs will either fail dependency resolution or require a fork/ignore-platform-reqs, which is not acceptable for a production dependency. The practical entry criteria are therefore: pin to a specific commit, verify against our exact Laravel/PHP/DB matrix, and be prepared to vendor the ~small source into an internal package regardless.

Technical risk.

  • Correctness risk (highest). The rewrite assumes a simple hasMany/hasOne/belongsTo shape with a single local/foreign key. Polymorphic relations, belongsToMany with pivot tables, custom whereHas closures that reference the parent table, and self-referencing relations with aliases are where IN-subquery rewrites commonly diverge from exists semantics. These divergences produce wrong rows silently, which is a far worse failure mode than a slow query.
  • Performance risk (inverted). The premise that IN (subquery) beats exists is a MySQL-5.x-era generalization. MySQL 8 semi-join and subquery materialization frequently make whereHas equal or better, and a large IN list can regress. Any adoption must be justified by EXPLAIN output on our data, not by the benchmark in the README.
  • Supply-chain risk. Single maintainer, no release in four years, no stated security process, docs primarily in Chinese, and a 0 dependents Packagist signal (likely an undercount, since the Dcat Admin ecosystem pulls it transitively, but still not a reassuring health indicator).
  • Opportunity signal. The 20.18 opportunity score is consistent with the above: this is a narrow, legacy-era micro-optimization, not a platform capability.

Key questions.

  1. Which specific slow queries are we trying to fix, and what does EXPLAIN show for the current whereHas on MySQL 8? If the optimizer already semi-joins, the package buys us nothing.
  2. Do any target relations involve pivots, morphs, or custom keys? If yes, scope them out explicitly.
  3. Are we willing to own an internal fork (patch-level), and who is the named owner?
  4. Is the Laravel version floor satisfiable without ignore-platform-reqs?
  5. Has anyone written a differential test suite proving row-for-row equivalence with whereHas on our schema?

Integration Approach

Stack fit. PHP/Laravel + MySQL. It is compatible with any Laravel app that meets the version constraint and requires no infrastructure, queue, cache, or driver changes. It also composes cleanly with query-object/repository patterns, which is where I would confine it — do not let whereHasIn appear in controllers or ad-hoc scopes.

Migration path. Treat it as a query-level optimization, not a package rollout:

  1. Baseline and capture the slow query log for the top N whereHas call sites.
  2. Vendor a pinned fork into an internal Composer package (acme/laravel-wherehasin) with the Laravel 9+ constraint widened and the macro registration moved to a service provider we control.
  3. Add a differential test harness that runs both whereHas and whereHasIn for each candidate relation and asserts identical ID sets.
  4. Convert call sites one at a time behind the test suite, capturing EXPLAIN before/after.

Compatibility. Restrict supported relation types to simple one-to-one/one-to-many with default keys. Block pivots and morphs at the API level (a wrapper that throws on unsupported relation types is better than a silent wrong result). Verify behavior under withTrashed(), global scopes, and whereHas closures that reference the outer table.

Sequencing. (1) Validate optimizer behavior → (2) fork and widen constraints → (3) differential tests → (4) pilot 3–5 call sites in a non-critical path → (5) measure, then expand or abandon. Budget one sprint; if step 1 shows the MySQL 8 optimizer already handles the target queries, stop and close the evaluation.

Operational Impact

Maintenance. Low code surface, but effectively zero upstream maintenance. Assume we own the fork indefinitely: PHP/Laravel compatibility patches, security review of new macro behavior, and re-validation on every framework major. Cost is small but permanent and must be budgeted, not assumed away.

Support. No commercial support, no SLAs, issue tracker largely dormant and non-English. Internal support burden falls on the backend platform team; document the supported relation matrix so application engineers don't misuse it.

Scaling. Gains are workload-dependent and do not scale predictably: the rewrite helps most where the inner subquery is highly selective and the outer table is large, and can hurt where the IN list is huge or the optimizer would have chosen a semi-join. This is a per-query tuning artifact, not a capacity-planning lever — do not count it toward a scaling roadmap.

Failure modes.

  • Silent incorrect results on unsupported relation shapes — the critical one; mitigate with runtime guards plus differential tests.
  • Performance regression after a MySQL upgrade changes the optimizer plan — mitigate with query-plan assertions in CI for the converted sites.
  • Dependency breakage on a Laravel/PHP upgrade blocking unrelated work — mitigate by forking now rather than at upgrade time.
  • Knowledge loss — the "why" behind each converted call site disappears; require an inline comment linking to the benchmark.

Ramp-up. Near-zero for engineers already fluent in Eloquent; roughly half a day to teach the supported/unsupported relation matrix and the EXPLAIN-first rule. The real ramp-up is on the platform side: whoever owns the fork needs to be comfortable reading the package's small source and Laravel's relationship internals.

Recommendation. Adopt narrowly and conditionally: only if EXPLAIN on MySQL 8 shows a real win for a named set of queries, only behind an internal fork, and only with differential tests in place. If the optimizer baseline already passes, the correct decision is to skip the dependency and instead fix the underlying schema/indexing — which addresses the root cause with no long-term ownership cost.

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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox