Yii2:选择距离并映射到模型
Yii2: Selecting distance and mapping to model
在我的 ProjectController 中,我得到了以下函数:
public function actionFindNearest($latitude, $longitude, $amount){
$projects = Project::findNearest($latitude, $longitude, $amount);
$html = '';
foreach($projects as $project){
$html .= $this->renderPartial( '/project/preview', array('model'=>$project), true );
}
return $html;
}
模型中的方法如下所示:
public static function findNearest($latitute, $longitude, $amount){
$sql = 'SELECT SQRT(
POW(69.1 * (latitude - '.$latitute.'), 2) +
POW(69.1 * ('.$longitude.' - longitude) * COS(latitude / 57.3), 2)) AS distance, p.*
FROM project as p
ORDER BY distance LIMIT '.$amount;
$command = Yii::$app->db->createCommand($sql);
return $command->queryAll();
}
我现在得到的是一个包含 3 个对象的数组,其中包含所有模型属性以及我想要的距离 - 完美!
在控制器中,我现在将它传递给 renderPartial:
foreach($projects as $project){
$html .= $this->renderPartial( '/project/preview', array('model'=>$project), true );
}
在 preview.php 模板中,距离属性丢失了,因为现在我只有模型对象,其中距离不是官方字段。
编辑:项目的模型属性class:
/**
* This is the model class for table "project".
*
* @property integer $id
* @property string $updated
* @property string $name
* @property string $description
* @property string $teaserimage
* @property string $goal
* @property string $current
* @property string $startdate
* @property string $enddate
* @property string $created
* @property string $headerimage
* @property integer $category_id
* @property integer $address_id
* @property integer $user_id
* @property string $website_url
*
* @property Comment[] $comments
* @property Donation[] $donations
* @property Goodie[] $goodies
* @property Address $address
* @property Category $category
* @property User $user
*/
我怎样才能在我的模板文件中使用距离?
感谢您的建议!
您需要将 public $distance
属性 添加到您的项目模型中,然后它会自动填充每条记录
我做了类似的事情,例如,如果你想从 table 中获取 10 公里范围内的所有记录。方法是先计算边界minLat, maxLat, minLng, maxLng,然后过滤记录,只得到进入正方形的记录,然后计算距离(只针对这条记录,不针对整个table)有两个目的:
- 首先排除在正方形(minLat,maxLat,minLong,maxLong)内但不在圆内($MyLocation,5 km)的记录。
- 其次,获取每条记录的距离,并根据距离进行排序。
我认为这是最好的方法,请参考这篇文章
https://www.mullie.eu/geographic-searches/
请注意引擎在 "select" 之前执行 "where" 子句。
不要忘记将属性 "distance" 添加到您的模型,并将其添加到重写方法 "fields"。
class WoPdv extends \yii\db\ActiveRecord{
public $distance='';
...
public function fields() {
$fields=parent::fields();
// unset($fields['distance']);
$fields[]= "distance";
return $fields;
}
...
}
在控制器中
$range = 10;// km
// earth's radius in km = ~6371
$radius = 6371;
$maxlat = $lat + rad2deg($range / $radius);
$minlat = $lat - rad2deg($range / $radius);
$maxlng = $lng + rad2deg($range / $radius / cos(deg2rad($lat)));
$minlng = $lng - rad2deg($range / $radius / cos(deg2rad($lat)));
$q = WoPdv::find()->where(['between', 'wo_pdvLat', $minlat, $maxlat])->andWhere(['between', 'wo_pdvLong', $minlng, $maxlng]);
$q->select(['*',"ROUND((((acos(sin((".$lat."*pi()/180)) * sin((`wo_pdvLat`*pi()/180))+cos((".$lat."*pi()/180)) * cos((`wo_pdvLat`*pi()/180)) * cos(((".$lng."- `wo_pdvLong`)*pi()/180))))*180/pi())*60*1.1515*1.609344),2) as distance"]);//distance in km
$q->having('distance <='.$range);
$q->orderBy('distance');
// echo $q->createCommand()->getRawSql();die();
$POSlist=$q->all();
在我的 ProjectController 中,我得到了以下函数:
public function actionFindNearest($latitude, $longitude, $amount){
$projects = Project::findNearest($latitude, $longitude, $amount);
$html = '';
foreach($projects as $project){
$html .= $this->renderPartial( '/project/preview', array('model'=>$project), true );
}
return $html;
}
模型中的方法如下所示:
public static function findNearest($latitute, $longitude, $amount){
$sql = 'SELECT SQRT(
POW(69.1 * (latitude - '.$latitute.'), 2) +
POW(69.1 * ('.$longitude.' - longitude) * COS(latitude / 57.3), 2)) AS distance, p.*
FROM project as p
ORDER BY distance LIMIT '.$amount;
$command = Yii::$app->db->createCommand($sql);
return $command->queryAll();
}
我现在得到的是一个包含 3 个对象的数组,其中包含所有模型属性以及我想要的距离 - 完美! 在控制器中,我现在将它传递给 renderPartial:
foreach($projects as $project){
$html .= $this->renderPartial( '/project/preview', array('model'=>$project), true );
}
在 preview.php 模板中,距离属性丢失了,因为现在我只有模型对象,其中距离不是官方字段。
编辑:项目的模型属性class:
/**
* This is the model class for table "project".
*
* @property integer $id
* @property string $updated
* @property string $name
* @property string $description
* @property string $teaserimage
* @property string $goal
* @property string $current
* @property string $startdate
* @property string $enddate
* @property string $created
* @property string $headerimage
* @property integer $category_id
* @property integer $address_id
* @property integer $user_id
* @property string $website_url
*
* @property Comment[] $comments
* @property Donation[] $donations
* @property Goodie[] $goodies
* @property Address $address
* @property Category $category
* @property User $user
*/
我怎样才能在我的模板文件中使用距离?
感谢您的建议!
您需要将 public $distance
属性 添加到您的项目模型中,然后它会自动填充每条记录
我做了类似的事情,例如,如果你想从 table 中获取 10 公里范围内的所有记录。方法是先计算边界minLat, maxLat, minLng, maxLng,然后过滤记录,只得到进入正方形的记录,然后计算距离(只针对这条记录,不针对整个table)有两个目的:
- 首先排除在正方形(minLat,maxLat,minLong,maxLong)内但不在圆内($MyLocation,5 km)的记录。
- 其次,获取每条记录的距离,并根据距离进行排序。
我认为这是最好的方法,请参考这篇文章 https://www.mullie.eu/geographic-searches/
请注意引擎在 "select" 之前执行 "where" 子句。
不要忘记将属性 "distance" 添加到您的模型,并将其添加到重写方法 "fields"。
class WoPdv extends \yii\db\ActiveRecord{
public $distance='';
...
public function fields() {
$fields=parent::fields();
// unset($fields['distance']);
$fields[]= "distance";
return $fields;
}
...
}
在控制器中
$range = 10;// km
// earth's radius in km = ~6371
$radius = 6371;
$maxlat = $lat + rad2deg($range / $radius);
$minlat = $lat - rad2deg($range / $radius);
$maxlng = $lng + rad2deg($range / $radius / cos(deg2rad($lat)));
$minlng = $lng - rad2deg($range / $radius / cos(deg2rad($lat)));
$q = WoPdv::find()->where(['between', 'wo_pdvLat', $minlat, $maxlat])->andWhere(['between', 'wo_pdvLong', $minlng, $maxlng]);
$q->select(['*',"ROUND((((acos(sin((".$lat."*pi()/180)) * sin((`wo_pdvLat`*pi()/180))+cos((".$lat."*pi()/180)) * cos((`wo_pdvLat`*pi()/180)) * cos(((".$lng."- `wo_pdvLong`)*pi()/180))))*180/pi())*60*1.1515*1.609344),2) as distance"]);//distance in km
$q->having('distance <='.$range);
$q->orderBy('distance');
// echo $q->createCommand()->getRawSql();die();
$POSlist=$q->all();