2013-03-26 9 views
13

Ich habe versucht, einige Datenbankschema zu definieren, um das Laravel-Framework zu verwenden. Ich möchte ein Fußballspiel modellieren. Der erste Schritt, den ich machen wollte, ist das Entity Relationship Diagramm zu definieren, aber ich fand das (was ich für ziemlich trivial hielt) in einigen Aspekten verwirrend.Datenbank eins zu viele mit zwei Fremdschlüsselfeldern in Laravel

Erstens ist der offensichtliche Ansatz zu sagen, dass ein Match mit zwei Teams zusammenhängt und ein Team mit einer beliebigen Anzahl von Matches verbunden ist. Wir hätten also eine "Viele zu Viele" -Beziehung.

Aber die Implementierung einer Viele-zu-viele-Beziehung besteht darin, zwei Tabellen und eine Zwischentabelle zu haben, um beide Entitäten in Beziehung zu setzen. Ich denke, das wäre zu viel, wenn ich weiß, dass ein Match immer zwei Teams hat und einfach zwei Spalten (local_id und visitant_id) mit Fremdschlüsseln für den Teamtisch haben würde. Außerdem möchte ich tun können:

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

Also, auf das ich dachte, ich ein „one to many“ -Beziehung bin der Umsetzung, aber mit diesem habe ich ein anderes Problem. Zum Abrufen alle Spiele ein Team spielte hat, würde ich tun:

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

Aber ich kann das nicht tun, weil ich nur eine Schlüsselspalte angeben können, wenn die Spiele definieren() -Methode in beredten (standardmäßig wäre es team_id, aber es sollte visitant_id und local_id sein.

Antwort

31

Nach etwas mehr gräbt in die Quellcode ich dort gefunden ist ein Weg, um tatsächlich mein Datenbankschema zu halten, wie es ist und zu erreichen, was ich will (zumindest in Laravel 4) . Ich stellte mein Problem in Github und Taylor Otwell (Konzept des Frameworks) gab mir die richtige Antwort: https://github.com/laravel/framework/issues/1272

Zitiert ihn, sollte es so einfach wie diese:

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

Und dann ...

$team = Team::find(2); 
$matches = $team->allMatches; 

Update: Der github Link nicht funktioniert, weil Laravel mehr nicht Bugreports auf diese Weise nehmen: http://laravel-news.com/2014/09/laravel-removes-github-issues/

+0

für mich diese Rückkehr nur "visitant_id" verwandte Modelle ... – ciccioassenza

+0

Dies funktioniert immer noch in Laravel 5.2 – arleslie

+0

In Laravel 5.3 $ Dies ist ein leeres Modellobjekt. Irgendwelche Ideen, wie das in Laravel 5.3 zu erreichen? –

3

Dies ist eines dieser berühmten Datenbank-Design-Probleme. Freundschaftsbeziehungen leiden zum Beispiel unter derselben Schwierigkeit. Da Sie Eloquent verwenden, würde ich vorschlagen, dass Sie mit vielen zu vielen Ansatz zu bleiben und haben eine zusätzliche boolean Spalte local auf dem Zwischentisch

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:

Verfahren has_many_and_belongs_to(...)->with('field') nichts zu tun hat mit eifrigem Laden. Es teilt Eloquent mit, die Zwischentabellenspalte field zu laden und diese in den Pivot zu setzen.

Verbrauch:

$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 
    } 
}