Skip to main content

Custom Filter Elements

Filter Elements define how a filter value (from a form or context) is applied to the SQL query.

1. Registration (#[AsFilterElement])

To create a custom filter element, annotate your class with the #[AsFilterElement] attribute. It is recommended to extend AbstractFilterElement.

use HeimrichHannot\FlareBundle\DependencyInjection\Attribute\AsFilterElement;
use HeimrichHannot\FlareBundle\FilterElement\AbstractFilterElement;
use HeimrichHannot\FlareBundle\Filter\FilterInvocation;
use HeimrichHannot\FlareBundle\Query\FilterQueryBuilder;

#[AsFilterElement(
type: 'my_custom_filter',
formType: MyCustomFilterType::class
)]
class MyCustomFilterElement extends AbstractFilterElement
{
public function __invoke(FilterInvocation $invocation, FilterQueryBuilder $qb): void
{
$value = $invocation->getValue();

if (empty($value)) {
return;
}

$qb->where($qb->column('my_field') . ' = :val')
->setParameter('val', $value);
}
}

Attribute Parameters:

  • type: Unique identifier for the filter type.
  • formType: The Symfony Form Type class used for this filter in the frontend.
  • palette: (Optional) Specific DCA palette for filter configuration.
  • isTargeted: (Optional) Boolean. If true, the filter expects a specific table alias.

2. The FilterQueryBuilder

The FilterQueryBuilder provides a safe and fluent API for modifying the SQL query. It automatically handles table aliasing to prevent collisions.

Key Methods:

  • column(string $name): Returns the quoted column name prefixed with the correct table alias (e.g., `main`.`my_field`). Always use this for column names!
  • where(string|CompositeExpression $query, ?array $params = null): Adds a WHERE condition.
  • setParameter(string $param, mixed $value): Safely binds a value to a placeholder.
  • whereInSerialized(mixed $find, string $column): Special helper for filtering against Contao's serialized array columns.
  • abort(): Static method to immediately stop filtering and return an empty result set (e.g., if a required value is missing).

Example:

public function __invoke(FilterInvocation $invocation, FilterQueryBuilder $qb): void
{
$value = $invocation->getValue();

// Simple equality
$qb->where($qb->column('city') . ' = :city', ['city' => $value]);

// Using Expression Builder
$qb->where($qb->expr()->gt($qb->column('price'), ':min'))
->setParameter('min', 100);
}

3. Context-Specific Invokers

If your filter needs different logic depending on the context (e.g., a "Search" filter that behaves differently in an "Interactive" list vs. an "API" context), you can use the #[AsFilterInvoker] attribute on specific methods. See Filter Invocation for details.