I have a situation where I need to extract objects from persistent layer after applying some filters and then do some maths on object data and filter base of another query parameter.
Use case: Get all the location which are within the radius of 10km of given latitude and longitude.
Which can be translated into an api endpoint as:
https://api.testdomain.com/api/location?latitude=10&longitude=20&distance=10
I have location entity with:
* @ApiFilter(SearchFilter::class, properties={
* "longitude": "start",
* "latitude":"start",
* "city":"partial",
* "postal_code":"partial",
* "address":"partial",
* }
* )
class Location
{
...
public function withinDistance($latitude, $longitude, $distance):?bool
{
$location_distance=$this->distanceFrom($latitude,$longitude);
return $location_distance<=$distance;
}
}
Since latitude
and longitude
are entity attributes search will be applied and sql query filter is applied, while distance
is not an attribute we have to apply this kind of filter after all object are retrieved from db, which is mystery for me.
I am looking to put following code somewhere after query result is returned :
public function getCollection($collection){
//return after search filtered applied on location.longitute and location.latitude
$all_locations_of_lat_long=$collection;
$locations_within_distance=[];
$query = $this->requestStack->getCurrentRequest()->query;
$lat= $query->get('latitude',0);
$lng= $query->get('longitude',0);
$distance= $query->get('distance',null);
if($distance==null){
return $all_locations_of_lat_long;
}
for($all_locations_of_lat_long as $location){
if($location->withinDistance($lat,$lng,$distance))
$locations_within_distance[]=$location;
}
return $locations_within_distance;
}
What is correct why to apply such filter on entity object collections returned ? I don't think ORM filter will be helpful in this case.
I found that its easy to filter entities by writing a custom controller action and filtering entities after they are retrieved from persistence layer. This could mean I had to fetch all records and then filter which is very costly.
Alternate option was, as suggested by qdequippe, was simply write a custom filter to find distance as follow:
Define a distance filter:
The idea is we are expecting
latitude
,longitude
and optionallydistance
parameters in query string. If on one of required param is missing filter is not invoked. If distance is missing we will assume default distance10km
.Since we have to add DQL functions for
acos
,cos
,sin
andradians
, instead we use doctrine extensions as follow:Install doctrine extensions:
composer require beberlei/doctrineextensions
Configure api filters on location entity: