Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/71.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
SilverStripe ORM中每个mysql在位置Y周围半径X内的位置_Mysql_Orm_Geolocation_Silverstripe - Fatal编程技术网

SilverStripe ORM中每个mysql在位置Y周围半径X内的位置

SilverStripe ORM中每个mysql在位置Y周围半径X内的位置,mysql,orm,geolocation,silverstripe,Mysql,Orm,Geolocation,Silverstripe,我正在根据SilverStripe 3.4.0中的mysql过滤位置Y周围半径X内的位置 到目前为止,我已经实现了一个原始查询来获取圆圈中的ID,然后使用这些ID来过滤每个SilverStripe ORM,因为我必须根据多个条件进行过滤,而geofilter只是其中之一 另请参见谷歌的“商店定位器”示例: 这将提供所需的结果,但需要额外的查询是否可以将地理过滤器直接添加到ORM内的查询?我不确定“直接添加到ORM内的查询”是什么意思,但可以理解为“不调用Web服务”,然后我可以提供以下解决方案

我正在根据SilverStripe 3.4.0中的mysql过滤位置Y周围半径X内的位置

到目前为止,我已经实现了一个原始查询来获取圆圈中的ID,然后使用这些ID来过滤每个SilverStripe ORM,因为我必须根据多个条件进行过滤,而geofilter只是其中之一

另请参见谷歌的“商店定位器”示例:


这将提供所需的结果,但需要额外的查询是否可以将地理过滤器直接添加到ORM内的查询?

我不确定“直接添加到ORM内的查询”是什么意思,但可以理解为“不调用Web服务”,然后我可以提供以下解决方案

注意:我建议使用javascript在商店定位器中直接与google maps一起执行此操作,以便通过javascript同步完成计算

function FilterMemberByPostCodeDistance($params, $query){
    $query->where('Member.PostCode IS NOT NULL')
        ->innerJoin('PostCodeToLocation',"SUBSTRING_INDEX(SUBSTRING_INDEX(Member.PostCode,' ', 1),' ',-1) = PostCodeToLocation.OutCode");
 
    $latitude = (float)$postCodeToLocation->Latitude;
    $longitude = (float)$postCodeToLocation->Longitude;
 
    $fTemp = floatval($params['Distance']) / 111.045;
    $fMagicSquareMinLatitude = $latitude - $fTemp;
    $fMagicSquareMaxLatitude = $latitude + $fTemp;
 
    $fTemp = 50.0 / (111.045 * cos(deg2rad($latitude)));
    $fMagicSquareMinLongitude = $longitude - $fTemp;
    $fMagicSquareMaxLongitude = $longitude + $fTemp;
 
    $query->where(
        //Magic Square - this is a simple square to filter out most out of distance values before the magic circle
        //this is done because the circle calculation is much more expensive that the square
 
        'PostCodeToLocation.Latitude  BETWEEN '.$fMagicSquareMinLatitude.' AND '.$fMagicSquareMaxLatitude.'
            AND PostCodeToLocation.Longitude BETWEEN '.$fMagicSquareMinLongitude.' AND '.$fMagicSquareMaxLongitude
 
        //Magic Circle (https://en.wikipedia.org/wiki/Haversine_formula)
        //This is what does the complicated maths to determine if the postcode is in the cirectle or not
        //not as we are using out codes only, this is a "good estimate" but not 100% accurate
 
        //.' AND acos(sin(RADIANS('.$latitude.'))
        //  * sin(RADIANS(PostCodeToLocation.Latitude))
        //  + cos(RADIANS('.$latitude.'))
        //  * cos(RADIANS(PostCodeToLocation.Latitude))
        //  * cos(RADIANS(PostCodeToLocation.Longitude)
        //  - (RADIANS('.$longitude.'))))
        //  * 6371 <= '.($params['Distance'] * 1.60934) //Kilometers
 
        //REFACTOR of above to process more upfront within PHP
        .' AND acos(sin('.deg2rad($latitude).')
           * sin(RADIANS(PostCodeToLocation.Latitude)) + '.cos(deg2rad($latitude))
        .' * cos(RADIANS(PostCodeToLocation.Latitude))
           * cos(RADIANS(PostCodeToLocation.Longitude) - '.deg2rad($longitude).'))
           * 6371 <= '.($params['Distance'] * 1.60934) //Kilometers
    );
    return $query;
}

可以找到上面的数据文件。

是的,可以使用ORM来实现这一点。您可以将
DataQuery
DataList
中拉出,对其进行更改(添加子句等),然后使用它更新
DataList

比如:

$dataList = MyObject::get();

$dataQuery = $dataList->dataQuery();

$dataQuery->where(...);
$dataQuery->having(...);

$dataList->setDataQuery($dataQuery);
添加select并为其添加别名有点棘手,因为您需要针对
DataQuery
修改
SQLQuery
,但这也应该是可能的,尽管只需添加haversin公式即可进行排序

$dataList->sort(...)

直接在ORM中添加一个过滤器到底是什么意思?@Shadow-SilverStripe进行延迟加载。这意味着我们可以修改查询$DataObjects。我的意思是$DataObjects->where(“…”),因为您的查询只有having子句,所以我将使用dataobject类的
having()
方法。但是,您可以轻松地将
filter()
方法中的任何内容包含在查询的where子句中。将此条件添加到原始查询可能更容易,而不是试图找出如何以SilverStripe的方式重写原始查询。我没有说你会删除一个查询,但它会以最理想的方式完成:直接在mysql上,因为这是数据的来源,而不需要在php上做额外的步骤。只需补充说明:你的查询和下面的所有答案(此时)计算“精确”距离(可能不尽可能精确,但仍然如此)针对每一行。虽然当有1000行时,这并不需要花太多时间处理单个行,但处理查询将需要很长时间。执行边界框搜索(位置在适合您距离的区域的NE、SE、SW、NW坐标内)并过滤此信息要快得多(小得多)如果需要精确的距离,用PHP设置。thx@Barry但说实话,我喜欢我拥有的比你建议的更多。为了获得位置-Y的lat/lng,我根据谷歌进行地理编码,但为了找到圆圈中的位置,我只需根据MySQL查询DB。但我想在一次查询中做到这一点。正如我所说的“如果你的意思是…”因为我不是很确定。我认为你现在的情况是最好的,因为你不能把HAVING子句放到ORM中。很抱歉,我有时会误解这个问题:)你每天都会学到新东西……是的@Barry,很酷,'我会尝试一下,然后再报告。如果我失败了,我会在IRC上唠叨你:)
class PostCodeToLocation extends DataObject{

    static $db = array(
        'OutCode'       => 'Varchar(5)',
        'Latitude'      => 'Float',
        'Longitude'     => 'Float'
    );
 
    public static $indexes = array(
        'OutCode'           => true
    );
 
    public function PopulatePostCodeToLocationTable() {
 
        DB::query('TRUNCATE TABLE PostCodeToLocation');
 
        $arrPostCodetoLocations = file(BASE_PATH .'/mysite/.../postcode_outcode_to_latlong.csv');
        if(!empty($arrPostCodetoLocations))
            foreach ($arrPostCodetoLocations as $strPostCodetoLocation) {
                list ($strOutCode,$strLatitude,$strLongitude) = explode(',',$strPostCodetoLocation);
                DB::query("INSERT INTO PostCodeToLocation (OutCode, Latitude, Longitude )
                    VALUES ('".$strOutCode."','".$strLatitude."','".$strLongitude."')"
                );
            }
    }
}
$dataList = MyObject::get();

$dataQuery = $dataList->dataQuery();

$dataQuery->where(...);
$dataQuery->having(...);

$dataList->setDataQuery($dataQuery);
$dataList->sort(...)