Подтвердить что ты не робот

Как сортировать по полю сводной таблицы отношений "многие ко многим" в "Красноречивой 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");
    }))
4b9b3361

Ответ 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');