Weave Code
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 Query Builder Laravel Package

spatie/laravel-query-builder

Build safe, flexible Eloquent queries from incoming API requests. Supports whitelisted filtering (partial/exact/scope/custom), sorting, includes, field selection, pagination, and grouped AND/OR filters—ideal for JSON:API-style endpoints with minimal boilerplate.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Eloquent-Centric: Perfectly aligned with Laravel’s Eloquent ORM, enabling seamless integration into existing query logic. The package abstracts complex query-building logic while maintaining compatibility with Laravel’s query builder.
  • API-First Design: Optimized for API endpoints where dynamic filtering, sorting, and pagination are critical. Follows RESTful conventions (e.g., ?filter[name]=John, ?sort=-created_at).
  • Modularity: Supports granular control via AllowedFilter, AllowedSort, and AllowedInclude, enabling fine-tuned permissions per endpoint or model.
  • Composability: Works alongside Laravel’s built-in scopes, global scopes, and query modifiers (e.g., withTrashed(), whereHas()), reducing duplication.

Integration Feasibility

  • Low Friction: Requires minimal boilerplate—replace static Model::query() with QueryBuilder::for(Model::class) and configure allowed parameters.
  • Backward Compatibility: Non-breaking; existing queries remain functional. Can be incrementally adopted (e.g., start with filtering in one endpoint).
  • Middleware Integration: Easily extendable via Laravel middleware to enforce query constraints (e.g., rate-limiting, authentication-based filtering).
  • Testing: Mockable and testable via Laravel’s HTTP tests (e.g., assertDatabaseCount() with dynamic queries).

Technical Risk

  • Performance Overhead:
    • Dynamic filtering/sorting may introduce N+1 queries if not paired with with() or eager loading.
    • Mitigation: Use allowedIncludes() and with() to preload relationships.
  • Security Risks:
    • Unrestricted allowedFilters/allowedSorts could expose sensitive fields (e.g., password).
    • Mitigation: Validate against a whitelist (e.g., ->allowedFilters(['name', 'email'])).
  • Complexity in Custom Logic:
    • Custom filters/sorts require implementing interfaces (e.g., Sort, Filter).
    • Mitigation: Start with built-in features; extend only when necessary.
  • Version Lock-In:
    • Breaking changes in minor versions (e.g., Laravel 10+ compatibility).
    • Mitigation: Pin versions in composer.json and monitor UPGRADING.md.

Key Questions

  1. Use Case Alignment:
    • Is this primarily for public APIs, admin panels, or internal tools? (Affects security/validation needs.)
  2. Existing Query Complexity:
    • How many custom scopes/relationships exist? Will they conflict with QueryBuilder?
  3. Performance SLAs:
    • Are there baseline query time requirements? (Test with large datasets.)
  4. Team Adoption:
    • Does the team have experience with dynamic query builders? (Training may be needed for custom filters.)
  5. Monitoring:
    • How will invalid queries (e.g., ?sort=password) be logged/handled in production?

Integration Approach

Stack Fit

  • Laravel Ecosystem:
    • Native support for Eloquent, API Resources, and Laravel’s HTTP layer.
    • Integrates with:
      • Laravel Scout: For search-based filtering (e.g., AllowedFilter::scout()).
      • Laravel Nova: Extendable via Nova’s tool integration.
      • Laravel Sanctum/Passport: Secure API endpoints with query constraints.
  • Third-Party Packages:
    • Spatie’s Other Packages: E.g., laravel-permission for role-based filtering.
    • API Tools: Works with tools like Postman or Insomnia for dynamic query testing.

