具有计算列(即地理位置距离)的Api平台过滤器

时间:2020-01-10 14:44:32

标签: api-platform.com

我已经为Api平台完成了几种不同的自定义过滤器,但是现在我需要另外一个自定义过滤器,而我却错过了正确的方法。基本上,任务是根据给定点的地理距离对项目进行排序并显示距离。在纯SQL中,这非常容易(例如参见https://mysqlserverteam.com/mysql-5-7-and-gis-an-example/),但是在Api Platform中,这似乎很复杂。 基本上有几个任务要做:

  • 向具有gps值的列添加自定义过滤器,简单
  • 定义起始位置。可以设置为order[gps]值,简单,通常不需要相反的方向
  • (可选)使用最大过滤所有行。距离,也容易在SQL WHERE中使用变量。 https://github.com/api-platform/api-platform/issues/382https://gist.github.com/vincentchalamon/6afb137e8c2d1dec1d5a1978b45b64ec
  • 的评论中对此进行了描述
  • 添加具有计算距离的新SELECT列。您可以在php实体,序列化器或自定义控制器中添加计算列,但是如何在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'];
  • 最后,如果您在SQL中有多余的列,则可以按其值addOrderBy()
  • 然后的问题是,如果多余的列并不总是存在于查询中,那么如何将其添加到实体中? (仅在按距离排序时显示)。

可能我可以将其分为两部分-保留$queryBuilder仅进行排序,并再次在php序列化器/控制器中计算额外列的距离,但这对于大型数据集而言效率很低。 (无论如何,甚至学说都会一次又一次地计算三次-count(),DISTINCT标识详细查询)

任何人都已经使用过或有任何想法吗?

1 个答案:

答案 0 :(得分:0)

您需要添加一个自定义过滤器:

  1. 以米为单位计算距离
  2. 根据半径(最大距离)过滤
  3. 按最近顺序排序

如下:

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
相关问题