Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CakePHP从数据库查询最近的经纬度_Php_Mysql_Cakephp_Location_Cakephp 3.0 - Fatal编程技术网

CakePHP从数据库查询最近的经纬度

CakePHP从数据库查询最近的经纬度,php,mysql,cakephp,location,cakephp-3.0,Php,Mysql,Cakephp,Location,Cakephp 3.0,在CakePHP(v3)应用程序中,如何根据传递的lat lng值检索最接近的结果 我希望将它们作为本机CakePHP实体返回,因此如下所示: public function closest($lat, $lng) { $sightings = //records within given lat lng $this->set(compact('sightings')); $this->set('_serialize', ['sightings']);

在CakePHP(v3)应用程序中,如何根据传递的lat lng值检索最接近的结果

我希望将它们作为本机CakePHP实体返回,因此如下所示:

public function closest($lat, $lng) {

    $sightings = //records within given lat lng 

    $this->set(compact('sightings'));
    $this->set('_serialize', ['sightings']);
}
我知道这个SQL是有效的:

SELECT *,
       ( 3959 * acos( cos( radians(50.7) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-1.8) ) + sin( radians(50.7) ) * sin( radians( latitude ) ) ) ) AS distance
  FROM sightings
HAVING distance < 10
 ORDER BY distance
 LIMIT 0 , 20
因此,现在距离显示在我的json输出中(值为null,正如现在预期的那样,但我觉得这至少是一个步骤)

我在这里看了一下:这似乎是我想要实现的,所以假设如下:

$latitude = 51.145;
$longitude = -1.45;
$distance = 100;

$this->Sightings->virtualFields
    = array('Sightings.distance'
     => '(3959 * acos (cos ( radians('.$latitude.') )
    * cos( radians( Sightings.latitude ) )
    * cos( radians( Sightings.longitude )
    - radians('.$longitude.') )
    + sin ( radians('.$latitude.') )
    * sin( radians( Sightings.latitude ) )))');

$sightings = $this->Sightings->find('all', [
    'conditions' => ['Sightings.distance <' => $distance]
]);

$this->set(compact('sightings'));
$this->set('_serialize', ['sightings']);
纬度=51.145;
$经度=-1.45;
$distance=100;
$this->sighting->virtualFields
=阵列('观测距离'
=>'(3959*acos(弧度('.$latitude'))
*cos(弧度(观测纬度))
*cos(弧度(视野、经度)
-弧度(“.$longitude.”)
+sin(弧度(“.$纬度”))
*sin(弧度(视野、纬度));
$sightings=$this->sightings->find('all')[

“条件”=>[“Sightings.distance您需要在此处使用ConnectionManager

例如:

use Cake\Datasource\ConnectionManager;  // Mention this first, preferably on top of the page.

$connection = ConnectionManager::get('default');

$results = $connection
  ->execute('SELECT * FROM articles WHERE id = :id', ['id' => 1])
  ->fetchAll('assoc');
你可以试着用这种方式设置你的查询。它肯定会有用的

将此作为参考:


蛋糕3中不再有虚拟字段,但您仍然可以为计算字段创建别名

根据@ndm的建议,您最好绑定
$latitude
$longitude
以防止SQL注入

$distanceField = '(3959 * acos (cos ( radians(:latitude) )
    * cos( radians( Sightings.latitude ) )
    * cos( radians( Sightings.longitude )
    - radians(:longitude) )
    + sin ( radians(:latitude) )
    * sin( radians( Sightings.latitude ) )))';
使用where

$sightings = $this->Sightings->find()
    ->select([
        'distance' => $distanceField
    ])
    ->where(["$distanceField < " => $distance])
    ->bind(':latitude', $latitude, 'float')
    ->bind(':longitude', $longitude, 'float')
    ->contain(['Photos', 'Tags']);
$sightings=$this->sightings->find()
->挑选([
“距离”=>$distanceField
])
->其中([“$distance字段<”=>$distance])
->绑定(':latitude',$latitude',float')
->绑定(':longitude',$longitude',float')
->包含([‘照片’、‘标签’);
使用have

$sightings = $this->Sightings->find()
    ->select([
        'distance' => $distanceField
    ])
    ->having(['distance < ' => $distance])
    ->bind(':latitude', $latitude, 'float')
    ->bind(':longitude', $longitude, 'float')
    ->contain(['Photos', 'Tags']);
$sightings=$this->sightings->find()
->挑选([
“距离”=>$distanceField
])
->有(['distance<'=>$distance])
->绑定(':latitude',$latitude',float')
->绑定(':longitude',$longitude',float')
->包含([‘照片’、‘标签’);

有几种方法可以实现您的结果

1.原始查询 您可以执行一个

然后可以运行自定义查询,如:

$results = $conn->execute('MY RAW SQL HERE');
2.原始查询,带急切加载 如果要运行查询和,则需要使用contains方法,如:

$query = $articles->find('all', ['contain' => ['Authors', 'Comments']]);
3.使用虚拟字段 如果要使用上面示例中的虚拟字段,则需要将其添加到实体模型类中,如:

protected function _getDistance()
{
    //access model members using $this->_properties e.g.
    //return $this->_properties['latitude'] . '  ' .
    //    $this->_properties['longitude'];
}
这将确保json中的距离不再为空

您可以使用distance方法from来构造查询

public function distance(array $pointX, array $pointY) {
    $res = $this->calculateDistance($pointX, $pointY);
    return ceil($res);
}

public static function calculateDistance($pointX, $pointY) {
    $res = 69.09 * rad2deg(acos(sin(deg2rad($pointX['lat'])) * sin(deg2rad($pointY['lat']))
        + cos(deg2rad($pointX['lat'])) * cos(deg2rad($pointY['lat'])) * cos(deg2rad($pointX['lng']
        - $pointY['lng']))));
    return $res;
}
4.原始PHP
最后,不推荐,您可以检索所有需要的信息,并使用PHP缩小结果范围。痛苦、缓慢且不推荐。

人们可能希望查看以下内容:

CakePHP GeoDistance是一种CakePHP 3行为,用于使用球面余弦定律根据地图距离查询地理编码数据。它非常适合“查找最近的X”或“查找我附近的Y”类型的查询


完成了任务。

最终我找到了解决方案。下面是工作示例

$distance = 25;
$start_latitude = 12.920479;
$start_longitude = 77.670547;

$contents = $this->Sightings->find()->select(['latitude', 'longitude', 'distance' => 'SQRT(
    POW(69.1 * (latitude - '.$start_latitude.'), 2) +
    POW(69.1 * ('.$start_longitude.' - longitude) * COS(latitude / 57.3), 2))'])->having(["distance < " => $distance]);

到目前为止,这是我的方法,但我没有做任何距离方面的事情,我不确定如何将sql插入到蛋糕中。公共函数findClosest($lat,$lng){$sightings=$this->sightings->find('all')->where(['sightings.created>'=>newtime('-12小时'))->limit(5);$this->set(compact('sightings'))$this->set(“_serialize',['sightings'])}提示:这是针对cake 2.x的,在将其转换为3.x时遇到问题。请提供CakePHP生成的SQL。不,这也是针对3.x的,如果您阅读它,可以看到:)它将链接到一个cake 3插件。众所周知,它也被提到,在做任何其他研究之前,这应该是你的第一站。这确实有效,谢谢。有没有办法包括['contain'=>['Photos','Tags']对象,或者我必须编写连接吗?这基本上是一个精确的查询…我只需要按lat/lng公共函数索引($lat,$lng){$sightings=$This->sightings->find('all',['contain'=>['Photos','Tags']])->where(['sightings.created>'=>新时间('-12小时))->顺序进行过滤(['Sightings.created'=>'ASC']->limit(5);$this->set(compact('Sightings');$this->set('u serialize',['Sightings'));}我认为使用join是一个更好的选择。当您使用SELECT这种方式时,它将无法识别模型关联,因此contain的使用是值得怀疑的。它有点接近。我将输出呈现为json,问题是相关表不再显示为相关json对象。例如
联接表中的id
正在覆盖查询的主主表中的id
。这看起来非常接近,可能看起来像是针对cake 2.0的,我不确定如何实现它,还有建议?请确保在此示例中显式强制转换或引用
$latitude
$longitude
,或者使用bindings,否则这可能是一个SQL注入漏洞!@ndm你说得对。我将在第二天改进我的回答。这非常接近我需要的,它选择了正确的行,但它似乎只包含距离值,有没有办法将实体水合为“正常”的当然,您可以选择所需的所有字段。手册说明了如何选择模型的所有字段try
->autoFields(true)
以选择所有字段
public function distance(array $pointX, array $pointY) {
    $res = $this->calculateDistance($pointX, $pointY);
    return ceil($res);
}

public static function calculateDistance($pointX, $pointY) {
    $res = 69.09 * rad2deg(acos(sin(deg2rad($pointX['lat'])) * sin(deg2rad($pointY['lat']))
        + cos(deg2rad($pointX['lat'])) * cos(deg2rad($pointY['lat'])) * cos(deg2rad($pointX['lng']
        - $pointY['lng']))));
    return $res;
}
$distance = 25;
$start_latitude = 12.920479;
$start_longitude = 77.670547;

$contents = $this->Sightings->find()->select(['latitude', 'longitude', 'distance' => 'SQRT(
    POW(69.1 * (latitude - '.$start_latitude.'), 2) +
    POW(69.1 * ('.$start_longitude.' - longitude) * COS(latitude / 57.3), 2))'])->having(["distance < " => $distance]);
   {"lat": xx.920479,
    "lng": xx.670547,
    "distance": "0"
   }