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

Query Bus Laravel Package

gnugat/query-bus

A lightweight query bus for PHP that dispatches queries to dedicated handlers, helping decouple read operations from application code. Includes middleware support for composing cross-cutting concerns around query execution.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit This is a CQRS-style read-side package: a QueryBus dispatches a query object to the single QueryMatcher that claims to handle it. That maps cleanly onto Laravel's service-container idiom (bindings, AppServiceProvider registration, constructor injection), so it fits the framework's conventions rather than fighting them. It is a narrow, single-responsibility library — it does not impose a persistence layer, HTTP layer, or DTO contract beyond the query/matcher pairing. That is good for adoption: it can be introduced in one bounded context without a rewrite of controllers or models.

The v1.0.0 content is thin but substantive: matcher resolution logic plus explicit prioritization at registration time. Prioritization is the architecturally interesting part. It implies overlapping matchers are expected — multiple matchers may match a query, and the highest-priority one wins. That is a deliberate escape hatch (e.g. tenant-specific overrides, feature-flagged read paths, test doubles replacing production matchers), and it is also the package's main architectural hazard, because resolution order becomes implicit behavior encoded in registration order.

Integration feasibility Low-to-moderate. The surface area is small: register matchers in a service provider, inject QueryBus where needed. There is no stated dependency on queues, caching, or a specific Laravel major version, so a spike should be a day or two of work, not a sprint. The genuine cost is not wiring — it is the decision about where queries live and whether the team accepts query objects as a first-class concept. That is an organizational decision, not a technical one.

Technical risk

  • Prioritization semantics are unspecified in the notes. Is priority an integer, a registration-order tiebreak, or first-match-wins? What happens on equal priority, or when two matchers claim the same query class? Silent last-writer-wins would be a production footgun. This is the top item to verify.
  • No match behavior is undocumented. Does an unrouted query throw, return null, or fail late? Fail-fast is strongly preferred; silent nulls will surface as confusing bugs far from the cause.
  • v1.0.0 with a two-bullet changelog suggests limited production mileage. There is no visible evidence of maturity signals: test coverage, static analysis level, CI matrix across Laravel/PHP versions, changelog history, issue-tracker responsiveness.
  • Bus-as-service-locator risk. Teams new to CQRS frequently over-apply it, wrapping every read in a query object and adding indirection with no payoff. Governance risk exceeds technical risk here.
  • Debugging opacity. Dispatch indirection makes stack traces less direct; without logging of "query → resolved matcher → priority," production diagnosis gets slower.

Key questions

  1. What are the exact priority semantics, and is there a documented tiebreak rule?
  2. Does the bus throw a typed exception on unmatched queries? Is it catchable and distinguishable?
  3. Is there compile-time or boot-time validation that exactly one matcher resolves per query (or is that left to runtime)?
  4. What Laravel and PHP versions are supported, and is there a CI matrix proving it?
  5. Test coverage level, static analysis baseline, and open-issue count?
  6. Does it support middleware/decorators on the bus (logging, timing, caching) — or would we have to fork to add them?
  7. License and maintainer count/bus factor?

Integration Approach

Stack fit Strong fit for a Laravel monolith or modular monolith that already leans on the container. It is framework-native and additive — no database driver, no queue backend, no new infrastructure. It is a poor fit for teams with no CQRS vocabulary, or for codebases where read logic is already well-factored into repositories/services; there, it adds a layer without removing one.

Migration path Strangler-fig, one read path at a time. Do not convert existing controllers wholesale. Pick a low-traffic, well-understood read endpoint, introduce the query + matcher, route it through the bus, and leave the rest of the app untouched. The package's minimalism makes it easy to remove later if the experiment fails — a genuine advantage over heavier CQRS frameworks.

Compatibility Unverified from the release notes. Confirm supported Laravel/PHP ranges against our current runtime before committing; confirm whether a major-version bump of Laravel is likely to strand us. Pin the version explicitly and avoid ^ ranges until the project demonstrates a stable release cadence.

Sequencing

  1. Spike (1 day): prove dispatch, matcher resolution, unmatched-query behavior, and priority collision behavior in a throwaway branch. Write down observed semantics — do not trust the README.
  2. Characterization tests: encode the resolution rules as our own tests so a future upstream change to priority handling fails loudly in our suite.
  3. Pilot one read path in production behind a normal deploy (no flag needed — the change is internal).
  4. Establish a registration convention: a single QueryServiceProvider, matchers registered in one place, priorities explicit and commented where non-obvious. Forbid priority-by-registration-order in code review.
  5. Logging hook: capture query class and resolved matcher at dispatch, at least at debug level, before broad rollout.
  6. Expand to further read paths only after the pilot has run a full release cycle.

Operational Impact

Maintenance Low ongoing surface area — one dependency, no runtime services, no schema. The burden is code hygiene: registrations accumulate, and priority annotations rot. Budget a standing convention (one registration file, explicit priorities) or the bus will slowly become unpredictable. Monitor upstream release frequency and responsiveness; a v1.0.0 package with a two-line changelog has not yet demonstrated a maintenance cadence.

Support External support is uncertain and probably thin — likely a single maintainer. Internal mitigation: keep the integration thin enough that we could vendor or replace the package in under a week. Concretely, wrap dispatch behind our own narrow interface so call sites never depend on package classes directly. That one indirection is worth the cost here.

Scaling Runtime scaling is a non-issue — dispatch is in-process method resolution, negligible versus I/O. The scaling concern is cognitive and organizational: as matchers multiply, reasoning about "which matcher will handle this query" gets harder. Priority is a tool that helps at low counts and hurts at high counts. Keep the matcher count per bounded context small and treat priority collisions as a design smell, not a feature.

Failure modes

  • Ambiguous resolution — two matchers claim a query; wrong one wins silently. Highest-severity risk. Mitigate with a startup assertion if the package permits, otherwise a test that enumerates queries and asserts a single resolution.
  • Unmatched query — silent null propagates into a view/response as an empty result rather than an error. Verify and, if silent, add a fail-fast wrapper.
  • Priority inversion after refactor — a registration reorder changes behavior with no diff at the call site. Mitigate by explicit priorities and a test that pins expected matcher per query.
  • Package abandonment — mitigate via the dispatch wrapper described above.
  • Debugging friction — mitigated by dispatch logging.

Ramp-up Low for anyone fluent in Laravel DI: a competent mid-level engineer should be productive in half a day. The real ramp-up cost is conceptual — teaching the team when not to introduce a query. Pair the technical onboarding with a short written guideline covering: what belongs in a query (a read intent, not a command), when to skip the bus (trivial one-line reads), and how priorities are assigned and reviewed. Without that, expect six weeks to sprawl into wrapping every model access, at which point the abstraction is costing more than it returns.

Recommendation: Proceed to a one-day spike, contingent on answering questions 1, 2, and 4. Do not adopt broadly until priority and unmatched-query semantics are pinned by our own tests.

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.
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk