2014-04-04 8 views
11

Próbuję działać, aby relacje zagnieżdżone z obciążeniem, z ograniczeniami, działały. Każdy zdaje się podając ten sam przykład chętny-załadunkowych zagnieżdżonych relacji:Laravel 4.1 Zachłanne ładowanie zagnieżdżonych relacji z ograniczeniami

$users = User::with('posts.comments')->get(); 

Co chcę zrobić zamiast tego jest uzyskanie wszystkich Użytkowników związane ze stanowiskiem danego id. Ale jednocześnie chcę również uzyskać komentarze związane z tym postem.

w 4.1, to aby osiągnąć ten ostatni, mogę zrobić:

$comments = Comment::whereHas('post', function($query) { $query->whereId(1); })->get(); 

Czy istnieje sposób, aby poślubić dwa i ograniczyć zagnieżdżony związek?

Odpowiedz

8

Faktycznie okazało się, że dużo łatwiejsze niż myśl.

Biorąc pod uwagę te modele:

class User extends \Eloquent { 

    public function posts() 
    { 
     return $this->hasMany('Post'); 
    } 

    public function comments() 
    { 
     return $this->hasManyThrough('Comment', 'Post'); 
    }  

} 

class Post extends \Eloquent { 

    public function user() 
    { 
     return $this->belongsTo('User'); 
    } 

    public function comments() 
    { 
     return $this->hasMany('Comment'); 
    }  

} 

class Comment extends \Eloquent { 

    public function post() 
    { 
     return $this->belongsTo('Post'); 
    } 

} 

Możemy przynieść użytkownikowi, który posiada daną wiadomość w taki sposób:

$userId = 2; $postId = 5; 
$user = User::with(['comments' => function($q) use($postId) { $q->where('post_id', $postId); }])->find($userId); 

to nie będzie działać przy użyciu get(), ponieważ nie ograniczać użytkowników do tylko tych związanych z danym postem. Ale to jest w porządku, ponieważ jesteśmy zainteresowani tylko jednym postem post_id $ postId. Ponieważ post należy do jednego i tylko jednego użytkownika, nie musimy martwić się o innych użytkowników. Możemy zatem użyć funkcji find() lub first(), aby uzyskać rzeczywiste wyniki.

Ponadto, „środkowy” stosunki czyli „post” jest automatycznie zwracana i możemy dostać go w następujący sposób bez konieczności używania dodatkowego „z” jak zasugerowano w poprzedniej odpowiedzi:

var_dump($user->posts); 
3

Jest to trudne do osiągnięcia, że ​​w kontekście user-> post-> Komentarz, ale łatwo można to zrobić już od Napisz jeśli to dla ciebie:

Post::with('users')->with('comments')->find(1); 

jak będzie załadować wszystkich użytkowników i wszystkich komentarze związane z danym wpisem.

- edit: Nie ufaj pierwsze zdanie, to jest tak proste, jak to:

// $id of the post you want 

User::with(['comments' => function ($q) { // this is hasManyThrough relation 
    $q->where('post_id',$id);    // comments only related to given post 
}])->with(['posts' => function ($q) { 
    $q->whereId($id);      // here we load only the post you want 
}])->whereHas('posts', function ($q) { 
    $q->whereId(1);       // here we filter users by the post 
})->get(); 

pamiętać jednak, że laravel potrwa 3 pytania, aby zrobić to

+0

Po prostu zauważyłem, że muszę zwrócić obiekt użytkownika, ponieważ mój kontroler (i widok) oczekują obiektu użytkownika. Kosztownym kosztem byłoby później wykonanie kolejnej kontroli w celu ustalenia, który to obiekt. – kJamesy

+0

edytowane, sprawdź teraz –

+0

Dzięki za twój wkład. Okazało się, że nie musimy używać dodatkowego "z" lub "whereHas". Kończąc go w miejscu, gdzie ('post_id', $ id ') dostarczy nam wszystkiego, czego potrzebujemy. A ponieważ post należy do tylko jednego użytkownika, powinniśmy użyć find() lub first() zamiast get(). – kJamesy

7

If relacje w modelach są poprawne można po prostu zrobić:

$user = User::with('posts.comments')->get(); 

można dodać dowolną liczbę kontaktów, jak chcesz (lub do limitu pamięci;)).

Działa również z tabelami przestawnymi.

+0

Głosowałem za tobą, ponieważ tak naprawdę nie przeczytałeś tego pytania. Odpowiedź, którą podałeś, jest właściwie sugerowana w pytaniu jako zła odpowiedź. – kJamesy

+0

Chciałem tylko wspomnieć, że metoda relacji w modelu musi być "public", a nie "protected" ani "private". (Zazwyczaj używam 'protected ') – IIllIIll