Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

uccdev's avatar

Laravel Pagination causes MethodNotAllowedHttpException ?

So I am working on a site that paginates two different types of DB queries.

The first is a generic "get everything" query. The second has specific checks (e.g "WHERE name = 'John'")

Both are done with simplePaginate(num); I'll show my code if it's considered relevant.

The first works perfectly fine. BUT the second throws an error whenever I use the Next or Previous buttons to fetch the next results.

               Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException

No message

This is not an out-of-bounds error since I know the database has more values under the specified query. **EDIT: No longer the case, see "EDIT 2". **

Does anyone know why this happens?

EDIT: For clarity, here is my code for the second query. It works for the first page, but ONLY causes errors when I use one of the buttons to move to another page.

          $postmen = DB::table('postmen')
  ->join('cats', 'postmen.cat_id', '=', 'cats.cat_id')
  ->join('reg_status', 'postmen.status_id', '=', 'reg_status.status_id')
  ->select('postmen.postmen_id', 'postmen.forename', 'postmen.surname',
   'cats.description AS catdesc', 'reg_status.description AS regdesc')
   ->where(function ($query) use ($request) {
     if (!empty($request->forename)) {
       $query->where('postmen.forename', $request->forename);
     }
     if (!empty($request->surname)) {
       $query->where('postmen.surname', $request->surname);
     }
     if (!empty($request->cat_id)) {
       $query->where('postmen.cat_id', $request->cat_id);
     }
     if (!empty($request->status_id)) {
       $query->where('postmen.status_id', $request->status_id);
     }
     if (!empty($request->postmen_id)) {
       $query->where('postmen.postmen_id', $request->postmen_id);
     }
   })
  ->paginate(10);

EDIT 2: It's been pointed out that now the route was incorrect. I had been using exclusively "route::post". I have added a route::get for my view now:

      Route::get('/postmen', 'myController@searchByCriteria');

I am no longer getting a "MethodNotAllowedHttpException". Instead I am getting a time-out because it's redirecting itself too often. I'm not sure what's wrong there.

Any advice?

0 likes
29 replies
jlrdw's avatar

The second, you need to append query string I suspect. Refer to docs under pagination.

uccdev's avatar

@JLRDW - Do you mean the append to pagination code? Like:

                       {{ $users->appends(['sort' => 'votes'])->links() }}

I'm not sure how that should look. Say my pagination is like this:

                       {{ $postmen->links() }}

What should I append to that?

Vilfago's avatar

What is the route method of the page ? It should be get

Vilfago's avatar

It's the reason why I think. The link populated by $foo->links() work with get method

uccdev's avatar

@VILFAGO - I added a get path for it now, and I think that worked. I'm not getting the same dd error page anymore. What I am getting instead, tragically, is a page timeout. Apparently my page has redirected me too many times?

munazzil's avatar

Then try

        php artisan view:clear
        php artisan cache:clear
jlrdw's avatar

Did you try to change the end

$query ->paginate(10);

Right now you're not paginating anything it doesn't look like.

You have to double-check logic in these queries.

Snapey's avatar

make sure the page is on a get route and that you return a view and not a redirect.

uccdev's avatar

@JLRDW - Where do you suggest making that change? In my controller or my view? if you mean the controller, then it is already there, as shown in the original post:

      $postmen = DB::table('postmen')
       ...
       ...->paginate(10);
munazzil's avatar

Your using for this related controller in web.php as Route::resource or Route::get or post?

uccdev's avatar

@MUNAZZIL - I'm not sure how to open the laravel console. I'm working with my text editor at the moment.

Also, I have a route::get and a route::post for this page.

munazzil's avatar

Can you display the web.php code over here and laravel version?

uccdev's avatar

@MUNAZZIL - The web.php code:

       Route::post('/postmen', 'myController@searchByCriteria');
       Route::get('/postmen', 'myController@searchByCriteria');
munazzil's avatar

Can you change as like below because get method should be first.

   Route::get('/postmen', 'myController@searchByCriteria'); 
   Route::post('/postmen', 'myController@searchByCriteria');
   

Else change as like below and check.

Route::resource('/postmen', 'myController');
uccdev's avatar

