Question

I am trying to create a page where I can see all the people in my database and create edits on them. I made a form where I fill in the data from the database of certain fields.

I would like to navigate trough them by a Next and Previous button.

For generating the next step I have to take the ID larger than the current one to load the next profile.

For generating the previous step I have to take the ID smaller than the current one to load the previous profile.

My route:

Route::get('users/{id}','UserController@show');

Controller:

public function show($id)
    {

        $input = User::find($id);

        // If a user clicks next this one should be executed.
        $input = User::where('id', '>', $id)->firstOrFail();



        echo '<pre>';

        dd($input);

        echo '</pre>';

        return View::make('hello')->with('input', $input);
    }

View: The buttons:

<a href="{{ URL::to( 'users/' . $input->id ) }}">Next</a>

What is the best approach to get the current ID and increment it?

Was it helpful?

Solution

Below are your updated controller and view files derived from @ridecar2 link,

Controller:

public function show($id)
{

    // get the current user
    $user = User::find($id);

    // get previous user id
    $previous = User::where('id', '<', $user->id)->max('id');

    // get next user id
    $next = User::where('id', '>', $user->id)->min('id');

    return View::make('users.show')->with('previous', $previous)->with('next', $next);
}

View:

<a href="{{ URL::to( 'users/' . $previous ) }}">Previous</a>
<a href="{{ URL::to( 'users/' . $next ) }}">Next</a>

OTHER TIPS

// in your model file
public function next(){
    // get next user
    return User::where('id', '>', $this->id)->orderBy('id','asc')->first();

}
public  function previous(){
    // get previous  user
    return User::where('id', '<', $this->id)->orderBy('id','desc')->first();

}
// in your controller file
$user = User::find(5); 
// a clean object that can be used anywhere
$user->next();
$user->previous();

In your App\Models\User.php

...
protected $appends = ['next', 'previous'];

public function getNextAttribute()
{
    return $this->where('id', '>', $this->id)->orderBy('id','asc')->first();
}

public function getPreviousAttribute()
{
    return $this->where('id', '<', $this->id)->orderBy('id','asc')->first();
}

In your Controller you can simply do this:

public function show(User $user)
{
    return View::make('users.show')
    ->with('user', $user)
    ->with('previous', $user->previous)
    ->with('next', $user->next);
}

I understand the approach being taken here by user2581096 but I am not sure it is efficient (by any standards). We are calling the database 3 times for really no good reason. I suggest an alternative that will be way more efficient and scalable.

Do not pass the previous and next IDs to the view. This eliminates 2 unnecessary database calls.

Create the following routes:

users/{id}/next

users/{id}/previous

These routes should be used in the href attributes of the anchor tags

Add methods in the controller to handle each of the new routes you have created. For example:

 public  function getPrevious(){
        // get previous  user
        $user = User::where('id', '<', $this->id)->orderBy('id','desc')->first();
        return $this->show($user->id);
    }

This function will only be called when you actually click on the button. Therefore, the database call is only made when you need to actually look up the user.

To get next and previous post we can use max and min functions on Model id in laravel. here is an example to get this https://usingphp.com/post/get-next-and-previous-post-link-in-laravel The Controller:

public function post($id)
{
    $post = Post::find($id);
    $previous = Post::where('id', '<', $post->id)->max('id');
    $next = Post::where('id', '>', $post->id)->min('id');
    return view( 'post', compact( 'post', 'next', 'previous' ));
}

The View:

@if($next)
   <a href="{{ route( 'blog.show', $next->id ) }}">{{$next->title}}</a>
@endif
@if($previous)
   <a href="{{ route( 'blog.show', $previous->id ) }}">{{$previous->title}}</a>
@endif

Here's a link I found that should help: http://maxoffsky.com/code-blog/laravel-quick-tip-get-previous-next-records/

It looks like for next you want to use: $next = User::where('id', '>', $id)->min('id'); and have the view as: <a href="{{ URL::to( 'users/' . $next->id ) }}">Next</a>

Also don't forget to pass $next to the view.

Simplest approach

// User.php
public static function findNext($id)
{
    return static::where('id', '>', $id)->first();
}

// UserController.php
$nextUser = User::findNext($id);

// view
<a href="{{ URL::to( 'users/' . $nextUser->id ) }}">Next</a>

Lazy approach :

// view
<a href="{{ URL::to( 'users/' . $input->id . '/next') }}">Next</a>

// routes.php (should be optimized, this is just to show the idea)
Route::get('users/{user}/next', function($id) {
    $nextUser = User::findNext($id);
    return Redirect::to('user/' . $id);
});

in-case you want to retrieve the prev/next records along with their data, you can try

$id   = 7; // for example

$prev = DB::table('posts')->where('id', '<', $id)->orderBy('id','desc')->limit(1);
$next = DB::table('posts')->where('id', '>', $id)->limit(1);

$res = DB::table('posts')
        ->where('id', '=', $id)
        ->unionAll($prev)
        ->unionAll($next)
        ->get();

// now $res is an array of 3 objects
// main, prev, next
dd($res);

1- the query builder is usually much faster than eloquent.

2- with union we are now only hitting the db once instead of 3.

// yourModel.php
public function previous()
{
   return $this->find(--$this->id);
}

public function next()
{
   return $this->find(++$this->id);
}

Works like magic, you can chain it:

$prevprev = Model::find($id)->previous()->previous();
$nextnext = Model::find($id)->next()->next();

First, get a record out of the database.

    $post = Post::where('slug', $slug)->first();

With a database record, we can get the previous record where the record id is less than the id stored inside $post order by the id in descending order and use first() to get a single record back.

    $previous = Post::where('id', '<', $post->id)->orderBy('id','desc')->first();

To get the next record it's almost the same query, this time get the record where the id is more than the id stored in $post.

    $next = Post::where('id', '>', $post->id)->orderBy('id')->first();

Controller:

public function show($id)
{
    // get the current user
    $user = User::find($id);

    // get previous user id
    $previous = User::offset($user->id-2)->first();

    // get next user id
    $next = User::offset($user->id)->first();

    return View::make('users.show')->with('previous', $previous)->with('next', $next);
}

i developed the code.

it work all times, even if we don't have any next or prev post

public function nextPost($table, $id)
{
    $next = DB::table($table)->where('id', '>', $id)->orderBy('id','asc')->first();
    if(!$next)
        $next = DB::table($table)->orderBy('id','asc')->first();

    return $next;
}

public function prevPost($table, $id)
{
    $prev = DB::table($table)->where('id', '<', $id)->orderBy('id','desc')->first();
    if(!$prev)
        $prev = DB::table($table)->orderBy('id','desc')->first();
    return $prev;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top