Framework: Links() render of Pagination broke when using SortBy()

Created on 27 Apr 2019  路  11Comments  路  Source: laravel/framework

  • Laravel Version: v5.8.14
  • PHP Version: 7.3
  • Database Driver & Version: PostgreSQL

Description:

When adding a sortBy() to a paginated query I returns the error:

Method Illuminate\Database\Eloquent\Collection::links does not exist.

Saying this function (which is default for pagination) isn't working:
{{ $results->links() }}
When I remove that function in the view, it does render correctly and also the same amount of items as given to the paginate function.

Steps To Reproduce:

Make a Query like this:

$results = Company::has('location')->paginate(10)->sortBy(function ($company) {
    return $company->location->distance; // for example
}); 

Add in the view: {{ $results->links() }} and then you'll see the error. Remove tat from the view and it'll work.

Most helpful comment

You can either swap the paginator's collection with the sorted collection

$results = Company::has('location')->paginate(10);

$results->setCollection(
    $results->sortBy(function ($company) {
        return $company->location->distance;
    })
);

All 11 comments

This is correct. The paginator forwards the "sortBy" call to the paginator's collection, returning the collection. Collections don't have a "links" method. There are many solutions on stackoverflow for handling this situation.

You can either swap the paginator's collection with the sorted collection, or build up a Paginator manually with the sorted data.

Either way, you'll probably get more help on one of the support channels:
Laracasts Forums
Laravel.io Forums
Discord
Larachat
IRC
StackOverflow

You can either swap the paginator's collection with the sorted collection

$results = Company::has('location')->paginate(10);

$results->setCollection(
    $results->sortBy(function ($company) {
        return $company->location->distance;
    })
);

@staudenmeir looks promising, but it sorts the distances of the given paginated values and no the whole collection of results ;-)

@Jaspur I don't see how that could be happening.

What does the result of dd($results->sortBy(...)); look like?

@staudenmeir the result is correct and shown as a paginator, but because you pagina to each 10 results.. it does the sorting for th谩t specific 10 results each time. you get what I mean? ;-)
there should be a full get() to fetch all results, then sort them by location and th茅n paginate them.

Now I see the issue, I misread your comment.

This requires a different query: You have to join the locations table and use orderBy().
Do you know what I mean?

Nope? @staudenmeir

Something like this:

$results = Company::select('companies.*')
    ->join('locations', 'locations.id', '=', 'companies.location_id')
    ->orderBy('locations.distance')
    ->paginate(10);

@staudenmeir the problem it that it can't do the orderBy(), because the distance is only available via the sortBy() because it's calculated afterwards and not stored in the database.

The implementation is immaterial to the original post. You'll have to figure out how to implement this and then swap the paginator's collection with what you need.

Was this page helpful?
0 / 5 - 0 ratings