Laravel sortBy paginate
У меня есть таблица постов и таблица комментариев, комментарий принадлежит посту, и у меня есть настройка отношений в модели Пост и комментарий. Я сортировал посты по количеству комментариев каждого поста так:
$posts = Post::with('comments')->get()->sortBy(function($post) {
return $post->comments->count();
});
Что мне интересно, так это как я могу разбить эти отсортированные посты на страницы?
$posts = Post::with('comments')->get()->sortBy(function($post) {
return $post->comments->count();
})->paginate(20);
не работает и выдает ошибку, в которой говорится, что paginate - неопределенный метод.
3 ответа
Я не знаю, можете ли вы сделать это с помощью Eloquent, но вы можете использовать для этого соединение:
$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);
Однако, похоже, что в этом случае все записи берутся из базы данных и отображаются только записи из paginator, поэтому, если у вас много записей, это пустая трата ресурсов. Кажется, вы должны сделать ручную нумерацию страниц для этого:
$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();
с помощью skip
а также take
но я не эксперт по Eloquent и, возможно, есть лучшее решение для достижения вашей цели, так что вы можете подождать, и, возможно, кто-то даст лучший ответ.
Это звучит очевидно, но Eloquent не будет возвращать набор результатов здесь, а вернет коллекцию.
Если копаться в источнике (Builder::get
звонки Builder::getFresh
, который вызывает Builder::runSelect
, который вызывает Connection::select
), вы обнаружите, что он намерен просто вернуть результаты, которые затем помещаются в коллекцию (которая имеет метод sortBy).
/**
* 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());
});
}
Если вы хотите выполнить нумерацию страниц без загрузки каждого элемента, вам нужно использовать решение @Marcin (продублировано ниже):
$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();
Просто удалите get()
в цепочечных вызовах и посмотреть, что вы получаете, paginate должен заменить вызов get().