Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

A Custom Filter

A Custom Filter

~15 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

The built-in filters cover MOST cases – for a full-text search across MULTIPLE fields with ONE single parameter, a CUSTOM filter is needed.

When a custom filter is needed

  • ONE parameter should search SEVERAL fields AT ONCE (e.g. ?q=relaunch searches both name AND description).
  • The filtering logic depends on MORE than a simple database comparison (e.g. a similarity search).
  • Computed/virtual fields from chapter 25 should ALSO be filterable (the built-in filters work ONLY on real database columns).

Creating the filter class

api/src/Filter/MultiFieldSearchFilter.php
<?php

declare(strict_types=1);

namespace App\Filter;

use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\QueryBuilder;

final class MultiFieldSearchFilter extends AbstractFilter
{
    protected function filterProperty(
        string $property,
        mixed $value,
        QueryBuilder $queryBuilder,
        \ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface $queryNameGenerator,
        string $resourceClass,
        ?Operation $operation = null,
        array $context = [],
    ): void {
        if ('q' !== $property || !\is_string($value)) {
            return;
        }

        $alias = $queryBuilder->getRootAliases()[0];
        $parameter = $queryNameGenerator->generateParameterName('q');

        $queryBuilder
            ->andWhere("{$alias}.name LIKE :{$parameter} OR {$alias}.description LIKE :{$parameter}")
            ->setParameter($parameter, '%' . $value . '%');
    }

    public function getDescription(string $resourceClass): array
    {
        return [
            'q' => [
                'property' => null,
                'type' => 'string',
                'required' => false,
                'description' => 'Searches name AND description simultaneously.',
            ],
        ];
    }
}

filterProperty() gets called for EVERY query parameter that matches the resource – the check 'q' !== $property ensures the filter reacts ONLY to its OWN q parameter. getDescription() provides the metadata for Swagger UI, EXACTLY as with the built-in filters.

Registering the filter

use App\Filter\MultiFieldSearchFilter;

#[ApiFilter(MultiFieldSearchFilter::class)]

NO properties array needed – the filter defines its OWN parameter name ITSELF via getDescription().

Testing the custom filter

curl -k 'https://localhost/api/projects?q=redesign'

Finds projects where "redesign" appears EITHER in the name OR in the description – ONE parameter instead of two separate SearchFilter requests.

Tipp: The AbstractFilter scaffolding is DELIBERATELY built similarly to a QueryBuilder from the Symfony course (chapter 21) – ANYONE who's already written custom repository methods with QueryBuilder there will feel right at home here.