CakePHP запрос ближайшей долготы широты из базы данных

В приложении CakePHP (v3), как я могу получить самые близкие результаты на основе пройденных значений lat lng?

Я хотел бы вернуть их в качестве родственных сущностей CakePHP, поэтому примерно так:

public function closest($lat, $lng) { $sightings = //records within given lat lng $this->set(compact('sightings')); $this->set('_serialize', ['sightings']); } 

Я знаю, что этот SQL работает:

 SELECT *, ( 3959 * acos( cos( radians(50.7) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-1.8) ) + sin( radians(50.7) ) * sin( radians( latitude ) ) ) ) AS distance FROM sightings HAVING distance < 10 ORDER BY distance LIMIT 0 , 20 

Борясь, чтобы объединить эти два.

ОБНОВИТЬ

    я добавил

     class Sighting extends Entity { public $_virtual = ['distance']; //rest of class... } 

    Итак, теперь distance показывается в моем json-выходе (со значением null, как ожидалось прямо сейчас, но я чувствую, что это шаг в аренду).

    Я посмотрел здесь: http://www.mrthun.com/2014/11/26/search-distance-cakephp/, который, похоже, я пытаюсь достичь, так предполагал что-то вроде этого:

     $latitude = 51.145; $longitude = -1.45; $distance = 100; $this->Sightings->virtualFields = array('Sightings.distance' => '(3959 * acos (cos ( radians('.$latitude.') ) * cos( radians( Sightings.latitude ) ) * cos( radians( Sightings.longitude ) - radians('.$longitude.') ) + sin ( radians('.$latitude.') ) * sin( radians( Sightings.latitude ) )))'); $sightings = $this->Sightings->find('all', [ 'conditions' => ['Sightings.distance <' => $distance] ]); $this->set(compact('sightings')); $this->set('_serialize', ['sightings']); 

    Результаты в: Column not found: 1054 Unknown column 'Sightings.distance' in 'where clause'

    Не уверен, возможно ли CakePHP v2 в отличие от v3?

    Related of "CakePHP запрос ближайшей долготы широты из базы данных"

    в торте 3 больше нет виртуальных полей, но вы все равно можете создать псевдоним для вычисленного поля

    Как было предложено @ndm, вам лучше привязать $latitude и $longitude чтобы предотвратить инъекции SQL

     $distanceField = '(3959 * acos (cos ( radians(:latitude) ) * cos( radians( Sightings.latitude ) ) * cos( radians( Sightings.longitude ) - radians(:longitude) ) + sin ( radians(:latitude) ) * sin( radians( Sightings.latitude ) )))'; 

    используя

     $sightings = $this->Sightings->find() ->select([ 'distance' => $distanceField ]) ->where(["$distanceField < " => $distance]) ->bind(':latitude', $latitude, 'float') ->bind(':longitude', $longitude, 'float') ->contain(['Photos', 'Tags']); 

    используя

     $sightings = $this->Sightings->find() ->select([ 'distance' => $distanceField ]) ->having(['distance < ' => $distance]) ->bind(':latitude', $latitude, 'float') ->bind(':longitude', $longitude, 'float') ->contain(['Photos', 'Tags']); 

    Здесь вы должны использовать ConnectionManager.

    Например:

     use Cake\Datasource\ConnectionManager; // Mention this first, preferably on top of the page. $connection = ConnectionManager::get('default'); $results = $connection ->execute('SELECT * FROM articles WHERE id = :id', ['id' => 1]) ->fetchAll('assoc'); 

    Вы можете попробовать и настроить свой запрос таким образом. Это определенно сработает.

    Используйте это как ссылку:

    Выражения SELECT с CakePHP 3

    Существует несколько подходов для достижения вашего результата.

    1. Необработанный запрос

    Вместо того, чтобы бороться с ORM, вы можете выполнить необработанный запрос ?

     $conn = ConnectionManager::get('my_connection'); 

    И затем вы можете запустить пользовательский запрос, например:

     $results = $conn->execute('MY RAW SQL HERE'); 

    2. Сырой запрос с загрузкой

    Если вы хотите запустить запрос и загружать отношения , вам нужно будет использовать метод contains, например:

     $query = $articles->find('all', ['contain' => ['Authors', 'Comments']]); 

    3. Использование виртуальных полей

    Если вы хотите использовать виртуальные поля, как в приведенном выше примере, вам нужно добавить его в класс модели сущности, например:

     protected function _getDistance() { //access model members using $this->_properties eg //return $this->_properties['latitude'] . ' ' . // $this->_properties['longitude']; } 

    Это должно обеспечить, что ваше расстояние больше не равно нулю в вашем json.

    И вы можете использовать метод расстояния из библиотеки CakephpGeo для построения запроса

     public function distance(array $pointX, array $pointY) { $res = $this->calculateDistance($pointX, $pointY); return ceil($res); } public static function calculateDistance($pointX, $pointY) { $res = 69.09 * rad2deg(acos(sin(deg2rad($pointX['lat'])) * sin(deg2rad($pointY['lat'])) + cos(deg2rad($pointX['lat'])) * cos(deg2rad($pointY['lat'])) * cos(deg2rad($pointX['lng'] - $pointY['lng'])))); return $res; } 

    4. Сырой PHP

    Наконец, и не рекомендуется, вы можете получить всю необходимую информацию и использовать PHP, чтобы сузить результаты. Болезненный, медленный и не рекомендуется.

    Люди могут захотеть посмотреть плагин GeoDistance CakePHP :

    CakePHP-GeoDistance – это поведение CakePHP 3 для запроса геокодированных данных на основе картографического расстояния с использованием закона сферического косинуса. Это отлично подходит для запросов «найти мои ближайшие X» или «найти Y рядом со мной».

    https://github.com/chris48s/cakephp-geodistance

    Сделала работу.