Migration Path

  1. Pilot Endpoint:
    • Start with a low-risk API endpoint (e.g., /api/public/users).
    • Replace static User::query() with QueryBuilder::for(User::class).
    • Example:
      // Before
      return User::where('active', true)->get();
      
      // After
      return QueryBuilder::for(User::class)
          ->allowedFilters(['name', 'role'])
          ->allowedSorts('name', 'created_at')
          ->get();
      
  2. Incremental Rollout:
    • Add filtering/sorting to one parameter group at a time (e.g., first filter, then sort).
    • Use feature flags to toggle QueryBuilder per endpoint.
  3. Middleware Layer:
    • Create middleware to enforce query constraints globally:
      public function handle(Request $request, Closure $next) {
          if ($request->routeIs('admin.*')) {
              $request->merge(['filter[active]' => true]);
          }
          return $next($request);
      }
      
  4. Documentation:
    • Update API docs (e.g., Swagger/OpenAPI) to reflect new query parameters.
    • Example:
      # OpenAPI
      /users:
        get:
          parameters:
            - name: filter[name]
              in: query
              description: Filter by name (partial match)
              required: false
              schema:
                type: string
      

Compatibility

  • Laravel Versions:
    • Tested on Laravel 8+; check UPGRADING.md for version-specific notes.
    • Action: Ensure compatibility with your Laravel version (e.g., PHP 8.1+ features).
  • Database Support:
    • Works with MySQL, PostgreSQL, SQLite, and SQL Server.
    • Caveat: Custom sorts (e.g., LENGTH()) may vary by DB (test with your RDBMS).
  • Caching:
    • Cache invalidation may be needed if queries change frequently (e.g., Cache::remember()).
    • Tip: Use QueryBuilder::cacheFor() for static queries.

Sequencing

  1. Phase 1: Basic Filtering/Sorting
    • Implement allowedFilters/allowedSorts for 2–3 core endpoints.
    • Validate with manual API tests.
  2. Phase 2: Relationships
    • Add allowedIncludes for nested data (e.g., /users?include=posts.comments).
    • Test N+1 query risks.
  3. Phase 3: Advanced Features
    • Custom filters/sorts (e.g., date ranges, complex joins).
    • Integration with search (e.g., Algolia + AllowedFilter::scout()).
  4. Phase 4: Monitoring
    • Log invalid queries (e.g., InvalidSortQuery).
    • Set up alerts for slow queries.

Operational Impact

Maintenance

  • Configuration Drift:
    • Risk: allowedFilters/allowedSorts may diverge across endpoints.
    • Solution: Centralize configurations (e.g., trait or base controller):
      // app/Traits/Queryable.php
      trait Queryable {
          protected function applyQueryBuilder() {
              return QueryBuilder::for($this->model)
                  ->allowedFilters($this->filters)
                  ->allowedSorts($this->sorts);
          }
      }
      
  • Deprecation:
    • Monitor Spatie’s CHANGELOG for breaking changes.
    • Action: Pin versions and set calendar reminders for upgrades.
  • Documentation:
    • Maintain a runbook for common query patterns (e.g., "How to add a date-range filter").

Support

  • Debugging:
    • Use QueryBuilder::toSql() to inspect generated queries:
      $query = QueryBuilder::for(User::class)->allowedFilters(['name']);
      \Log::debug($query->toSql(), $query->getBindings());
      
    • Tool: Laravel Debugbar to visualize query execution.
  • Client-Side Issues:
    • API consumers may misuse query parameters (e.g., ?sort=password).
    • Solution: Return user-friendly errors:
      try {
          return $query->get();
      } catch (InvalidSortQuery $e) {
          return response()->json(['error' => 'Invalid sort: ' . $e->getMessage()], 400);
      }
      
  • Community:
    • Leverage GitHub issues and Spatie’s docs for troubleshooting.

Scaling

  • Performance Bottlenecks:
    • Filtering: Complex LIKE queries or full-text search may slow down under load.
      • Mitigation: Use database indexes (e.g., ALTER TABLE users ADD FULLTEXT(name)).
    • Sorting: Large datasets with ORDER BY on non-indexed columns.
      • Mitigation: Add indexes or use database-specific optimizations (e.g., PostgreSQL’s BRIN indexes).
    • Includes: Deeply nested relationships (posts.comments.author) can bloat queries.
      • Mitigation: Use with() to preload critical paths.
  • Caching Strategies:
    • Cache query results for static parameters:
      return Cache::remember("users_{$request->filter}", now()->addHours(1), function () use ($request) {
          return QueryBuilder::for
      
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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony