web-dev-qa-db-ja.com

Eloquent ORMで多対多の関係のピボットテーブルのフィールドで並べ替える方法

私はEloquent ORMをしばらく使用していて、それをよく知っていますが、次のことはできませんFluentでは非常に簡単です

私は多対多の曲を持つユーザーがいて、中間テーブルはsong_userである必要があります。再生回数から判断して、ユーザーの上位の曲を取得したい。もちろん、プレイカウントは中間テーブルに保存されます。

私は流暢にそれを行うことができます:

$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");
    }))
30
duality_

Laravel 4に移動する予定があるかどうかはわかりませんが、ピボットテーブルのフィールドでソートするための雄弁な例を次に示します。

public function songs() {
  return $this
    ->belongsToMany('Song')
    ->withPivot('play_count')
    ->orderBy('pivot_play_count', 'desc');
}

withPivotは雄弁なwithに似ており、ピボットテーブルのplay_countフィールドを、すでに含まれている他のキーに追加します。結果では、すべてのピボットテーブルフィールドの先頭にpivotが付いているため、orderByで直接参照できます。

Laravel 3でそれがどのように見えるかはわかりませんが、おそらくこれは正しい方向を示すのに役立ちます。

乾杯!

49
BigBlueHat

私はユーザーガイドで何かを見つけました、どうやら with() メソッドが必要です。

ユーザーガイド から:

デフォルトでは、ピボットテーブルの特定のフィールド(2つの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。私はこれをテストで確認しましたが(単体テストでクエリを表示する方法がまだわからないため)、おそらくこの動作に依存すべきではありません。

5
dualed

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();
1
Travis Bennett

私はこれを(いくつかのビルドで)単に関係メソッドを使用して行っています。私はピボットテーブルで 'order'列をよく使用し、次のようにします。

$article->tags()->order_by( 'order')->get();

結合テーブルに「order」という名前の列がある場合、これはあいまいになる可能性があります。その場合は、-> order_by( 'article_tag.order')を指定する必要があります。そして、はい、結果セットでその列を取得するには、-> with()を使用する必要があります。スタイルの問題として、with()を関係メソッドから除外し、代わりにVanilla関係オブジェクトを返します。

0
Collin James

Eloquentモデルでは、テーブル名を含めると、orderBy列をチェーンできます。

return $this->belongsToMany('App\Post')->withTimestamps()->orderByDesc('posts.created_at');
0
Josh LaMar