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 Control Model Laravel Package

laravel-expansions/query-control-model

Query Control Model is a Laravel package that adds controllable query behaviour to Eloquent models, letting you define, restrict, and reuse model queries through clean, consistent APIs. It helps keep filtering and data access predictable across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a thin convenience layer over Eloquent's with() and withCount() — it lets you pass relations as a comma-separated string (or array) instead of hand-building arrays everywhere. Start here:

  1. Install and pin the fixed version. The v1.0.2 patch corrects a parsing bug in how with / withCount values were split on commas, so require ^1.0.2 rather than ^1.0.0:
    composer require <vendor>/<package>:"^1.0.2"
    
  2. Read the tests first. With a one-line changelog like this, tests/ is the most trustworthy spec for exactly which input shapes are supported (string with commas, arrays, nested relations, closures).
  3. Check for a config file (config/<package>.php) and publish it only if you need to change defaults: php artisan vendor:publish --tag=<package>-config.
  4. First use case: replacing ad-hoc relation lists in a controller or repository:
    // Before
    Post::with(['author', 'comments'])->withCount(['comments'])->paginate();
    
    // After
    Post::with('author,comments')->withCount('comments')->paginate();
    

The win is small per call site but compounds in codebases where relation lists are assembled from request filters, config, or service parameters.

Implementation Patterns

Prefer arrays for static lists, strings for dynamic ones. Arrays are self-documenting and immune to parsing ambiguity; comma strings shine when the list arrives from a query param, config value, or an admin-editable setting. Keep the string form at the boundary (request/config) and normalize to arrays once.

Normalize once at the edge of your application. Don't scatter string parsing across controllers. A small helper or form request that returns array keeps eager-loading logic testable and makes the v1.0.2 semantics explicit in your own code:

$relations = collect(explode(',', $request->string('include')))
    ->map(fn ($r) => trim($r))
    ->filter()
    ->all();

Post::with($relations)->withCount($countRelations)->paginate();

Use closures for constrained eager loads. These are the case most likely to brush against the comma-parsing fix — a closure body should never be stringified into a relation list:

Post::with(['comments' => fn ($q) => $q->where('approved', true)])
    ->withCount(['comments as approved_comments_count' => fn ($q) => $q->where('approved', true)])
    ->get();

Alias withCount deliberately. withCount('comments as total_comments') produces total_comments in the serialized payload; standardize aliases per resource so API contracts don't drift between endpoints.

Keep it consistent across repositories/API resources. If you adopt the package, adopt it everywhere — mixing raw with([...]) and package string calls in the same layer makes grep-based audits of eager loading much harder.

Pair with pagination and resources. Eager-loaded counts are computed in the same query, so ->withCount(...)->paginate(25) then mapping through an ApiResource is the cleanest path for list endpoints.

Gotchas and Tips

  • The v1.0.2 fix is the headline. In earlier versions, with / withCount values were exploded on commas unconditionally, which was a mistake: any value legitimately containing a comma was silently split into bogus relation names. After upgrading, double-check any call site where you passed a string that contained a comma for a reason other than separating relations — behavior may now differ from what you empirically relied on.
  • Silent failure mode. Eloquent throws RelationNotFoundException on unknown relations, so a mis-split string usually surfaces as a runtime exception rather than a wrong result. If you see a relation name that looks like a fragment of another string, suspect leftover parsing assumptions.
  • Whitespace. 'author, comments' — verify the package trims segments. If it doesn't, ->map('trim') your list before passing it, or you'll get a RelationNotFoundException for ' comments'.
  • Nested relations and dot notation (comments.author) are a separate concern from comma splitting; ensure your own normalization doesn't accidentally split on other delimiters.
  • Duplicates are usually free but not always. Repeating a relation is harmless for with, but duplicate aliases in withCount can produce confusing column names — dedupe your input list.
  • Debugging N+1: DB::listen(), Laravel Telescope, or Model::preventLazyLoading() in non-production will tell you instantly whether the eager load actually happened. A string that parsed to nothing looks identical to a string that worked, until you count queries.
  • Extension point: if the package resolves relations through a macro, trait, or builder mixin, that's where to hook custom normalization (e.g. whitelisting allowed relations from request input). Never pass raw user input into with() without an allow-list — it's an information-disclosure vector.
  • Pin and lockfile-check. Given the changelog is a single vague sentence, treat this as a low-signal patch: confirm composer.lock moved to 1.0.2, run your eager-loading tests, and read the diff of the parsing method before trusting it in a hot path.
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.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc