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

Query Filter Bundle Laravel Package

bugloos/query-filter-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require bugloos/query-filter-bundle
    

    Add the bundle to your config/bundles.php under Bugloos\QueryFilterBundle\QueryFilterBundle.

  2. First Use Case: Filter a Book entity by title via a query string or array:

    use Bugloos\QueryFilterBundle\QueryFilter;
    
    // In a Symfony controller
    $queryFilter = new QueryFilter($this->getDoctrine()->getManager());
    $books = $queryFilter->filter(
        $this->getDoctrine()->getRepository('App\Entity\Book')->createQueryBuilder('b'),
        $_GET['filter'] ?? []
    )->getQuery()->getResult();
    
  3. Key Files to Review:

    • src/QueryFilter.php: Core logic for filtering.
    • tests/Fixtures/: Example database schema and relations (e.g., Book, Author, Publisher).
    • src/Filter/: Custom filter types (e.g., LikeFilter, InFilter).

Implementation Patterns

1. Basic Filtering

Use the QueryFilter class to apply filters to Eloquent-like queries (Symfony Doctrine QueryBuilder):

$qb = $entityManager->getRepository('App\Entity\Book')->createQueryBuilder('b');
$filteredResults = $queryFilter->filter($qb, [
    'title' => 'Laravel',  // LIKE '%Laravel%'
    'price' => ['>', 20],  // Price > 20
])->getQuery()->getResult();

2. Relation Filtering (2-Level Deep)

Filter nested relations without joins using dot notation:

$filters = [
    'author.name' => 'John',  // Filters Book.author.name
    'publisher.city' => 'Paris',  // Filters Book.publisher.city
];
$queryFilter->filter($qb, $filters);

Under the hood, the bundle uses DISTINCT and IN subqueries for performance.

3. Custom Filter Types

Extend default filters (e.g., LikeFilter, InFilter) for domain-specific logic:

use Bugloos\QueryFilterBundle\Filter\AbstractFilter;

class CustomRangeFilter extends AbstractFilter {
    public function apply($queryBuilder, $field, $value, $alias) {
        if (is_array($value)) {
            list($min, $max) = $value;
            return $queryBuilder->andWhere("$alias.$field BETWEEN :min AND :max")
                ->setParameter('min', $min)
                ->setParameter('max', $max);
        }
        return $queryBuilder;
    }
}

Register it in services.yaml:

services:
    Bugloos\QueryFilterBundle\Filter\CustomRangeFilter:
        tags: [query_filter.filter]

4. API Integration

Parse query strings in Symfony controllers:

use Symfony\Component\HttpFoundation\Request;

public function index(Request $request) {
    $filters = $request->query->get('filter', []);
    $qb = $entityManager->getRepository('App\Entity\Book')->createQueryBuilder('b');
    return $queryFilter->filter($qb, $filters)->getQuery()->getResult();
}

Example URL: /api/books?filter[title]=Laravel&filter[price][>]=20

5. Performance Optimization

  • Avoid N+1: Use fetchJoin for eager-loaded relations when filtering.
  • Index Fields: Ensure filtered columns (e.g., author.name) are indexed.
  • Batch Filters: For large datasets, limit filters to critical fields.

Gotchas and Tips

Pitfalls

  1. Case Sensitivity: Default LikeFilter is case-insensitive. For case-sensitive searches, override the filter:

    $queryBuilder->andWhere("$alias.$field LIKE :val")
        ->setParameter('val', "%$value%");
    
  2. Deep Relation Limits: The bundle supports 2-level deep relations by default. For deeper nesting, extend QueryFilter or use raw SQL.

  3. Reserved Keywords: Field names like order, limit, or group may conflict with query builder methods. Use aliases:

    $filters = ['book_order' => 'ASC']; // Instead of 'order'
    
  4. Null Handling: Filters with null values may break queries. Sanitize input:

    $filters = array_filter($_GET['filter'] ?? [], fn($v) => $v !== 'null');
    

Debugging

  • Query Dumping: Enable Doctrine query logging to inspect generated SQL:
    $queryFilter->filter($qb, $filters)->getQuery()->getSQL();
    
  • Filter Validation: Validate filters early to avoid runtime errors:
    if (!array_key_exists('author.name', $filters)) {
        throw new \InvalidArgumentException("Invalid filter: author.name");
    }
    

Tips

  1. Reusable Filter Configs: Define filter schemas per entity (e.g., BookFilter class) to enforce allowed fields:

    class BookFilter {
        public static function allowedFields(): array {
            return ['title', 'author.name', 'published_at'];
        }
    }
    
  2. Caching Filters: Cache filtered results for static or rarely changing data:

    $cacheKey = md5(serialize($filters));
    $results = $cache->get($cacheKey, function() use ($qb, $filters) {
        return $queryFilter->filter($qb, $filters)->getQuery()->getResult();
    });
    
  3. Testing: Use the bundle’s test fixtures (tests/Fixtures/) to validate edge cases:

    $this->assertCount(2, $queryFilter->filter($qb, ['author.name' => 'John'])->getQuery()->getResult());
    
  4. Symfony Forms Integration: Bind filters to form fields for user-friendly input:

    $form = $this->createFormBuilder()
        ->add('title', TextType::class, ['attr' => ['class' => 'filter-input']])
        ->getForm();
    

    Then extract values from $request->request->get('filter').

  5. Performance Profiling: Compare query execution times with/without filters using Symfony Profiler or Blackfire. Deep relations may add overhead.

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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware