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

Filterable Laravel Package

jerome/filterable

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require jerome/filterable

Publish the config (if needed):

php artisan vendor:publish --provider="Filterable\FilterableServiceProvider"
  1. First Use Case: Create a filter for a model (e.g., UserFilter):

    php artisan make:filter UserFilter --model=User
    

    This generates a stub in app/Filters/UserFilter.php.

  2. Apply to a Controller:

    use Filterable\Filterable;
    use App\Filters\UserFilter;
    
    class UserController extends Controller
    {
        use Filterable;
    
        public function index(UserFilter $filter)
        {
            $users = $filter->apply($this->userRepository->all());
            return response()->json($users);
        }
    }
    
  3. Test with API Request: Send a request with query params like:

    /users?name=John&status=active
    

    The package automatically maps these to filter methods.


Implementation Patterns

Core Workflow

  1. Define Filters: Extend Filterable\Filter and use traits like Filterable\Concerns\FiltersByRequest:

    namespace App\Filters;
    
    use Filterable\Filter;
    use Filterable\Concerns\FiltersByRequest;
    
    class UserFilter extends Filter
    {
        use FiltersByRequest;
    
        protected $model = User::class;
    
        public function name($query, $name)
        {
            return $query->where('name', 'like', "%{$name}%");
        }
    
        public function status($query, $status)
        {
            return $query->where('status', $status);
        }
    }
    
  2. Dependency Injection: Laravel’s DI container resolves filters automatically. No manual instantiation needed.

  3. Caching Strategies: Enable caching in config/filterable.php:

    'cache' => [
        'enabled' => true,
        'driver' => 'redis',
        'prefix' => 'filterable_',
    ],
    

    Use Cacheable trait for automatic caching:

    use Filterable\Concerns\Cacheable;
    
    class UserFilter extends Filter
    {
        use Cacheable;
    }
    
  4. Complex Queries: Chain filters or use closures:

    public function activeAndRecent($query)
    {
        return $query->where('active', true)
                    ->where('created_at', '>', now()->subDays(30));
    }
    
  5. API Integration: Use Filterable\Concerns\ValidatesRequests to validate input:

    use Filterable\Concerns\ValidatesRequests;
    
    class UserFilter extends Filter
    {
        use ValidatesRequests;
    
        protected $rules = [
            'status' => 'in:active,inactive,pending',
        ];
    }
    

Gotchas and Tips

Common Pitfalls

  1. Cache Key Collisions:

    • Ensure getCacheKey() in your filter returns unique keys for different query combinations.
    • Default implementation uses md5(request()->getQueryString()), but override if needed:
      public function getCacheKey()
      {
          return md5($this->request->name . $this->request->status);
      }
      
  2. Performance with Large Datasets:

    • Disable caching for complex queries:
      public function apply($query)
      {
          $this->disableCache();
          return parent::apply($query);
      }
      
    • Use OptimizesQueries trait to add select() or with() optimizations:
      use Filterable\Concerns\OptimizesQueries;
      
      class UserFilter extends Filter
      {
          use OptimizesQueries;
      
          protected $alwaysSelect = ['id', 'name', 'email'];
      }
      
  3. Request Binding Issues:

    • Ensure filter methods match request keys exactly (case-sensitive).
    • Use snake_case for request keys if your model uses snake_case attributes.
  4. Testing Quirks:

    • Mock the request object in tests:
      $filter = new UserFilter($this->app->make(Request::class));
      $filter->setRequest(['name' => 'John']);
      
    • Use getAppliedQuery() to inspect the built query:
      $query = $filter->getAppliedQuery();
      $this->assertEquals('select * from users where name like ?', $query->toSql());
      

Pro Tips

  1. Dynamic Filter Methods: Dynamically generate filter methods based on request data:

    use Filterable\Concerns\DynamicallyFilters;
    
    class UserFilter extends Filter
    {
        use DynamicallyFilters;
    
        protected $dynamicFilters = ['meta_*'];
    }
    

    This will auto-generate methods for meta_age, meta_city, etc.

  2. Rate Limiting: Combine with Filterable\Concerns\RateLimitsFilters to throttle filter usage:

    use Filterable\Concerns\RateLimitsFilters;
    
    class UserFilter extends Filter
    {
        use RateLimitsFilters;
    
        protected $maxAttempts = 10;
        protected $decayMinutes = 1;
    }
    
  3. Custom Validation: Extend validation rules dynamically:

    protected function getRules()
    {
        $rules = $this->defaultRules;
        if ($this->request->has('advanced')) {
            $rules['status'] = 'required|in:active,inactive,pending,suspended';
        }
        return $rules;
    }
    
  4. Debugging: Enable query logging in config/filterable.php:

    'debug' => [
        'log_queries' => true,
        'log_path' => storage_path('logs/filterable.log'),
    ],
    

    View logs at storage/logs/filterable.log.

  5. Extending the Package:

    • Add custom traits under app/Filterable/Concerns/.
    • Override the service provider to bind custom filters:
      $this->app->bind(UserFilter::class, function ($app) {
          return new UserFilter($app->make(Request::class));
      });
      

```markdown
## Extension Points

### Customizing Filter Behavior
1. **Override Default Traits**:
   Replace `FiltersByRequest` with a custom trait to change how requests are parsed:
   ```php
   namespace App\Filterable\Concerns;

   use Filterable\Filter;

   trait CustomFiltersByRequest
   {
       public function handleRequest()
       {
           // Custom logic to parse request
           $this->requestData = $this->parseRequest();
       }
   }
  1. Add New Concerns: Create reusable logic in app/Filterable/Concerns/:

    namespace App\Filterable\Concerns;
    
    trait LogsFilters
    {
        public function apply($query)
        {
            \Log::info('Filter applied: ' . $this->getCacheKey());
            return parent::apply($query);
        }
    }
    
  2. Extend the Generator: Modify the Artisan command stubs in vendor/jerome/filterable/src/Filterable/Console/stubs/ or override them in your project’s app/Filterable/Console/stubs/.

Advanced Integration

  1. GraphQL Support: Use Filterable\Concerns\FiltersGraphQL to integrate with GraphQL queries:

    use Filterable\Concerns\FiltersGraphQL;
    
    class UserFilter extends Filter
    {
        use FiltersGraphQL;
    }
    

    Then resolve filters in your GraphQL resolver:

    $filter = app(UserFilter::class, ['input' => $args['filter']]);
    return $filter->apply(User::query());
    
  2. Livewire/Alpine.js: Bind filters to frontend components:

    // Alpine.js
    document.addEventListener('alpine:init', () => {
        Alpine.data('userFilters', () => ({
            name: '',
            status: '',
            apply() {
                window.location.search = new URLSearchParams({
                    name: this.name,
                    status: this.status
                });
            }
        }));
    });
    
  3. Custom Cache Drivers: Extend the cache logic by binding a custom driver in the service provider:

    $this->app->bind('filterable.cache', function ($app) {
        return new CustomCacheDriver();
    });
    

Testing Extensions

  1. Mocking Filters: Use partial mocks for testing:

    $filter = $this->partialMock(UserFilter::class, ['name', 'status']);
    $filter->shouldReceive('name')->once()->andReturn($query);
    
  2. Testing Cache Behavior: Mock the cache driver in tests:

    $this->app->instance('cache', Mockery::mock('overload', Cache::class));
    $this->app['cache']->shouldReceive('get')->
    
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core