CakePHP - Проблема с виртуальным полем с помощью Помощника по разбивке на страницы


У меня есть таблица списков с полями lat/long. Я использую формулу Хаверсина для вычисления расстояния (в качестве псевдонима/виртуального поля) между исходной точкой (33,987339, -81,036819) и широтой/длиной каждого списка и возвращаю списки с расстоянием в пределах 10 миль от исходной точки.

Следующий SQL-запрос в phpMyAdmin возвращает именно то, что я ожидаю:

SELECT *, round(3959 * acos(cos(radians(33.987339)) * cos(radians(Listing.lat)) * cos(radians(Listing.long) - radians(-81.036819)) + sin( radians(33.987339)) * sin(radians(Listing.lat)))) 
AS distance, `Listing`.`id` 
FROM `preview_site`.`listings` AS `Listing` 
LEFT JOIN `preview_site`.`users` AS `User` ON (`Listing`.`user_id` = `User`.`id`) 
LEFT JOIN `preview_site`.`categories` AS `Category` ON (`Listing`.`category_id` =   `Category`.`id`) 
LEFT JOIN `preview_site`.`states` AS `State` ON (`Listing`.`state_id` = `State`.`id`) 
WHERE `Listing`.`status` = 'Active' 
HAVING distance < 10 
ORDER BY `distance` ASC LIMIT 20

После попытки (и нескольких неудачных попыток) получить Код CakePHP чтобы правильно сгенерировать приведенный выше SQL, я использовал этот инструмент для генерации следующего кода контроллера CakePHP (он предоставлял как параметры модели, так и контроллера) из SQL:

$this->Paginator->virtualFields = array(
'distance' => 'round(3959 * acos(cos(radians(33.987339)) * cos(radians(Listing.lat )) * cos(radians(Listing.long) - radians(-81.036819)) + sin(radians(33.987339)) * sin(radians(Listing.lat))))');
$this->Paginator->settings = array(
'fields' => array(
    'Listing.*',
    'Listing.distance',
    'Listing.id',
    'Category.*',
    'State.*',
    'User.*',
),
'joins' => array(

    array(
        'conditions' => array(
            'Listing.user_id = UserJoin.id',
        ),
        'table' => 'users',
        'alias' => 'UserJoin',
        'type' => 'left',
    ),
    array(
        'conditions' => array(
            'Listing.category_id = CatJoin.id',
        ),
        'table' => 'categories',
        'alias' => 'CatJoin',
        'type' => 'left',
    ),
    array(
        'conditions' => array(
            'Listing.state_id = StateJoin.id',
        ),
        'table' => 'states',
        'alias' => 'StateJoin',
        'type' => 'left',
    ),
),
'conditions' => array(
    'Listing.status' => 'Active',
),
'order' => array(
    'distance' => 'asc',
),
'limit' => '5',
'having' => array(
    'distance <' => '10',
),
'contain' => array(
    'User',
    'Category',
    'State',
),
);
$data = $this->Paginator->paginate('Listing');
$this->set('listings', $data);

Если я использую этот код, я получаю следующую ошибку:

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Listing.distance' in 'field list'

Если я изменю $this->Пагинатор->Виртуальные поля на $this->Список ->Виртуальные поля (так как я не смог найти никакой документации по пагинатору, фактически использующему метод виртуальных полей), я не получу никаких ошибок и разбивка на страницы работает нормально, но возвращаемые результаты не ограничены расстоянием (возвращаются все записи списка). Вот фрагмент сгенерированного SQL-кода с псевдонимом расстояния:

SELECT `Listing`.*, `Listing`.`id`, `Category`.*, `State`.*, `User`.*, (round(3959 *  acos(cos(radians(33.987339)) * cos(radians(`Listing`.`lat` )) *  cos(radians(`Listing`.`long`) - radians(-81.036819)) + sin(radians(33.987339)) *  sin(radians(`Listing`.`lat`))))) 
AS `Listing__distance` 
FROM `preview_site`.`listings` AS `Listing` 

У кого-нибудь есть какие-либо предложения о том, как заставить это работать правильно? ЛЮБАЯ помощь будет очень признательна.

Author: Community, 2013-12-06

2 answers

Я думаю, что причина вашей проблемы в том, что CakePHP не распознает "Обладание", я полагаю. Поскольку у вас, похоже, нет группы по, вы можете просто использовать обычную WHERE и получить те же результаты, в данном случае array('conditions' => array('distance <' => 10)) Если у вас есть Группа По, см. Ниже:

Пирожное: Как я могу использовать операцию "НАЛИЧИЕ" при построении запросов с помощью метода find?

 1
Author: Kai, 2017-05-23 12:28:15

Существует довольно много открытых билетов, касающихся виртуальных полей. Это вполне может быть одним из них.

Даже несмотря на то, что ваша первоначальная привязка к пагинатору выглядит не так. Вы должны добавить виртуальные поля в текущую модель, поэтому перечислите.

$this->Listing->virtualFields['distance'] = ...

Для меня в тех сценариях, когда я не мог легко использовать виртуальное поле, помогало вручную использовать поле с псевдонимами, поэтому Listing__distance ASC в вашем заказе или, что более важно, в вашем предложении having. Вместо этого он также будет повторно использовать уже вычисленное поле сделать это снова (хотя я не знаю, есть ли здесь улучшение скорости таким образом). Смотрите это.

Также обратите внимание, что было бы чище использовать поведение , чтобы избежать повторения этого для других запросов (и сохранить его СУХИМ):

$this->Listing->setDistanceAsVirtualField($lag, $lng);

И я обычно использую условия для ограничения расстояния (в этом нет необходимости, не так ли?).

 0
Author: mark, 2013-12-06 00:22:52