2014-04-04 5 views
11

Sto cercando di ottenere relazioni innestate Eager-Loading, con vincoli, per funzionare. Ognuno sembra dare lo stesso esempio di ansioso-carico relazioni annidate:Laravel 4.1 Eager Caricamento relazioni nidificate con vincoli

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

Quello che voglio fare, invece è ottenere tutti i gli utenti connessi ad un post di un dato id. Ma allo stesso tempo, voglio anche ottenere i commenti associati a quel post.

In 4.1, ho per raggiungere il secondo, ho potuto fare:

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

C'è un modo per sposare questa due e vincolare una relazione annidata?

risposta

8

effettivamente trovato un molto più semplice del pensiero

Attribuite questi modelli:

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'); 
    } 

} 

Possiamo quindi recuperare un utente che ha un determinato posto in questo modo:

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

Questo non funziona quando si utilizza get() in quanto non vincolare gli utenti solo a quelli relativi al post specificato. Ma questo è OK dal momento che ci interessa solo un post di post_id $ postId. Poiché un post appartiene a uno e solo un utente, non dobbiamo preoccuparci degli altri utenti. Potremmo quindi utilizzare find() o first() per ottenere i risultati effettivi.

Inoltre, il rapporto cioè 'post' 'mezzo' viene restituito automaticamente e possiamo farlo nel modo seguente, senza dover utilizzare un extra 'con' come suggerito nella risposta precedente:

var_dump($user->posts); 
3

E 'difficile da raggiungere che, nel contesto di user-> Post-> Commento, ma si può facilmente fare questo a partire dal messaggio se quel seme si:

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

quanto caricherà tutti gli utenti e tutti commenti relativi al post specificato.

- edit: Non fidarti la prima frase, è semplice come questo:

// $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(); 

mente però che laravel verrà eseguito 3 interrogazioni per avere fatto

+0

Ho appena notato che è necessario restituire un oggetto utente perché il mio controller (e la vista) si aspettano un oggetto utente. Sarebbe molto costoso fare un altro controllo in seguito per determinare quale oggetto sia. – kJamesy

+0

modificato, controllalo ora –

+0

Grazie per il tuo contributo. Abbiamo scoperto che non è necessario utilizzare l'extra 'with' o 'whereHas'. La sua conclusione in base a dove ('post_id', $ id ') ci darà tutto ciò di cui abbiamo bisogno. E poiché un post appartiene a un solo utente, dovremmo usare find() o first() invece di get(). – kJamesy

7

Se i rapporti nei modelli sono corretti si può semplicemente fare:

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

È possibile aggiungere il numero di relazioni come si desidera (o fino al limite di memoria;)).

Funziona anche con tabelle pivot.

+0

Ho votato perché non hai letto la domanda. La risposta che hai dato è in realtà suggerita nella domanda di essere la risposta sbagliata. – kJamesy

+0

Inoltre, volevo solo menzionare che il metodo di relazione nel modello deve essere 'public', non' protected' né 'private'. (Di solito vado con 'protected') – IIllIIll