@MUNAZZIL - I tried the first change, and got no difference; still a timeout.

Then I commented those two lines out and used Route::resource instead. I got an error exception:

       BadMethodCallException: Method App\Http\Controllers\myController::store does not exist.
munazzil's avatar

That says your store controller function have codes without anything.Use as like below

public function store()
 {
    //
 }
jlrdw's avatar

See here:

Advanced Join Clauses here https://laravel.com/docs/5.7/queries#joins

and read this:

https://laracasts.com/discuss/channels/laravel/query-builder-joining-tables

Try something like: Not tested, but above links should work.

    public function verytemp()  // your method
    {
        $postmen = DB::table('postmen')
        ->join('cats', 'postmen.cat_id', '=', 'cats.cat_id')
        ->join('reg_status', 'postmen.status_id', '=', 'reg_status.status_id')
        ->select('postmen.postmen_id', 'postmen.forename', 'postmen.surname', 'cats.description AS catdesc', 'reg_status.description AS regdesc')
        if (!empty($request->forename))) {
        ->where(['postmen.forename', $request->forename]);
        }
        if (!empty($request->surname)) {
        ->where('postmen.surname', $request->surname);
        }
        if (!empty($request->cat_id)) {
        ->where('postmen.cat_id', $request->cat_id);
        }
        if (!empty($request->status_id)) {
        ->where('postmen.status_id', $request->status_id);
        }
        if (!empty($request->postmen_id)) {
        ->where('postmen.postmen_id', $request->postmen_id);
        }
        ->paginate(10);
    }

I'd use db facade or getPdo() for this.

See these:

https://laracasts.com/discuss/channels/guides/getpdo-usage

https://laracasts.com/discuss/channels/eloquent/writing-all-queries-directly-vs-model-relations

https://laracasts.com/discuss/channels/laravel/sql-native-to-query-builder

https://laracasts.com/discuss/channels/laravel/coverting-ms-access-queries-to-laravel-query-builder

https://laracasts.com/discuss/channels/general-discussion/sql-injection-2

jlrdw's avatar

A followup, and not saying you want to use regular PDO, but just throwing in another quick example. A regular query is just sometimes better than eloquent.

Example is not your query but just shows how a normal can easily be done:

    public function veryTemp()
    {
        $page = Request::input('page', '1');
        // other request as needed
        $bsdate = Request::input('begindate');
        $esdate = Request::input('enddate');
        $t1 = "b"; // thrown in to demo, report isn't paginated.
        $perpage = "5";
        $offset = ($page - 1) * $perpage;
        $krows = DB::select(); /// Put your count query here
        // above line is a query where you get total count////
        $numrows = $krows[0]->count;
        $pagingQuery = "LIMIT {$offset}, {$perpage}";
        $sql = "select distinct `account_types`.`AccountType` AS `AccountType`,`accounts`.`AccountNumber` AS `AccountNumber`,`accounts`.`AccountName` AS `AccountName`,sum(`transactions`.`Expense`) AS `Sum_Expense`,sum(`transactions`.`Income`) AS `Sum_Income` from ((`account_types` join `accounts` on((`account_types`.`AccountTypeID` = `accounts`.`AccountTypeID`))) join `transactions` on((`accounts`.`AccountID` = `transactions`.`AccountID`))) where (`transactions`.`TransactionDate` Between '$bsdate' and  '$esdate') group by `account_types`.`AccountType`,`accounts`.`AccountNumber`,`accounts`.`AccountName`";

        // a space and  " . $pagingQuery; would be added when paginating:
        //like long query ....  AccountName` " . $pagingQuery;

        $sth = DB::getPdo()->prepare($sql);
        $sth->execute();
        $quy = $sth->fetchAll(\PDO::FETCH_OBJ);
        $report = new LengthAwarePaginator($quy, $numrows, $perpage);
        $pagelinks = ['t1' => $t1, 'page' => $page]; // report has none, for demo only
        // here $pagelinks are appends to query string

        $title = 'Monthly Report';
        $view = 'acct/mreport';
        $layout = ViewLayout::getLayout('acct/reporttp');
        $content = View::make($view)
                ->with('report', $report)
                ->with('pagelinks', $pagelinks);
        return view($layout)->with('content', $content)->with('title', $title);
    }

In your case you may need to bind parameters, an example:

$dogid = Request::input('somevar');
        $sql = "SELECT * FROM dc_dogs WHERE dogid = :dogid";
        $params = ['dogid' => $dogid];
        $sth = DB::getPdo()->prepare($sql);
        $sth->execute($params); // binding taking place.
        $dog = $sth->fetch(\PDO::FETCH_ASSOC);
        return Response::json($dog);

THIS PART IGNORE, RETURN YOUR WAY

I DON'T USE BLADE:

//This part is custom       
 $title = 'Monthly Report';
        $view = 'acct/mreport';
        $layout = ViewLayout::getLayout('acct/reporttp');
        $content = View::make($view)
                ->with('report', $report)
                ->with('pagelinks', $pagelinks);
        return view($layout)->with('content', $content)->with('title', $title);

In the view to show pagination:

<?php echo str_replace('/?', '?', $dogs->appends($pagelinks)->render()); ?>
// convert to blade

This is just example.

My above query looped over produces:

https://i.imgur.com/RlzeSEp.jpg

I just do not get into active record, I programmed servlets and jsp for years, and just got used of regular queries.

But active record converts to normal queries at runtime anyway.

It is good for some things, but what is supposed to be a shortcut, in a larger query turns out to be harder than the normal sql.

Fine for straight forward relations, but complex joins and group by, nah.

But again these two links should help your query:

Advanced Join Clauses here https://laravel.com/docs/5.7/queries#joins

and read this:

https://laracasts.com/discuss/channels/laravel/query-builder-joining-tables

AddWebContribution's avatar
Level 42

You should try this:

Yes pagination only works with get parameters.

You should use GET method for your search page. POST requests aren't meant for the purpose of displaying data. Why? There are many reasons, but to be short I will give you two examples:

With GET parameters, let's say you are on sixth page - you can copy the link and paste it to friend and he will be able to view the same content as you. With POST this is impossible.

You can not use back button with POST requests, if you manage to get pagination to work.

POST requests are useful when you need to submit data to the server, in order to create new record, for example.

So I suggest you to change your route type to GET and your search form method to GET.

HimaShukla's avatar

you should try like this


{{$data->appends(['year'=>$year,'month'=>$month,'id'=>$id])->links()}}

if you are passing any parameters to controller to fetch data.

uccdev's avatar

@JLRDW - Thank you for your post. Sorry for the delay; I'd finished up for Christmas then.

I've tried the code in your first post, and gotten this error:

   syntax error, unexpected '->' (T_OBJECT_OPERATOR)

I'm not entirely sure about that. On the first "->where" in the first "if". It's not the extra ")" in the if, in case you were thinking of that.

Thank you very much for all of those links, but I admit, I'm not very sure how relevant some of them are. How are you suggesting I use advanced joins, for instance, to decide whether to optionally use elements? And the laracasts thread just says from what I see to 'use joins' some more.

Any advice?

uccdev's avatar

@MUNAZZIL - Sadly not yet, no. None of the provided solutions have worked; my pagination page still times out

Snapey's avatar

Please show the full controller method.

uccdev's avatar

@SNAPEY -

public function searchCriteria(Request $request) {
   //DO NOT USE "required", as no field here is (besides 'submit')
   $validated = Validator::make($request->all(), [
    "submit"      => "required",
    "forename"    => "nullable|regex:/^[a-zA-Z\s’'.-]+$/",
    "surname"     => "nullable|regex:/^[a-zA-Z\s’'.-]+$/",
    "cat_id"   => "between:0,4", //[Rule::in([1, 2, 3, 4, 5]) ],
    "status_id"   => "between:0,5",//[Rule::in([1, 2, 3, 4]) ],
    "postmen_id"  => "nullable|regex:/^[0-9]+$/"
   ]);
  $data = $request->all();
  $errors = $validated->errors();
  if($validated->fails()) {
    return redirect()->back()->withInput($request->all())->withErrors($errors);
  }

  try {

     $postmen = DB::table('postmen')
     ->join('cats', 'postmen.cat_id', '=', 'cats.cat_id')
     ->join('reg', 'postmen.status_id', '=', 'reg.status_id')
     ->select('postmen.postmen_id', 'postmen.forename', 'postmen.surname',
      'cats.description AS catdesc', 'reg.description AS regdesc')
      ->where(function ($query) use ($request) {
        if (!empty($request->forename)) {
          $query->where('postmen.forename', $request->forename);
        }
        if (!empty($request->surname)) {
          $query->where('postmen.surname', $request->surname);
        }
        if (!empty($request->cat_id)) {
          $query->where('postmen.cat_id', $request->cat_id);
        }
        if (!empty($request->status_id)) {
          $query->where('postmen.status_id', $request->status_id);
        }
        if (!empty($request->postmen_id)) {
          $query->where('postmen.postmen_id', $request->postmen_id);
        }
      })
     ->simplePaginate(10);


     if(isset($request->cat_id)) {
       $cat = DB::table(‘cats’)
         ->where('cat_id', $request->cat_id)
         ->first();
     }
     if(isset($request->status_id)) {
       $status = DB::table(‘reg')
         ->where('status_id', $request->status_id)
         ->first();
     }
     /*
     Deals with the "cat" and "status" fields. Returns data to the view depending on whether any of them are set. Also tells the 'postmen' view that special search results are used, by passing it $criteria
     */
     if (empty($postmen)) {
       return PostController::neutralSearch();
     }
     else {
       $criteria = True;
       $idFail = False;
       if (isset($cat) && !(isset($status))) {
         return view('postmen')->with('postmen', $postmen)
         ->with('course', $cat)
         ->with('criteria', $criteria)
         ->with('idFail', $idFail);
       }
       else if ((isset($status)) && !(isset($cat))) {
         return view('postmen')->with('postmen', $postmen)
         ->with('status', $status)
         ->with('criteria', $criteria)
         ->with('idFail', $idFail);
       }
       else if ( (isset($status)) && (isset($cat)) ) {
         if (!(isset($postmen)) || (empty($postmen))) {
           PostController::neutralSearch();
         }
         return view('postmen')->with('postmen', $postmen)
         ->with('course', $cat)
         ->with('status', $status)
         ->with('criteria', $criteria)
         ->with('idFail', $idFail);
       }
       else {
         return PostController::neutralSearch();
       }
         return view('postmen')->with('postmen', $postmen);
      }
     }
   } catch (Exception $ex) { //(Illuminate\Support\Facades\Validator $ex){
     dd($ex->getMessage());
     // Note any method of class PDOException can be called on $ex.
     return redirect()->back()->withInput($request->all())->withErrors($errors);
   }
}
Snapey's avatar

if you comment out the filters, does it return page 2,3 etc


     $postmen = DB::table('postmen')
     ->join('cats', 'postmen.cat_id', '=', 'cats.cat_id')
     ->join('reg', 'postmen.status_id', '=', 'reg.status_id')
     ->select('postmen.postmen_id', 'postmen.forename', 'postmen.surname',
      'cats.description AS catdesc', 'reg.description AS regdesc')
//     ->where(function ($query) use ($request) {
//        if (!empty($request->forename)) {
//          $query->where('postmen.forename', $request->forename);
//        }
//        if (!empty($request->surname)) {
//          $query->where('postmen.surname', $request->surname);
//        }
//        if (!empty($request->cat_id)) {
//          $query->where('postmen.cat_id', $request->cat_id);
//        }
//        if (!empty($request->status_id)) {
//          $query->where('postmen.status_id', $request->status_id);
//        }
//        if (!empty($request->postmen_id)) {
//          $query->where('postmen.postmen_id', $request->postmen_id);
//        }
//     })
     ->simplePaginate(10);

uccdev's avatar

@SNAPEY - Yes, Snapey; with the commented parts removed, it is just like my default search, and the pagination works perfectly. Unfortunately, my final site needs to have a query that can be optionally specific, like the commented parts try to do

uccdev's avatar

I found the error. A form the pagination used that I had overlooked was still using "POST". When I changed it to "GET", the timeout error vanished. Thank you for all your help!

Please or to participate in this conversation.