Использование сложных вычисляемых значений с помощью Eloquent

#laravel #laravel-4 #eloquent

#laravel #laravel-4 #eloquent

Вопрос:

У меня есть две таблицы, магазины и местоположения.

Прямо сейчас я делаю это:

 $shops = Shop::with('location');
if (Input::has('location')) {
    $shops->whereHas('location', function($q) use ($input) {
        $q->where('name', '=', Input::get('location');
    });
}

return $shops->paginate(10);
 

и все идет нормально.

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

 $shops->raw('(
    3959 * acos (
        cos ( radians(?) )
   * cos( radians( locations.lat ) )
   * cos( radians( locations.lon ) - radians(?) )
          sin ( radians(?) )
   * sin( radians( locations.lat ) )
        )
) AS distance
', array(Session::get('latitude'), Session::get('longitude'), Session::get('latitude')));
 

(ставится перед возвращаемым значением выше)

Это ничего не делает — замена на whereRaw также не работает.

Мне придется прекратить использовать Eloquent (снова!), Или с этим может справиться Eloquent?

Комментарии:

1. 2. Вы должны подключить событие eloquent и распечатать фактический SQL, сгенерированный вашей функцией, — тогда вы сможете отладить происходящее.

2. Это весь код, я не определил raw функцию конкретно. Запрос не изменяется при его использовании (возможно, потому, что он не существует?). Использование whereRaw вызывает исключение.

3. Я думаю вслух, что, поскольку вы выполняете вычисляемую функцию , вам, вероятно, нужно включить raw() при первоначальном вызове Shop . Так что, может быть, что-то вроде $shops = Show::with('location')->raw(<code>)

4. Кажется, что whereRaw всегда помещает код после WHERE оператора в SQL, что, я думаю, логично. Я не могу понять, как это сделать раньше, я думаю, это сработало бы, если бы я мог…

5. Может, вы просто используете raw()? Также — проверьте этот пример — вы могли бы попробовать select() с DB::raw() — laravel.com/docs/queries#raw-expressions

Ответ №1:

  1. Вам нужно selectRaw или select(DB::raw(...)) , не whereRaw
  2. Вам нужно присоединиться locations к таблице, чтобы выбрать из нее (чтобы привязать расстояние к Shop объектам) ИЛИ поместите эту часть в Location модели загрузки запросов (для привязки расстояния к Location объектам):
     Shop::with(['location' => function ($q) {
       $q->selectRaw(' *, YOUR_CALC_HERE as distance'); 
       // don't forget to select all with '*'
    }]);
     

Если вы хотите упорядочивать магазины по расстоянию, то вам определенно нужно объединение.

Ответ №2:

После некоторой помощи по IRC я решил сделать это именно так:

 // First, specify a manual join onto locations, so the values are available in this query
$shops->join('locations', 'shops.location_id', '=', 'locations.id');

// Second, add the selectRaw (which seems to not have variable binding?)
$shops->selectRaw('(
    3959 * acos (
        cos ( radians('.Session::get('latitude').') )
* cos( radians( locations.lat ) )
* cos( radians( locations.lon ) - radians('.Session::get('longitude').') )
          sin ( radians('.Session::get('latitude').') )
* sin( radians( locations.lat ) )
        )
) AS distance
');

// select the rest of the variables on shops afterwards to avoid any name collisons
$shops->addSelect('shops.*');