【问题标题】:How to specify a condition to retrieve data by radius (lat, lon)?如何指定条件以按半径(纬度,经度)检索数据?
【发布时间】:2016-04-02 23:58:08
【问题描述】:

在 cakephp 2 中,我可以为此使用 virtualField,但在 3 中似乎是不可能的。我已经为此苦苦挣扎了两天,没有来自互联网或 cakephp 手册的运气。我没有收到任何错误,但我确实收到了空白返回。

我的控制器中的代码如下所示:

if (isset($this->request->data['location']) && (isset($this->request->data['radius']))){
        $radius = $this->request->data['radius'];
        $location = $this->request->data['location'];
        $address = $location; // Google HQ
        $HttpSocket = new Client();
        $geocode = $HttpSocket->get('http://maps.google.com/maps/api/geocode/json?address='.$address.'&sensor=false');
        $geocode = $geocode->json;
        if ($geocode['status'] == "OK"){ 
        $lat = $geocode['results'][0]['geometry']['location']['lat'];
        $lon = $geocode['results'][0]['geometry']['location']['lng']; 

$R = 6371;  // earth's mean radius, km  

// first-cut bounding box (in degrees)
$maxLat = $lat + rad2deg($radius/$R);
$minLat = $lat - rad2deg($radius/$R);

// compensate for degrees longitude getting smaller with increasing latitude
$maxLon = $lon + rad2deg($radius/$R/cos(deg2rad($lat)));
$minLon = $lon - rad2deg($radius/$R/cos(deg2rad($lat)));

        $conditions[] = ['Venues.lat' => "'BETWEEN '".$minLat."' AND '".$maxLat."'"];
        $conditions[] = ['Venues.lon' => "'BETWEEN :'".$minLon."' AND :'".$maxLon."'"];
       }

 $this->paginate =[ 
        'limit' => 10,
        'order' => ['Quads.date' => 'asc'],
        'conditions' => $conditions,
        'contain' => [
            'Performers' => ['Genres'],
            'Users' => ['Profiles'],
            'Venues' => ['fields' => [
                    'name',
                    'id',
                    'verified',
                    'address1',
                    'city',
                    'zip_code'], 'States'=>['Countries']],
            'Categories',
            'Likes' => ['Users' => ['Profiles']]]];

    $quads = $this->paginate();

【问题讨论】:

标签: cakephp cakephp-3.0 latitude-longitude query-builder


【解决方案1】:

不可能(几乎)没有。旧的虚拟字段概念已经不复存在了,对,新的 ORM 足够灵活,不再需要了。

您的问题是您以错误的方式定义条件,您通过指定 key => value 集合在那里所做的事情是创建普通的运算符条件,其中值将根据列类型进行转义/转换。如果您真的没有收到任何错误,我会假设 lat/lan 列是数字类型,因此您的 BETWEEN ... 字符串确实以数字结尾,并且条件看起来像

Venus.lat = 0 AND Venus.lon = 0

还请注意,您正在创建一个嵌套数组,即

[
    ['keyA' => 'value'],
    ['keyB' => 'value']
]

虽然这有效,但如果您不知道,您可能会遇到更多问题,因此您最好坚持使用

[
    'keyA' => 'value',
    'keyB' => 'value'
]

除非确实有使用嵌套条件的技术原因。

tl;dr 使用表达式

话虽如此,您可以使用表达式来构建适当的条件,例如

$conditions[] = $this->Quads->Venues
    ->query()->newExpr()->between('Venues.lat', $minLat, $maxLat);

$conditions[] = $this->Quads->Venues
    ->query()->newExpr()->between('Venues.lon', $minLon, $maxLon);

这将安全地创建适当的条件,例如

Venus.lat BETWEEN a AND b AND Venus.lon BETWEEN x AND Y

请注意,建议通过包含列的表创建表达式(在这种情况下为VenuesTable),否则您必须手动指定列类型(请参阅QueryExpression::between() 的第四个参数)为了应用正确的转换/转义!

另见

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-15
    • 2012-01-27
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    相关资源
    最近更新 更多