jimmygns@me.com's avatar

pagination link doesn't work as expected

I just added a pagination to my view, and I did the following.

$currentPage = LengthAwarePaginator::resolveCurrentPage();
        $collection=collect($followers);
        $perPage=5;
        $currentPageResults = $collection->slice(($currentPage-1) * $perPage, $perPage)->all();

        //Create our paginator and pass it to the view
        $paginatedResults= new LengthAwarePaginator($currentPageResults, count($collection), $perPage);
        $paginatedResults->setPath($request->path());
        Log::info($request->path());
<ul class="list-group">
              @foreach($followers as $follower)
              <li class="list-group-item">
              <a href="{{ url('/profile/' . $follower->id) }}">{{$follower->name}}</a>
              </li>
              @endforeach

            </ul>
          </div>
          {!! $followers->links() !!}

It works well for http://localhost:8000/profile. However, when it clicks next page on http://localhost:8000/profile/{id} it redirects to http://localhost:8000/profile/profile/1?page=2. I don't really know where it gets the double profile from. I mean the Log::info($request->path()); prints the correct path for me. What am I missing here? Appreciate any help!!

0 likes
12 replies
SaeedPrez's avatar

My first thought is if your routes were setup correctly http://localhost:8000/profile/profile/1?page=2would throw a 404 error, page not found.

Make sure you don't have something like this..

Route::group(['prefix' => '/profile'], function() { // <<--- first /profile

    // this is bad
    Route::resource('/profile', 'someController'); // <-- second /profile

    // this is good
    Route::resource('/', 'someController');


    // this is bad
    Route::get('/profile/{profile}', 'someController@show'); // <-- second /profile

    // this is good
    Route::get('/{profile}', 'someController@show');

});

Both would produce /profile/profile because they have /profile path while being in a group that prefixes another /profile..

If this isn't the case, show us your routes..

jimmygns@me.com's avatar

@SaeedPrez I don't think that is the case here. First, I didn't use group, and my route looks just as simple as

Route::get('profile/{id?}','ProfileController@index');
SaeedPrez's avatar

@jimmygns@me.com can you show your whole routes file?

Edit

Also dump $request->path() and post the result here..

$paginatedResults->setPath($request->path());
dd($request->path()); // <<-- result of this
jimmygns@me.com's avatar

@SaeedPrez Sure, My route file:

Route::get('/', function () {
     return view('welcome');
});
Route::auth();

Route::get('home', 'HomeController@index');

//profile logistics
Route::get('profile/{id?}','ProfileController@index');

//image rendering
Route::get('profile_photo/{image}', 'FileSystemController@getProfileImage');

Route::post('profile/edit', 'FileSystemController@storeProfileImage');

and Log::info($request->path()); shows the paths are ''' [2016-06-01 05:45:24] local.INFO: profile [2016-06-01 05:45:31] local.INFO: profile/6 ''' for /profile and /profile/6.

SaeedPrez's avatar

@jimmygns@me.com

Your route file looks fine, although profile/{id?} might cause issues with profile/edit later on, but for now they use different methods.

What does your index() method on ProfileController look like?

Btw, so when you visit http://localhost:8000/profile/profile/1?page=2 you see the profile for user 1 and page 2?

jimmygns@me.com's avatar

@SaeedPrez The index method looks like

public function index(Request $request, $passed_in_id=null){
        if(!$passed_in_id){
            $current_user = Auth::user();
        }
        else{
            $current_user=User::findOrFail($passed_in_id);
        }
        $is_friend=False;
        
        $followers_id = Follower::where('subject',$current_user->id)->select('follower')->get();
        
        $followers=[];
        foreach($followers_id as $id){
            if($id===$passed_in_id){
                $is_friend=True;
            }
            $follower=User::find($id->follower);
            $followers[]=$follower;
        }
        $currentPage = LengthAwarePaginator::resolveCurrentPage();
        $collection=collect($followers);
        $perPage=5;
        $currentPageResults = $collection->slice(($currentPage-1) * $perPage, $perPage)->all();

        //Create our paginator and pass it to the view
        $paginatedResults= new LengthAwarePaginator($currentPageResults, count($collection), $perPage);
        $paginatedResults->setPath($request->path());
        Log::info($request->path());
        return view('user.profile',['me'=>$current_user,'followers'=>$paginatedResults,'is_friend'=>$is_friend]);
    }

and when i visit http://localhost:8000/profile/profile/1?page=2, i get 404 error. What it seems weird to me is it works as expected for http://localhost:8000/profile, as I click next it goes to http://localhost:8000/profile?page=2. I don't know why it doesn't work in the same way for http://localhost:8000/profile/{id}

SaeedPrez's avatar

@jimmygns@me.com

Hm, try this...

$paginatedResults= new LengthAwarePaginator($currentPageResults, count($collection), $perPage, $currentPage, ['path' => $request->path()]);
// $paginatedResults->setPath();
SaeedPrez's avatar

@jimmygns@me.com

Hm, have you tried without setting a path? If so what happens then

$paginatedResults = new LengthAwarePaginator($currentPageResults, count($collection), $perPage, $currentPage);
// $paginatedResults->setPath();

You might want to refactor your code and use ->paginate()

        if(!$passed_in_id){
            $current_user = Auth::user();
        }
        else{
            $current_user=User::findOrFail($passed_in_id);
        }

For example, the above code could be replaced by this

        $current_user = isset($passed_in_id) ? User::findOrFail($passed_in_id) : Auth::user();

If you setup a decent relationship, you could get followers like this, including pagination..

        $followers = $current_user->followers()->paginate(5);

So basically, your controller should look something like this..

public function index(Request $request, $passed_in_id = null)
{
    $current_user = isset($passed_in_id) ? User::findOrFail($passed_in_id) : Auth::user();
    $followers = $current_user->followers()->paginate(5);
    return view('user.profile', ['me' => $current_user, 'followers' => $follosers]);
}
jimmygns@me.com's avatar

@SaeedPrez Thanks for the input. yeah, i have tried without path, it redirects to the base url, for example http://localhost:8000/profile => http://localhost:8000?page=2 which is not what i wanted. I thought about refactoring the query too, but I got stuck on eloquent model relations. Basically, i have a model called follower which contains 2 columns follower, followee both are reference to the id in user model. I'm trying to query all the followers for one user. Can you give me some hints on how I can refactor this query using eloquent relationals.

SaeedPrez's avatar
Level 50

@jimmygns@me.com

So basically you have a many to many relationship between your users, with a pivot table called followers.

I think this might work, haven't tried it.. try it and let me know..

// In your User model


public function followers()
{
    return $this->belongsToMany(User::class, 'followers', 'followee', 'follower');
}

public function followees()
{
    return $this->belongsToMany(User::class, 'followers', 'follower', 'followee');
}

PS. I'm assuming your pivot table is called followers (2nd argument in the belongsToMany() method)

SaeedPrez's avatar

You should really check this whole series, especially episode 21+ that shows how to use many to many relationships with pivot table.

Please or to participate in this conversation.