将从SQL查询计算的字段添加到Yii2 ActiveRecord模型
我正在编写代码以返回位于指定区域内的位置列表,并且接近某个经度和纬度。数据库布局是有一个包含业务的位置表,一个区域表(它定义了区域(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);
}
您应该将此属性只是添加到您的类:
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饲料。
问完这个问题后不久,我发现了一个稍微不雅的回答。
我不得不在我的位置模型中覆盖填充记录和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);
}
一旦添加了这些,距离属性开始出现在模型中。
不需要这样做 – soju
函数在模型中?并返回一组行? – scaisEdge
正确。但它是一个web服务,最终将输出整个集合作为json对象。 – TMorgan