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 Bundle Laravel Package

studiomado/query-bundle

Query Bundle is a Laravel package for building reusable, composable Eloquent queries. It helps move complex filtering, sorting, and data retrieval logic into dedicated query classes, keeping controllers and models cleaner and making database queries easier to maintain and test.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin. composer require studiomado/query-bundle — but read composer.json in the repo before you run it. The last tagged release is from October 2022 and it has zero dependents on Packagist, so the illuminate/* and php constraints were written for the Laravel 9 era. If you're on Laravel 10/11 you'll likely get a dependency-resolution failure; decide up front whether you'll use --with-all-dependencies, a dev-main constraint, or a fork.

Where to look first, in order:

  1. tests/ — with 13 stars there is effectively no tutorial ecosystem, and the test suite is the real documentation. It shows the intended call order and the shape of the query objects better than the README.
  2. src/ top level — identify the service provider and whether it registers container bindings or publishes a config file. If a config is published, run php artisan vendor:publish --provider="StudioMado\QueryBundle\...ServiceProvider" and read every key before you touch a controller.
  3. The CHANGELOG / git history — for a package this small, the commits tell you what the author actually uses it for and which paths are untested.

First use case. The natural entry point is an index endpoint: take a request with filter, sort, and page parameters, translate it into an Eloquent builder, and return a paginated collection. Do it once, end to end, in a single controller action before you try to abstract anything. Something like:

public function index(IndexUsersRequest $request)
{
    $query = User::query();

    // apply the bundle's query-building step here, based on what src/ exposes
    $users = $query->paginate($request->integer('per_page', 15));

    return UserResource::collection($users);
}

Get that working and covered by a feature test before rolling it out to other endpoints — that test becomes your regression net for every later integration.

Implementation Patterns

Keep the request-to-query translation in one place. The durable pattern with any query-building package is a thin seam: a form request that validates the allowed parameters, and a single class (or base controller method) that consumes the validated array and returns a builder. Controllers stay declarative; the package stays at the edge.

// app/Queries/BuildsIndexQueries.php
trait BuildsIndexQueries
{
    protected function buildQuery(string $model, array $params)
    {
        $query = $model::query();

        // hand off to the bundle here
        return $query;
    }
}

Compose rather than configure. If the bundle exposes discrete steps (filter, sort, include relations, paginate), apply them in a fixed, explicit order in your seam class. Fixed order = predictable SQL = debuggable. Resist the urge to make the order configurable from the request.

Bind it, don't new it. Register the bundle's query/factory classes in a QueryBundleServiceProvider (or your AppServiceProvider) and inject them. When you eventually swap to spatie/laravel-query-builder or hand-rolled scopes — and with a package this quiet, plan for that — you change one binding instead of grepping for constructor calls.

Whitelist aggressively. Whatever the package does with filter[...] or sort= keys, treat the input as hostile. Validate filterable columns and sortable columns against an explicit array in the form request; never let a request key reach orderBy() or whereColumn() unvalidated. This is the single highest-risk integration point.

Test at the HTTP layer. Feature tests that hit the endpoint with a query string and assert the JSON shape are far more valuable than unit tests against the package's internals — you're testing your contract, not theirs, and the tests survive a package replacement. When a test fails and you need the SQL, dump $query->toSql() and $query->getBindings().

Pair it with a resource layer. Return JsonResource collections rather than raw models. Query packages tend to make it easy to expose more than you meant to (especially with eager-loading includes), and a resource class is the cheapest guard against that.

Gotchas and Tips

Maintenance risk is the headline gotcha. Last release 2022-10-04, 13 stars, 0 dependents. That means: no Stack Overflow answers, no blog posts, no third-party bug reports to learn from, and no guarantee of a Laravel 11 fix. Pin the exact version in composer.json, and budget a half-day to vendor it (copy the source into app/Support/QueryBundle under MIT) if your project has a multi-year horizon. Losing the license header is the only real obligation to watch.

Laravel version compatibility. Check illuminate/support and illuminate/database constraints before committing. If they cap below your installed version, composer require fails outright; composer require ... --with-all-dependencies may drag other packages backward, which is usually the wrong trade. Prefer a fork with a widened constraint over downgrading your framework.

Config caching. If the package publishes a config file, remember php artisan config:cache in production. Any values you edit in config/query-bundle.php on a cached deployment will silently do nothing — a classic 20-minute debugging session.

Debugging slow or wrong queries. Register a listener in a local service provider:

DB::listen(fn ($q) => logger($q->sql, $q->bindings));

This is faster than reading the package source to work out what it generated, and it immediately reveals things like N+1s from relation "includes" or an orderBy that got applied twice.

Watch for double application. Query-building packages often auto-apply from the request and letyou call a method manually. If you call both, you get duplicate WHERE clauses that still return correct-looking results — until pagination counts go wrong. Assert on toSql() in a test if counts ever look off.

Extension points to know. The service provider's bindings and any Macroable traits are your escape hatches. Before patching the package for a one-off need, check whether the class is bound in the container — you can often $this->app->bind(Original::class, MySubclass::class) and override a single method without forking.

Don't let it leak into your domain. Keep the package's types out of your models, actions, and jobs. The seam class described above is the whole point: with a package that has no public roadmap, the ability to delete it in an afternoon is worth more than any convenience it offers on day one.

Sanity-check the security posture yourself. Grep the source for orderBy, whereRaw, selectRaw, and DB::raw and confirm every user-influenced value is either parameter-bound or whitelisted. With no dependents and no CVE history, nobody else has done that audit for you.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle