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

Form Filter Bundle Laravel Package

brandoriented/form-filter-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require lexik/form-filter-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Lexik\Bundle\FormFilterBundle\LexikFormFilterBundle::class => ['all' => true],
    ];
    
  2. Create a Filter Form Type Extend AbstractType and use filter-specific field types (e.g., TextFilterType, DateFilterType). Example:

    use Lexik\Bundle\FormFilterBundle\Form\Filter\FormType;
    use Lexik\Bundle\FormFilterBundle\Form\Filter\Type\TextFilterType;
    
    class PostFilterType extends FormType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('title', TextFilterType::class, [
                    'label' => 'Title',
                    'required' => false,
                    'filter_parameter_name' => 'title', // Maps to query param
                ]);
        }
    }
    
  3. Register the Form Type Add to config/services.yaml:

    services:
        App\Form\Filter\PostFilterType:
            tags: ['form.type']
    
  4. First Use Case: Filtering in a Controller

    use Lexik\Bundle\FormFilterBundle\Form\Filter\FormInterface;
    use Lexik\Bundle\FormFilterBundle\Filter\FormFilter;
    
    public function listAction(Request $request, FormFilter $filter)
    {
        $form = $this->createForm(PostFilterType::class);
        $form->handleRequest($request);
    
        if ($form->isSubmitted() && $form->isValid()) {
            $queryBuilder = $this->getDoctrine()
                ->getRepository(Post::class)
                ->createQueryBuilder('p');
    
            $filter->filter($queryBuilder, $form);
            $results = $queryBuilder->getQuery()->getResult();
        }
        // ...
    }
    

Implementation Patterns

Workflows

  1. Filter Form Creation

    • Use Lexik\Bundle\FormFilterBundle\Form\Filter\Type\* filter types (e.g., TextFilterType, DateRangeFilterType, EntityFilterType).
    • Customize with options like:
      • filter_parameter_name: Maps form field to query parameter (e.g., ?title=search).
      • filter_field_name: Overrides default field name in the query.
      • filter_type: Custom filter logic (e.g., contains, starts_with).
  2. Query Integration

    • Inject FormFilter service into controllers/repositories.
    • Apply filters to QueryBuilder:
      $filter->filter($queryBuilder, $form);
      
    • Chain filters for complex queries:
      $filter->filter($qb, $form, 'AND'); // Default: 'AND'
      
  3. Reusable Filter Logic

    • Create abstract filter types for shared logic:
      abstract class BaseFilterType extends AbstractType
      {
          public function buildForm(FormBuilderInterface $builder, array $options)
          {
              $builder->add('field', $this->getFilterType(), [
                  'filter_parameter_name' => $options['parameter_name'],
              ]);
          }
      }
      
  4. API/REST Integration

    • Use filter_parameter_name to map query strings (e.g., /posts?title=test).
    • Validate and sanitize input in the form type:
      $builder->add('title', TextFilterType::class, [
          'constraints' => [new Length(['max' => 100])],
      ]);
      

Integration Tips

  • Doctrine DQL: Supports all standard DQL functions (e.g., LOWER(p.title) LIKE :title).
  • Custom Conditions: Extend Lexik\Bundle\FormFilterBundle\Filter\AbstractFilter for bespoke logic.
  • Symfony Serializer: Works with API Platform or FOSRestBundle for JSON-based filtering.
  • Event Listeners: Attach to kernel.request to auto-apply filters:
    public function onKernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        if ($request->isMethod('GET') && $request->attributes->has('filter_form')) {
            $form = $this->createForm($request->attributes->get('filter_form'));
            $form->handleRequest($request);
            // Apply filters...
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Parameter Name Conflicts

    • Ensure filter_parameter_name is unique to avoid query parameter collisions.
    • Debug with:
      $filter->getFilterParameters($form); // Inspect generated params
      
  2. Case Sensitivity in DQL

    • Use filter_type: 'contains' for case-insensitive searches:
      $builder->add('title', TextFilterType::class, [
          'filter_type' => 'contains',
      ]);
      
    • For case-sensitive, omit or use filter_type: 'exact'.
  3. Nested Filters

    • Avoid circular references in EntityFilterType:
      // Bad: Self-referential entity
      $builder->add('author', EntityFilterType::class, [
          'class' => Author::class,
          'filter_parameter_name' => 'author',
      ]);
      
    • Use property option to filter by a specific field:
      $builder->add('authorName', TextFilterType::class, [
          'property' => 'author.name', // Filters Author.name
      ]);
      
  4. Performance with Large Datasets

    • Add index_by to QueryBuilder to avoid memory issues:
      $qb->indexBy('p', 'p.id');
      
    • Use DISTINCT for multi-field filters:
      $qb->distinct();
      
  5. Form Validation vs. Filter Logic

    • Form validation (e.g., @Assert\NotBlank) runs before filtering.
    • Use filter_constraints to validate filter values:
      $builder->add('publishedAt', DateFilterType::class, [
          'filter_constraints' => [
              new Assert\GreaterThanOrEqual(['value' => new \DateTime('-1 year')]),
          ],
      ]);
      

Debugging

  • Query Dump Use Doctrine\DBAL\Logging\EchoSQLLogger to inspect generated SQL:

    $qb->getEntityManager()->getConnection()->getConfiguration()->setSQLLogger(new EchoSQLLogger());
    
  • Filter Parameter Inspection

    $parameters = $filter->getFilterParameters($form);
    dump($parameters); // Shows raw filter params
    
  • Event Subscribers Debug filter application with a subscriber:

    public function onFilterApplied(FilterEvent $event)
    {
        dump($event->getQueryBuilder()->getDQL());
    }
    

Extension Points

  1. Custom Filter Types Extend AbstractFilter for new logic:

    use Lexik\Bundle\FormFilterBundle\Filter\AbstractFilter;
    
    class CustomFilter extends AbstractFilter
    {
        public function apply(QueryBuilder $qb, $field, $value, $alias, $operator)
        {
            $qb->andWhere("LOWER($alias.$field) = LOWER(:val)")
               ->setParameter('val', $value);
        }
    }
    

    Register in services.yaml:

    services:
        App\Filter\CustomFilter:
            tags: ['lexik_form_filter.filter']
    
  2. Override Default Filter Types Replace built-in types (e.g., TextFilterType) by redefining them in your bundle.

  3. Dynamic Filter Fields Use FormEvents::PRE_SET_DATA to add fields conditionally:

    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
        $data = $event->getData();
        if ($data->isAdmin()) {
            $event->getForm()->add('adminOnlyField', TextFilterType::class);
        }
    });
    
  4. Localization Translate filter labels/placeholders via Symfony’s translation system:

    {{ form_label(form.title) }} {# Renders translated label #}
    

Configuration Quirks

  • Default Filter Types The bundle ships with:

    • TextFilterType (LIKE)
    • DateFilterType (BETWEEN)
    • EntityFilterType (IN)
    • BooleanFilterType (EQ)
    • NumberFilterType (EQ, GT, LT)
  • Parameter Prefix Add a prefix to all filter parameters:

    # config/packages/lexik_form_filter.yaml
    lexik_form_filter:
        parameter_prefix: 'filter_'
    

    Now ?title=test becomes `?

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.
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon