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 Eloquent Filter Laravel Package

mnabialek/laravel-eloquent-filter

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require mnabialek/laravel-eloquent-filter
    

    Publish the config (if extending defaults):

    php artisan vendor:publish --provider="Mnabialek\EloquentFilter\FilterServiceProvider"
    
  2. First Filter Class: Create a filter for your model (e.g., app/Filters/UserFilter.php):

    namespace App\Filters;
    
    use Mnabialek\EloquentFilter\Filter;
    
    class UserFilter extends Filter
    {
        protected $safeFields = ['name', 'email', 'active', 'role_id'];
    
        public function apply($query)
        {
            if ($this->has('name')) {
                $query->where('name', 'like', '%' . $this->get('name') . '%');
            }
    
            if ($this->has('active')) {
                $query->where('active', $this->get('active'));
            }
    
            if ($this->has('role_id')) {
                $query->where('role_id', $this->get('role_id'));
            }
        }
    }
    
  3. First Controller Usage:

    use App\Filters\UserFilter;
    
    public function index(Request $request)
    {
        $filter = new UserFilter($request->query());
        $users = User::query()->filter($filter)->get();
        return response()->json($users);
    }
    
  4. First API Endpoint: Test with:

    GET /users?name=John&active=true
    

Implementation Patterns

Core Usage Patterns

  1. Request Validation Integration: Combine with Laravel’s validation for security:

    public function index(Request $request)
    {
        $validated = $request->validate([
            'name' => 'sometimes|string|max:255',
            'active' => 'sometimes|boolean',
        ]);
    
        $filter = new UserFilter($validated);
        return User::filter($filter)->paginate(10);
    }
    
  2. Dynamic Filter Chaining: Build complex queries incrementally:

    $query = User::query();
    $query->filter(new UserFilter($request->all()))
          ->when($request->has('department'), function ($q) use ($request) {
              return $q->where('department_id', $request->department);
          });
    
  3. Filter Traits for DRY Code:

    trait Filterable
    {
        public function scopeFilter($query, Filter $filter)
        {
            return $filter->apply($query);
        }
    }
    

    Apply to your model:

    use App\Traits\Filterable;
    
    class User extends Model
    {
        use Filterable;
    }
    
  4. Filter Groups: Organize filters by feature (e.g., AdminFilters, PublicFilters):

    namespace App\Filters\Admin;
    
    class AdminUserFilter extends \Mnabialek\EloquentFilter\Filter
    {
        // ...
    }
    

Advanced Patterns

  1. Filter Caching: Cache frequent filter combinations:

    $cacheKey = md5(serialize($request->all()));
    $users = Cache::remember($cacheKey, now()->addHours(1), function () use ($filter) {
        return User::filter($filter)->get();
    });
    
  2. Filter Events: Dispatch events for filter application:

    public function apply($query)
    {
        event(new FilterApplied($this, $query));
        // ...
    }
    
  3. Filter Middleware: Centralize filter logic:

    public function handle($request, Closure $next)
    {
        $request->merge(['filters' => new UserFilter($request->query())]);
        return $next($request);
    }
    
  4. Filter Testing: Test filters in isolation:

    public function test_active_filter()
    {
        $filter = new UserFilter(['active' => true]);
        $query = User::query()->filter($filter);
        $this->assertEquals('active = ?', $query->toSql());
    }
    

Integration Tips

  1. API Resources: Use filters with API resources:

    public function toArray($request)
    {
        return [
            'data' => User::filter(new UserFilter($request->query()))->get(),
        ];
    }
    
  2. Livewire/Alpine.js: Dynamic filtering in frontend:

    // Livewire
    public $filters = [];
    
    public function applyFilters()
    {
        return User::filter(new UserFilter($this->filters))->get();
    }
    
  3. Scout Integration: Filter search results:

    $search = User::search($query)->filter(new UserFilter($request->query()));
    
  4. Multi-Tenancy: Combine with stancl/tenancy:

    $query = User::forTenant($tenant)->filter(new UserFilter($request->query()));
    

Gotchas and Tips

Common Pitfalls

  1. SQL Injection Risks:

    • Issue: Dynamic column names can expose SQL injection if not sanitized.
    • Fix: Always whitelist safe fields:
      protected $safeFields = ['name', 'email']; // Only allow these columns
      
  2. N+1 Query Problem:

    • Issue: Filters on relationships without with().
    • Fix: Eager load relationships:
      User::with('posts')->filter($filter)->get();
      
  3. Case Sensitivity:

    • Issue: like queries may fail due to collation.
    • Fix: Use LOWER() or ILIKE:
      $query->whereRaw('LOWER(name) LIKE LOWER(?)', ['%' . $this->get('name') . '%']);
      
  4. Boolean Parsing:

    • Issue: 'true' vs. true in requests.
    • Fix: Normalize inputs:
      $active = in_array(strtolower($this->get('active')), ['1', 'true', 'yes']);
      
  5. Pagination Conflicts:

    • Issue: Filters breaking pagination.
    • Fix: Apply filters before pagination:
      User::filter($filter)->paginate(10);
      

Debugging Tips

  1. Query Logging: Enable query logging to inspect generated SQL:

    DB::enableQueryLog();
    User::filter($filter)->get();
    dd(DB::getQueryLog());
    
  2. Filter Dumping: Debug filter inputs:

    dd($filter->getAll());
    
  3. Step-by-Step Query Building: Build queries incrementally to isolate issues:

    $query = User::query();
    if ($filter->has('name')) {
        $query->where('name', 'like', '%' . $filter->get('name') . '%');
        dd($query->toSql()); // Check SQL
    }
    

Configuration Quirks

  1. Safe Fields:

    • Override $safeFields to restrict filterable columns.
    • Example:
      protected $safeFields = ['id', 'name', 'created_at'];
      
  2. Default Values:

    • Set defaults in the filter:
      public function __construct(array $data = [])
      {
          $this->defaults = [
              'per_page' => 15,
              'sort' => 'name',
          ];
          parent::__construct($data);
      }
      
  3. Custom Operators:

    • Extend supported operators:
      public function apply($query)
      {
          if ($this->has('created_after')) {
              $query->where('created_at', '>', $this->get('created_after'));
          }
      }
      

Extension Points

  1. Custom Filter Classes: Extend Filter for reusable logic:

    class DateFilter extends Filter
    {
        public function apply($query)
        {
            if ($this->has('after')) {
                $query->where('created_at', '>', $this->get('after'));
            }
        }
    }
    
  2. Filter Macros: Add global filter methods:

    Filter::macro('scopeActive', function ($query) {
        return $query->where('active', true);
    });
    
  3. Filter Events: Listen for filter application:

    Filter::listen('applying', function ($filter, $query) {
        // Log or modify query
    });
    
  4. Filter Middleware: Centralize filter logic:

    public function handle($request, Closure $next)
    {
        $request->merge(['filters' => new UserFilter($request->query())]);
        return $next($request);
    }
    

Performance Tips

  1. Index Filtered Columns: Ensure filtered columns are indexed:

    CREATE INDEX idx_users_name ON users(name);
    
  2. **Limit Filter

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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor