cosminc's avatar

Applying pagination on a modified Eloquent collection

Hello,

Because I can't apply some filters directly in the database I need to filter the resulting Eloquent collection and then apply pagination to it.

Unfortunately ->paginate() doesn't work after you fetched the results with ->get() so I'm curious what are my options here.

After doing some research I found this function that somehow solves my problem:

public function paginate($items, $perPage = 15, $page = null, $options = []) {
    $page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
    $items = $items instanceof Collection ? $items : Collection::make($items);
    return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}

The problem is that by using it I'm loosing the possibility to use accessors like ->getEmailAttribute().

Here's a simplified code snippet just to have something to work with:

<?php

public function myFunction(array $filters, int $perPage) {
	$results = MyModel::distinct()
		->where('some_column', 'some value')
		->where('other_column', 'other value')
		->orderBy('this_column', ASC)
		->get();


	$results = $results->each(function($item) use ($filters) {
		return $item->filtered_column == $filters['first_filter'];
	});

	// Ideally I would love something like...
	return $results->paginate($perPage);
}
0 likes
2 replies
MichalOravec's avatar
Level 75

Add this macro to your AppServiceProvider to the boot method and pagination will work also on collection.

use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;

public function boot()
{
    Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
        $page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);

        return new LengthAwarePaginator($this->forPage($page, $perPage), $total ?: $this->count(), $perPage, $page, [
            'path' => LengthAwarePaginator::resolveCurrentPath(),
            'pageName' => $pageName,
        ]);
    });
}
1 like

Please or to participate in this conversation.