'Laravel Route issues with Route order in web.php

I have problem with routes in Laravel, I'm following one tutorial and we have this routes listed in web.php file

Route::get('/home', 'HomeController@index')->name('home');
Route::get('/blog', 'BlogController@index')->name('blog');
Route::get('/blog/create', 'BlogController@create');
Route::post('/blog/store', 'BlogController@store');
Route::get('/blog/{id}', 'BlogController@show');
Route::get('/blog/{id}/edit', 'BlogController@edit');
Route::patch('/blog/{id}', 'BlogController@update');
Route::delete('/blog/{id}', 'BlogController@destroy');
Route::get('/blog/bin', 'BlogController@bin');

Problem is in the last route to blog/bin, it is not working if I keep it down below however in tutorial we have moved it to top of other routes and then it's working fine, instructor said that there is some conflict in routes and that that last route need to be at top in order to work but didn't explain at all why ? Can anybody explain in little more details, as I'm really just started with Laravel...



Solution 1:[1]

When accessing a route, Laravel goes through your list of routes top to bottom, until it finds one that 'matches' at which point this route is immediately selected.

In your example, when trying to access /blog/bin using GET, it has two potential matches:

Route::get('/blog/{id}', 'BlogController@show');

and

Route::get('/blog/bin', 'BlogController@bin');

In this case, Route::get('/blog/{id}', 'BlogController@show'); comes first so it would be selected.

As the previous answers correctly state, placing the /blog/bin route above the /blog/{id} route would solve the problem. However, this 'solution' leaves you open to a similar mistake in the future (when, for example, defining a /blog/example route and accidentally placing it under /blog/{id}). In addition, I personally think it is not very elegant to have the functioning of your routes depend on the order to place them in.

In my opinion, when possible, a more robust solution is to restrict the possible values that are accepted by /blog/{id} with a regex constraint.

For example, if you are using a numeric ID for your blogposts, you know that you only want to use route /blog/{id} if id is a number. Thus, you would define your route as follows:

Route::get('/blog/{id}', 'BlogController@show')->where('id', '[0-9]+');

Of course this is often not a possibility, for example if you use the post title as an id, but if there is some way to differentiate a post id from any other /blog/foo route, then this would be a possibility.

Solution 2:[2]

You can't define a type on a route paramater. So Laravel is guessing that you parameter can be a Integer or even a String.

Based on that, If you try to access /blog/bin. Laravel will try to use the route /blog/{id} with "bin" in id param.

Here a better answer than mine : https://laracasts.com/discuss/channels/laravel/order-of-routes-being-applied/replies/149199

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Radical
Solution 2 Benjamin Brasseur