2016-09-28 32 views
1

我正在編寫代碼以返回位於指定區域內的位置列表,並且接近某個經度和緯度。數據庫佈局是有一個包含業務的位置表,一個區域表(它定義了區域(UrlName是一個標識該區域的塊)和一個將區域映射到位置的區域位置表。將從SQL查詢計算的字段添加到Yii2 ActiveRecord模型

SQL查詢非常多毛,但它計算一個名爲「Distance」的虛擬列,我希望在返回的模型中可以訪問該列。

這裏是出現在我的位置模型的代碼的縮寫版本:

 public static function getByRegionAndLatLong($regionName, $lat, $long) { 

     $sql = "SELECT 
      `Location`.`LocationId`, 
      `Location`.`Latitude`, 
      `Location`.`Longitude`, 
        (
        3959 * acos (
        cos (radians(:Latitude)) 
        * cos(radians(latitude)) 
        * cos(radians(longitude) - radians(:Longitude)) 
        + sin (radians(:Latitude)) 
        * sin(radians(latitude)) 
        ) 
       ) AS Distance 
       FROM Location 
        LEFT JOIN RegionLocation RL 
        ON RL.LocationId = Location.LocationId 
        LEFT JOIN Region R 
        ON R.RegionId = RL.RegionId 
       WHERE R.UrlName= :UrlName 
       ORDER BY Distance ; 
     "; 

     return Location::findBySql($sql, [ 
      ':Latitude' => $lat, 
      ':Longitude' => $long, 
      ':UrlName' => $UrlName 
     ])->all(); 
    } 

的問題是,當我運行查詢,我想爲所計算的「距離」一欄被列入結果。但是,由於數據庫中沒有名爲「距離」的實際字段,因此Yii2的ActiveRecord類將不會將字段添加到生成的模型中。

我可以通過在Location表中創建一個名爲「Distance」的列來避開它,但我希望有一種方法可以在不更改數據庫的情況下執行此操作。

我最終的目的是讓模型返回一個Location對象數組,每個Location對象都有一個「Distance」屬性。

public function actionGetStudiosByLatLong($regionName = '', $latitude='', $longitude='') { 
     \Yii::$app->response->format = 'json'; 

     return Location::getByRegionAndLatLong($regionName, $latitude, $longitude); 
    } 
+0

函數在模型中?並返回一組行? – scaisEdge

+0

正確。但它是一個web服務,最終將輸出整個集合作爲json對象。 – TMorgan

回答

2

您應該將此屬性只是添加到您的類:

class Location extends \yii\db\ActiveRecord 
{ 

    public function attributes() 
    { 
     // add distance attribute (will work for json output) 
     return array_merge(parent::attributes(), ['Distance']); 
    } 

    // ... 
} 

瞭解更多關於Selecting extra fields然後,控制器會使用類似於下面的代碼生成一個JSON飼料。

+0

這似乎是一個更優雅的解決方案,但我的控制器需要能夠用這些對象生成json提要(問題已被編輯以反映這一點)。當我將響應格式設置爲json並返回具有公共$ Distance屬性的對象時,該屬性被省略,因爲它不像所有其他字段一樣是屬性。但是當我對結果集進行json_encode時,我得到一個除了距離屬性以外都沒有的對象數組(這些屬性被省略)。 – TMorgan

+0

答覆已更新。 – soju

+0

那確實增加了一個距離字段,但是每個記錄的值都是空的。事實證明,我需要擺脫該答案以前版本中的距離公共屬性。正如所寫,它能正常工作。 – TMorgan

0

問完這個問題後不久,我發現了一個稍微不雅的回答。

我不得不在我的位置模型中覆蓋填充記錄和hasAttribute方法。

 /** 
    * Adds "Distance" field to records if applicable. 
    */ 
    public static function populateRecord($record, $row) 
    { 
     $columns = static::getTableSchema()->columns; 

     foreach ($row as $name => $value) { 
      if (isset($columns[$name])) { 
       $row[$name] = $columns[$name]->phpTypecast($value); 
      } 
     } 
     parent::populateRecord($record, $row); 

     if(isset($row['Distance'])) { 
      $record->setAttribute('Distance', $row['Distance']); 
     } 
    } 

    // Needed to convince the powers that be that "Distance" really is a field. 
    public function hasAttribute($name) 

    { 
     if($name == 'Distance') return true; 
     return parent::hasAttribute($name); 
    } 

一旦添加了這些,距離屬性開始出現在模型中。

+0

不需要這樣做 – soju