2014-10-15 10 views
5

Ho un post tabella e commenti tabella, il commento appartiene al post e ho impostato la relazione nel modello Post e Comment. Ho sorta messaggi per il numero di commenti di ogni post come questo:Laravel sortBy paginate

 $posts = Post::with('comments')->get()->sortBy(function($post) { 
      return $post->comments->count(); 
     }); 

Quello che mi chiedo è come posso impaginare questi posti ordinati?

 $posts = Post::with('comments')->get()->sortBy(function($post) { 
      return $post->comments->count(); 
     })->paginate(20); 

non funziona e mi dà errore che dice che paginate è un metodo indefinito.

risposta

4

Non so se si può farlo utilizzando Eloquente ma è possibile utilizzare uniscono per questo:

$posts = Post::leftJoin('comments','posts.id','=','comments.post_id')-> 
       selectRaw('posts.*, count(comments.post_id) AS `count`')-> 
       groupBy('posts.id')-> 
       orderBy('count','DESC')-> 
       paginate(20); 

Tuttavia sembra che in questo caso tutti i record sono presi dal database e visualizzati solo quelli da Paginator quindi se hai molti record è uno spreco di risorse. Sembra che si dovrebbe fare impaginazione manuale per questo:

$posts = Post::leftJoin('comments','posts.id','=','comments.post_id')-> 
       selectRaw('posts.*, count(comments.post_id) AS `count`')-> 
       groupBy('posts.id')-> 
       orderBy('count','DESC')-> 
       skip(0)->take(20)->get(); 

utilizzando skip e take, ma io non sono Eloquente esperto e forse c'è una soluzione migliore per raggiungere il tuo obiettivo in modo da poter aspettare e forse qualcuno darà una risposta migliore .

+0

Thansk, così tanto per essere chiari, questa soluzione non sarà recupera tutti i record dal database e poi li risolve, recupera solo 20 record all'inizio, giusto? – dulan

+0

@dulan, sì, se stiamo parlando del 2 ° codice. Nel primo codice tutti i record verranno recuperati dal database e visualizzati solo alcuni di essi, quindi è necessario scegliere la seconda soluzione –

+0

grazie per l'utilizzo di skip() –

0

Basta rimuovere il get() nelle chiamate concatenate e vedere cosa ottieni, impaginato deve sostituire la chiamata get().

+0

Non funzionerà. 'sortBy' è usato per il set di risultati, quindi l'uso di paginate fa sì che l'ordinamento venga eseguito solo per le prime 20 righe e non per tutti i record. Questa è la differenza. Ordinare prima quindi impaginare non opposto –

+0

Gli ho consigliato di rimuovere get(), non di sostituirlo con paginate(), paginate lo sostituirà funzionalmente. – cdarken

1

Sembra ovvio, ma Eloquent non restituirà un risultato impostato qui, ma restituirà una raccolta.

Se si scava nella fonte (Builder::get chiamate Builder::getFresh, che chiama Builder::runSelect, che chiama Connection::select), troverete che è intenzione è di tornare semplicemente i risultati, che vengono poi inseriti in una collezione (che ha la SortBy metodo).

/** 
* Run a select statement against the database. 
* 
* @param string $query 
* @param array $bindings 
* @param bool $useReadPdo 
* @return array 
*/ 
public function select($query, $bindings = array(), $useReadPdo = true) 
{ 
    return $this->run($query, $bindings, function($me, $query, $bindings) use ($useReadPdo) 
    {  
    if ($me->pretending()) return array(); 

    // For select statements, we'll simply execute the query and return an array 
    // of the database result set. Each element in the array will be a single 
    // row from the database table, and will either be an array or objects. 
    $statement = $this->getPdoForSelect($useReadPdo)->prepare($query); 

    $statement->execute($me->prepareBindings($bindings)); 

    //** this is a very basic form of fetching, it is limited to the PDO consts. 
    return $statement->fetchAll($me->getFetchMode()); 
    }); 
} 

Se si desidera avere la paginazione senza caricare ogni elemento, allora avete bisogno di usare @ la soluzione di Marcin (duplicato sotto):

$posts = Post::leftJoin('comments','posts.id','=','comments.post_id')-> 
      selectRaw('posts.*, count(comments.post_id) AS `count`')-> 
      groupBy('posts.id')-> 
      orderBy('count','DESC')-> 
      skip(0)->take(20)->get(); 
Problemi correlati