15

私はlaravelフレームワークを使用するためにいくつかのデータベーススキーマを定義しようとしています。サッカーの試合をモデル化したい。私がやりたかった最初のステップは、実体関連図を定義することですが、これ(これは非常に些細なことだと思いました)がいくつかの面で混乱していることがわかりました。

まず、明らかなアプローチは、試合は2つのチームに関連しており、チームは任意の数の試合に関連していると言うことです。したがって、「多対多」の関係になります。

しかし、多対多の関係の実装は、両方のエンティティを関連付けるために2つのテーブルと1つの中間テーブルを持つことです。マッチには常に2つのチームがあり、Teamsテーブルへの外部キーを持つ2つの列(local_idとvisitant_id)があるだけで十分であることがわかっている場合、これは多すぎると思います。さらに、私はできることをしたい:

Match::find(1)->local() or Match::find(1)->visitant();

それで、これを考えて、私は「1対多」の関係を実装していますが、これには別の問題があります。チームがプレイしたすべての試合を取得するには、次のようにします。

Team::find(1)->matches(); 

ただし、eloquentでmatches()メソッドを定義するときに指定できるキー列は1つだけなので、これを行うことはできません(デフォルトでは、team_idになりますが、visitant_idとlocal_idである必要があります)。

4

2 に答える 2

34

ソースコードをさらに掘り下げた後、データベーススキーマを実際にそのままにして、(少なくともLaravel 4では)必要なものを実現する方法があることがわかりました。私は自分の問題をgithubに投稿し、Taylor Otwell(フレームワークの作成者)が正しい答えをくれました:https ://github.com/laravel/framework/issues/1272

彼を引用すると、それはこれと同じくらい簡単なはずです:

class Team extends Eloquent  {
    public function allMatches()
    {
        return $this->hasMany('Match', 'visitant_id')->orWhere('local_id', $this->id);
    }
}

その後...

$team = Team::find(2);
$matches = $team->allMatches;
于 2013-05-13T17:45:45.220 に答える
3

これは、それらの有名なデータベース設計の問題の1つです。たとえば、友情関係も同じ困難に苦しんでいます。Eloquentを使用しているので、多対多のアプローチに固執しlocal、中間テーブルに追加のブール列を設定することをお勧めします

class Match extends Eloquent {
    public $includes = array('team'); // Always eager load teams
    public function teams() {
        return $this->has_many_and_belongs_to('team')->with('local');
    }
    public function get_local() {
        foreach ($this->teams as $team) {
            if ($team->pivot->local) return $team;
        }
    }
    public function get_visitant()   {
        foreach ($this->teams as $team) {
            if (!$team->pivot->local) return $team;
        }
    }
}

class Team extends Eloquent  {
    public function matches() {
        return $this->has_many_and_belongs_to('match')->with('local');
    }
    // I'm doing separate queries here because a team may have
    // hundreds of matches and it's not worth looping through
    // all of them to retrieve the local ones
    public function matches_as_local()  {
        return $this->has_many_and_belongs_to('match')->with('local')
            ->where('pivot_local', '=', 1);
    }
    public function matches_as_visitant()  {
        return $this->has_many_and_belongs_to('match')->with('local')
            ->where('pivot_local', '=', 0);
    }
}

Obs:

この方法has_many_and_belongs_to(...)->with('field')は、積極的な読み込みとは何の関係もありません。Eloquentに、中間テーブル列をロードfieldしてピボットに配置するように指示します。

使用法:

$match = Match::find(1);

$match->local; // returns local team
$match->visitant; // returns visitant team

$team = Team::find(1);
$team->matches; // returns all matches
$team->matches_as_local; // ...
$team->matches_as_visitant; // ...

foreach ($team->matches as $match) {
    if ($match->pivot->local) {
        // put nice local icon here
    } else {
        // put nice visitant icon here
    }
}
于 2013-03-27T01:44:07.250 に答える