Как сортировать по полю сводной таблицы отношений "многие ко многим" в "Красноречивой ORM"
Я использую Eloquent ORM в течение некоторого времени, и я знаю это довольно хорошо, но я не могу сделать следующее, а это очень легко сделать в Fluent.
У меня есть пользователи со многими-ко-многим песнями, промежуточная таблица - song_user (как и должно быть). Я бы хотел получить лучшие песни пользователя, судя по счету игры. Конечно, счетчик воспроизведения хранится в промежуточной таблице.
Я могу сделать это в Fluent:
$songs = DB::table('songs')
->join('song_user', 'songs.id', '=', 'song_user.song_id')
->where('song_user.user_id', '=', $user->id)
->orderBy("song_user.play_count", "desc")
->get();
Легко. Но я хочу сделать это в Eloquent, который, конечно, не работает:
$songs = Song::
with(array("song_user" => function($query) use ($user) {
$query->where("user_id", "=", $user->id)->orderBy("play_count", "desc");
}))
Ответы
Ответ 1
Не уверен, что вы планируете переместиться в Laravel 4, но здесь пример Eloquent для сортировки по полям сводных таблиц:
public function songs() {
return $this
->belongsToMany('Song')
->withPivot('play_count')
->orderBy('pivot_play_count', 'desc');
}
withPivot
похож на красноречивый with
и добавит поле play_count
из сводной таблицы к другим уже включенным ключам. Все поля сводной таблицы имеют префикс pivot
в результатах, поэтому вы можете ссылаться на них непосредственно в orderBy
.
Я понятия не имею, как это будет выглядеть в Laravel 3, но, возможно, это поможет вам в правильном направлении.
Ура!
Ответ 2
Я только что нашел что-то в руководстве пользователя, очевидно, вам нужен метод with()
.
Из User-Guide:
По умолчанию возвращаются только определенные поля из сводной таблицы (два поля id и временные метки). Если ваша сводная таблица содержит дополнительные столбцы, вы можете получить их также с помощью метода with()
class User extends Eloquent {
public function roles()
{
return $this->has_many_and_belongs_to('Role', 'user_roles')->with('column');
}
}
Итак, вы можете использовать что-то подобное этому при определении своих отношений:
$this->has_many_and_belongs_to('User')->with('playcount');
Пример
Я просто использовал это, чтобы убедиться, что он работает...
class Song extends Eloquent {
function users()
{
return $this->has_many_and_belongs_to('User')->with('playcount');
}
}
class User extends Eloquent {
function songs()
{
return $this->has_many_and_belongs_to('Song')->with('playcount');
}
}
// My test method
class TestOrm extends PHPUnit_Framework_TestCase {
public function testSomethingIsTrue()
{
foreach(User::find(3)->songs()->order_by('playcount')->get() as $song)
echo $song->name, ': ', $song->pivot->playcount, "\n";
echo "\n";
foreach(User::find(3)->songs()->order_by('playcount','desc')->get() as $song)
echo $song->name, ': ', $song->pivot->playcount, "\n";
}
}
Выход
Jingle Bells: 5
Mary had a little lamb: 10
Soft Kitty: 20
The Catalyst: 100
The Catalyst: 100
Soft Kitty: 20
Mary had a little lamb: 10
Jingle Bells: 5
Примечание. Не случайно, что без использования order_by()
результат выглядит отсортированным в ascending
порядке playcount
. Я подтвердил это путем тестирования (поскольку пока не знаю, как отображать запросы в модульных тестах), но вы, вероятно, не должны полагаться на это поведение.
Ответ 3
Любой метод, доступный в Fluent, также должен быть доступен с Eloquent. Возможно, это то, что вы ищете?
$songs = Song->join('song_user', 'songs.id', '=', 'song_user.song_id')
->where('song_user.user_id', '=', $user->id)
->orderBy("song_user.play_count", "desc")
->get();
Ответ 4
Я делал это (на нескольких сборках) просто используя метод отношений, как у вас. Я часто использую столбец "порядок" в сводной таблице, а затем делаю что-то вроде этого.
$article->tags()->order_by( 'order')->get();
Это может быть неоднозначным, если в таблице соединения есть столбцы с именем "порядок". Если это так, вам нужно указать → order_by ('article_tag.order'). И да, вам нужно использовать → with(), чтобы получить этот столбец в результирующем наборе. Как только вопрос стиля, я оставил бы метод with() из метода отношений и вместо этого вернул бы объект отношений с ванилью.
Ответ 5
В вашей модели Eloquent вы можете связать столбец orderBy, если вы включаете имя таблицы:
return $this->belongsToMany('App\Post')->withTimestamps()->orderByDesc('posts.created_at');