Yii2:选择距离并映射到模型

时间:2015-06-19 11:16:26

标签: php mysql activerecord yii2 distance

在我的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模板中,distance属性会丢失,因为现在我只有模型对象,其中距离不是官方字段。

编辑:项目类的模型属性:

/**
 * 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
 */

如何在模板文件中使用距离?

感谢您的建议!

2 个答案:

答案 0 :(得分:1)

您需要将public $distance属性添加到项目模型中,然后为每条记录自动填充

答案 1 :(得分:0)

我做类似的事情,例如,如果要从表中获取10公里范围内的所有记录。该方法是计算边界minLat,maxLat,minLng,maxLng并过滤记录以仅将记录放入正方形,然后出于两个目的进行距离的计算(仅针对此记录,而不针对整个表):

  • 首先,排除在正方形(minLat,maxLat,minLong,maxLong)中但不在圆中的记录($ MyLocation,5 km)。
  • 第二,获取每个记录的距离并根据距离进行排序。

我认为这是最好的方法,请参阅本文 https://www.mullie.eu/geographic-searches/

请注意,引擎在“选择”之前执行“ 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();