Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

hal9k's avatar
Level 5

How to limit pagination to X items/pages

Hello,

I'm making a simple video site and I'm trying to display top 100 videos for each genre, split to 20 videos per page (total 5 pages).

This is what I have right now

$top100videos = Videos::where('genre', $genre)
                    ->orderby('rating', 'desc')
                    ->with('actors')
                    ->paginate(20);

but that returns every single video I have and paginates it. I have tried using ->take(100) but this doesn't work since paginatie already uses offset() and take(). It really sucks that I can't use take() with paginate()!

Does anyone has an idea how to solve this?

Thanks!

0 likes
22 replies
lara65535's avatar

Why not add in a column to the videos called ranking? Add in a where clause like

->andWhere('rank', '<=', 100)

That then will fetch all items with a rank under 100 for a specified genre

Edit* If rating is your rank then simply do...

$top100videos = Videos::where('genre', $genre)
                    ->andWhere('rating', '<=', 100)
                    ->orderby('rating', 'desc')
                    ->with('actors')
                    ->paginate(20);
1 like
jlrdw's avatar

Please dig in the docs, skip take is all there:

skip / take

To limit the number of results returned from the query, or to skip a given number of results in the query, you may use the skip and take methods:

$users = DB::table('users')->skip(10)->take(5)->get();

Alternatively, you may use the limit and offset methods:

$users = DB::table('users')
                ->offset(10)
                ->limit(5)
                ->get();
hal9k's avatar
Level 5

@gofish543 I don't want all videos with 100 rank/score than first 100 videos ordered by rank/score.

@topvillas I have tried that too - but it doesn't work :(

@jirdw I know how skip/take and offset/limit works but I don't think that it will work with paginate, and also I don't want to paginate query builder results collection than eloquent objects collection.

lara65535's avatar

Yes, if you use the <= sign in the query it will take rank/score of 1-100 and then paginate it by 20. This gives 5 blocks of 20 scores with each block representing 1-20, 21-40, 41-60, 61-80, and 81-100 respectivly

hal9k's avatar
Level 5

@goldfish543 This table can have thousands of clips... The rating is used just to order the clips by user rating and nothing else. It can't be used to fetch 100 videos since you don't know their ratings...

lara65535's avatar

https://github.com/laravel/framework/issues/4629

$top100videos = Videos::where('genre', $genre)
                    ->orderby('rating', 'desc')
                    ->with('actors')
                    ->take(100)
                    ->get()

$videos = Paginator::make($top100videos->toArray(), $top100videos->count(), 100);

What appears to be happening is you are forced to make the query, and limit your results. Then take that collection and make a paginator out of it.

hal9k's avatar
Level 5

I have seen that but that's old (laravel 4) and Paginator::make doesn't work now.

It appears that I can create a paginator object but the code looks really messy and uses array (not eloquent objects so I can't call methods on them) so I'm looking if there's some better and cleaner way to do it...

lara65535's avatar

Edit* Have you tried using a LengthAwarePaginator?

use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
$currentPage = LengthAwarePaginator::resolveCurrentPage();

$top100videos = Videos::where('genre', $genre)
                      ->orderby('rating', 'desc')
                      ->with('actors')
                      ->take(/* How many you want */)
                      ->get()

$perPage = /* Per page Number */;

$currentPageSearchResults = $collection->slice($currentPage * $perPage, $perPage)->all();

$paginatedTop100 = new LengthAwarePaginator($currentPageSearchResults, count($collection), $perPage);

return view(/* Insert View */, ['top100' => $paginatedTop100 ]);

and then the view

@foreach ($top100 as $top)
    {{ $top }}
@endforeach

{{ $top100->render() }}
1 like
hal9k's avatar
Level 5

I'll give it a try...

Still looks far more comples than simple ->take(100)

:)

jlrdw's avatar

This post has gotten funny I gave the answer above all of those query-builder methods are available in the orm also.

hal9k's avatar
hal9k
OP
Best Answer
Level 5

The LengthAwarePaginator woks... I had just to modify this line since offsets were wrong:

$currentPageSearchResults = $collection->slice($start, $perPage)->all();

Also had to add this above it to calculate the start correctly:

if ($currentPage==1) {
    $start = 0;
}
else {
    $start = ($currentPage-1) * $perPage;
}

Since for the first page $currentPage * $perPage equals 20 so on the first page it would start from 20th item (instead from 1st - zero one) and then at last page it would have nothing to show...

Anyway, this solution works... I hope that Paginator would soon be compatible with take() or limit() so this can be done easier...

In the meantime here's the entire code:

$collection = Videos::where('genre', $genre)
                      ->orderby('rating', 'desc')
                      ->with('actors')
                      ->take(100)
                      ->get()


$perPage = 20;

$currentPage = LengthAwarePaginator::resolveCurrentPage();

if ($currentPage == 1) {
    $start = 0;
}
else {
    $start = ($currentPage - 1) * $perPage;
}

$currentPageCollection = $collection->slice($start, $perPage)->all();

$paginatedTop100 = new LengthAwarePaginator($currentPageCollection, count($collection), $perPage);

$paginatedTop100->setPath(LengthAwarePaginator::resolveCurrentPath());


return view('top100videos', ['top100' => $paginatedTop100 ]);
jlrdw's avatar

You didn't read the whole issue. The person did not know what they were doing who created the issue.

hal9k's avatar
Level 5

How come? What did I miss?

Snapey's avatar

late now I know, but I would probably run 2 queries, one to take(100) entries and then pluck() the id's then do a second wherein($ids)->paginate(20);

4 likes
hal9k's avatar
Level 5

Not a bad idea at all! I'll try it out tomorrow... Thanks for the input...

jlrdw's avatar

Wow that is something I used appends often in version 5.1 but there is a problem with it in 5.4 I hope they fix it.

jlrdw's avatar

I closed above issue and am just using a Lengthaware now.

hal9k's avatar
Level 5

@Snapey - tried your way... works like charm and it's super clean and readable... Thank you for your input!

ahmadissa's avatar

@Snapey Your are genius, thank you for the idea it really solved a big issue for me.

Please or to participate in this conversation.