core icon indicating copy to clipboard operation
core copied to clipboard

Custom Radius Location Filter returns "Too many parameters: the query defines 3 parameters and you bound 4"

Open Guuri11 opened this issue 3 years ago • 1 comments

Hi there! I've created a custom filter to search by radius location, with a radius, latitude & longitude.

<?php

namespace App\ApiPlatform;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\PropertyInfo\Type;

final class RadiusLocationFilter extends AbstractContextAwareFilter
{
    protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
    {
        if (
            $property !== 'radius'
        ) {
            return;
        }

        $parameterName = $queryNameGenerator->generateParameterName($property); // Generate a unique parameter name to avoid collisions with other filters
        $radiusParams = explode(',', $value);
        $queryBuilder
                ->select('o')
                ->where('(((acos(sin(( :latitude * pi() / 180))*sin(( o.latitude * pi() / 180)) + cos(( :latitude * pi() /180 ))*cos(( o.latitude * pi() / 180)) * cos((( :longitude - o.longitude) * pi()/180)))) * 180/pi()) * 60 * 1.1515 * 1.609344) <= :distance')
                ->setParameter('distance', $radiusParams[0])
                ->setParameter('longitude', $radiusParams[1])
                ->setParameter('latitude', $radiusParams[2]);
    }

    // This function is only used to hook in documentation generators (supported by Swagger and Hydra)
    public function getDescription(string $resourceClass): array
    {

        // Parametros que espera recibir, ponemos todos para testear en la documentación, pero en realidad solo procesaremos uno, ya que se cogerá la úbicación real del usuario
        return [
            'radius' => [
                'property' => null,
                'type' => 'string',
                'required' => false
            ],
        ];
    }
}

It works well using just those params localhost:8000/posts?radius=150000&latitude=10&longitude=10

But when I try to use for example SearchFilter localhost:8000/posts?radius=150000&latitude=10&longitude=10&owner.username=foo

over a property it returns this error

{
    "@context": "/contexts/Error",
    "@type": "hydra:Error",
    "hydra:title": "An error occurred",
    "hydra:description": "Too many parameters: the query defines 3 parameters and you bound 4",
    ...
}

How can I create a custom filter like this & continue to filter by other properties? Thank you so much! :D

Guuri11 avatar Jun 04 '22 22:06 Guuri11

Please use the "Discussion" tab to ask for help. You are overriding the query with the "select" and the "where" sentence in your queryBuilder. You should get the root alias with $queryBuilder->getRootAliases()[0] and add the "where" sentence with $queryBuilder->andWhere($expression).

BrandonlinU avatar Jun 25 '22 14:06 BrandonlinU