Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elasticsearch - how to create a custom filter #1926

Open
signor-pedro opened this issue Mar 21, 2024 · 0 comments
Open

Elasticsearch - how to create a custom filter #1926

signor-pedro opened this issue Mar 21, 2024 · 0 comments

Comments

@signor-pedro
Copy link

signor-pedro commented Mar 21, 2024

Hi, I was trying to create a custom filter for geo-distance query.

I had a very hard time understanding what to do - this section is documented rather poorly.

I ended up doing something like this:

use ApiPlatform\Elasticsearch\Extension\RequestBodySearchCollectionExtensionInterface;
use ApiPlatform\Elasticsearch\Filter\AbstractFilter;
use ApiPlatform\Metadata\Operation;

class GeoDistanceFilter extends AbstractFilter implements RequestBodySearchCollectionExtensionInterface
{
    public function apply(array $clauseBody, string $resourceClass, ?Operation $operation = null, array $context = []): array
    {
        throw new \LogicException(
            'This method is never called, but for some reason dictated by the AbstractFilter type.'
        );
    }

    public function applyToCollection(array $requestBody, string $resourceClass, ?Operation $operation = null, array $context = []): array
    {
        // Check for the presence of geo-search parameters
        $filters = $context['filters'] ?? [];

        if (!isset($filters['latitute'], $filters['longitude'], $filters['distance'])) {
            return $requestBody;
        }

        // ... construct and apply the geo-distance query ...

        return $requestBody;
    }

    public function getDescription(string $resourceClass): array
    {
        return [
            'latitute' => [
                'property' => 'lat',
                'type' => 'float',
                'required' => false,
                'description' => 'Latitude for geo-distance search.',
                'openapi' => [
                    'example' => 48.8566,
                ],
            ],
            'longitude' => [
                'property' => 'lon',
                'type' => 'float',
                'required' => false,
                'description' => 'Longitude for geo-distance search.',
                'openapi' => [
                    'example' => 2.3522,
                ],
            ],
            'distance' => [
                'property' => 'distance',
                'type' => 'string',
                'required' => false,
                'description' => 'The maximum distance from the point (lat, lon). Example: "30km".',
                'openapi' => [
                    'example' => '30km',
                ],
            ],
        ];
    }
}

I had a hard time understanding some of these concepts:

  • what is the point of the apply method if it never gets called on runtime - some sort of a BC/adapter thing?
  • what is a reasonable code example of a custom filter? The docs only show an example of an extension:
class AndOperatorFilterExtension implements RequestBodySearchCollectionExtensionInterface
{
    public function applyToCollection(array $requestBody, string $resourceClass, ?Operation $operation = null, array $context = []): array;
    {
        $requestBody['query'] = $requestBody['query'] ?? [];
        $andQuery = [
            'query' => $context['filters']['fullName'],
            'operator' => 'and',
        ];
        
        $requestBody['query']['constant_score']['filter']['bool']['must'][0]['match']['full_name'] = $andQuery;
        
        return $requestBody;
    }
}

However this example would not work by itself, as it does not implement AbstractFilter nor FilterInterface. A more complete example together with an example of the annotation such as

#[ApiFilter(CustomGeoDistanceFilter::class, properties: ['locations.point' => 'geo_distance'])]
class SearchOffer
{
}

would be very appreciated.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant