movepixels's avatar

Find Neighbors

Is there a method or functionality in Laravel to find the record before and after a record?

Example: display a page / pagination Query database with whatever params and say return 25 records. Click on say the 6th record you go to view that page but you want to say to the user Next Profile / Previous Profile how would you then from the original query get record #5 for previous and #7 for Next?

CakePHP has a findNeighbours() but wondering if there is something similar for Laravel or how would be the best way to solve this issue?

Thanks,

Dave

0 likes
5 replies
burlresearch's avatar

It would be up to you define "what is a neighbor" and to implement that yourself.

You could start by making this a function on your Model, and refactor from there if you want a Repository pattern, or whatever you like.

It's up to you do define your concept of adjacency. If by next / prev you just want to go by ID's then you could do something like:

class Profile extends Model {
    public function next() {
        return self::find($this->id + 1);
    }
    public function prev() {
        return self::find($this->id - 1);
    }
}

The usage for this then would be when you're fetching Profiles:

php artisan tinker

>>> Profile::find(1)->prev()
=> null
>>> Profile::find(1)->next()
=> App\Profile {#2922
     id: 2,
     created_at: "2018-11-01 22:38:23",
     updated_at: "2018-11-01 22:38:23",
   }
jlrdw's avatar

You may need to select (limit 1), Max ID that's less than the current ID and Min ID that's greater than current ID.

Regular ID number would not work if some have been deleted.

But really this is just basic SQL something any developer should know how to handle.

Snapey's avatar
Snapey
Best Answer
Level 122

In your show method for the profile, you need to run the same query as on the index page, but just pluck the ID's (same query so that the same scope and sort order is used) and don't paginate.

You will then have an array of model IDs in an array.

Find the current ID in the array and get the array index +1 and -1 and pass these to the view as the IDs for next and previous.

Something like;

public function show(Request $request, $id)
{

    $profilesList = Profile::orderBy('name')->pluck('id');

    $index = $profilesList->search($id);

    ($index == 0)? $previous = 0 : $previous = $profilesList[$index-1];

    ($index == count($profilesList)? $next = $id : $next = $profilesList[$index+1];
    
    $profile = Profile::find($id);

    return view('profile.show')
        ->withProfile($profile)
        ->withNext($next)
        ->withPrevious($previous);

}

In the view, hide the previous button if $previous==0 and hide next button if $next == $profile->id

movepixels's avatar

Thanks guys for the insight will give it a try!

Dave

Snapey's avatar

You could cache the profileList query so that it does not get re-queried as you step through each page

Please or to participate in this conversation.