我已经为Api平台完成了几种不同的自定义过滤器,但是现在我需要另外一个自定义过滤器,而我却错过了正确的方法。基本上,任务是根据给定点的地理距离对项目进行排序并显示距离。在纯SQL中,这非常容易(例如参见https://mysqlserverteam.com/mysql-5-7-and-gis-an-example/),但是在Api Platform中,这似乎很复杂。 基本上有几个任务要做:
order[gps]
值,简单,通常不需要相反的方向Filter::filterProperty()
中添加呢?如果我尝试$queryBuilder->addSelect()
,则查询有效,但它破坏了序列化程序:Notice: Undefined index: _links
in vendor/api-platform/core/src/Hal/Serializer/CollectionNormalizer.php (line 85)
$data['_links']['item'][] = $item['_links']['self'];
addOrderBy()
。 可能我可以将其分为两部分-保留$queryBuilder
仅进行排序,并再次在php序列化器/控制器中计算额外列的距离,但这对于大型数据集而言效率很低。 (无论如何,甚至学说都会一次又一次地计算三次-count(),DISTINCT标识详细查询)
任何人都已经使用过或有任何想法吗?
答案 0 :(得分:0)
您需要添加一个自定义过滤器:
如下:
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
{
// otherwise filter is applied to order and page as well
if ($property !== 'distance') {
return;
}
[$lat, $lng, $radius] = explode(',', $value);
// add distance in DQL based on filter location point
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder
->addSelect('(6371000 * acos(cos(radians(' . $lat . ')) * cos(radians('.$rootAlias.'.lat)) * cos(radians('.$rootAlias.'.lng) - radians(' . $lng . ')) + sin(radians(' . $lat . ')) * sin(radians('.$rootAlias.'.lat)))) AS distance')
->having('distance <= :radius')
->setParameter('radius', $radius)
->orderBy('distance')
;
}
为此,您还需要为acos,cos,弧度,sin添加自定义DQL函数:
这里是Doctrine Extensions https://github.com/beberlei/DoctrineExtensions
的链接doctrine:
orm:
dql:
numeric_functions:
acos: DoctrineExtensions\Query\Mysql\Acos
cos: DoctrineExtensions\Query\Mysql\Cos
radians: DoctrineExtensions\Query\Mysql\Radians
sin: DoctrineExtensions\Query\Mysql\Sin