Laravel 4: en una relación anidada, ¿cómo ansío cargar y recuperar solo los primeros / últimos datos?

A : User, B : Conversations, C : Messages 

Quiero unirme a la conversación con su mensaje más reciente en una relación A-> B-> C de A.

Relaciones de trabajo en el modelo

 User belongsToMany Conversation Conversation belongsToMany User Conversation hasMany Message Message belongsTo Conversation User hasMany Message Message belongsTo User **note: User and Conversation are related to a many2many relationship connected by a pivot table 

He intentado

 $user->load(['conversations' => function($q) { $q->orderBy('created_at', 'desc'); $q->with('Messages')->orderBy('created_at','desc'); }]); 

Casi funcionó, pero no recibe el último mensaje. En cambio, carga todos los mensajes que pertenecen a esa conversación.

Resultado no deseado del código anterior

 array (size=7) 'id' => int 90 'name' => string 'haha,hehe' (length=9) 'created_at' => string '2014-07-03 15:04:04' (length=19) 'updated_at' => string '2014-07-03 15:04:04' (length=19) 'microseconds' => string '1404370893302' (length=13) 'pivot' => array (size=2) 'user_id' => int 1 'conversations_id' => int 90 'messages' => array (size=27) 0 => ... 1 => ... ... 26 => array (size=7) 'id' => int 816 'user_id' => int 1 'conv_id' => int 90 'body' => string 'test1' (length=5) 'created_at' => string '2014-07-03 01:13:35' (length=19) 'updated_at' => string '2014-07-03 01:13:35' (length=19) 'microseconds' => string '1404350015499' (length=13) 

Resultado Esperado

 array (size=7) 'id' => int 90 'name' => string 'haha,hehe' (length=9) 'created_at' => string '2014-07-03 15:04:04' (length=19) 'updated_at' => string '2014-07-03 15:04:04' (length=19) 'microseconds' => string '1404370893302' (length=13) 'pivot' => array (size=2) 'user_id' => int 1 'conversations_id' => int 90 'messages' => array (size=1) 0 => array (size=7) 'id' => int 816 'user_id' => int 1 'conv_id' => int 90 'body' => string 'test1' (length=5) 'created_at' => string '2014-07-03 01:13:35' (length=19) 'updated_at' => string '2014-07-03 01:13:35' (length=19) 'microseconds' => string '1404350015499' (length=13) 

Cuando pones get (o first / find etc para ese asunto) en el cierre, ejecuta la consulta una vez más, pero esa consulta se ignora, y luego Eloquent ejecuta esa consulta de nuevo:

 $user->load(['conversations' => function($q) { $q->orderBy('created_at', 'desc'); $q->with('Messages')->orderBy('created_at','desc') ->get() // this query is executed here ->first(); // this calls first method on the collection // but those 2 lines above take no effect with the eager load models // because Eloquent will execute the query again in the end }]); 

Así es como pones restricciones en la relación anidada ( pero no hará el trabajo aquí ):

 User::with(['conversations.messages' => function ($q) { $q->orderBy(...)->where(...) ...; // but limit(1) can't be used here }])->get(); 

Limit no se puede usar porque limita todo el conjunto a 1, por lo que solo se devolverá un mensaje en total. Dicho esto, solo 1 conversación habrá cargado un solo mensaje en una colección. Totalmente erróneo


Entonces, la única forma de lograr esto con Eloquent es esta relación de ‘ayuda’:

 // Conversation model public function latestMessage() { return $this->hasOne('Message')->latest(); } // then simply: $user->load('conversations.latestMessage'); $user->conversations->first()->latestMessage; // single Message model 

Intenta usar;

 User::with('conversations', 'conversions.messages') 

Y con eso puedes agregar tus ansiosos problemas de carga con un cierre como;

 User::with(array('conversations' => function(){}, 'conversions.messages' => function(){}) 

Tenga en cuenta que esto no está probado.