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

nitinvpro's avatar

Dynamic url calling using slug failed

I am working on a business listing website and using following routes working fine

  1. Route::get('/', [HomeController::class, 'index'])->name('home');
  2. Route::get('/country/{country}', [CountryController::class, 'index']);
  3. Route::get('/{country}/{state}', [StateController::class, 'index']);

these redirects to home page 4. Route::get('/cuisine/{cuisineSlug}', [CuisineController::class, 'cuisine']); 5. Route::get('/food/{food}', [FoodController::class, 'index']);

declared

use App\Http\Controllers\HomeController;

use App\Http\Controllers\CuisineController;

use App\Http\Controllers\FoodController;

use App\Http\Controllers\CountryController;

use App\Http\Controllers\StateController;

but if i put 4,5 before 1 they work fine but 2 and 3 stops working. What could be the issue and how to solve them for future additions as well?

I am using Laravel 10 php 8.1

0 likes
4 replies
gych's avatar

The issue is because of this route

Route::get('/{country}/{state}', [StateController::class, 'index']);

When you put it infront of the other routes Laravel by default doesn't know what {country} should be so it will for example see cuisine in route 4 as a match for {country} and therefore it will use this route and not look further for the other route.

You can either place route 3 as last or add where method or use a middleware to check if the url contains an actual country. Personally I would just put it as the last route since that's the easiest solution to your issue.

https://laravel.com/docs/11.x/routing#parameters-regular-expression-constraints

nitinvpro's avatar

@gych Thanks for reply, shifting country/state route worked but is there a way that I can use to bind them to their parameters because i need to create the following routes as well.

Route::get('/{city}/{restaurant}', 'RestaurantController@show'); Route::get('/{city}/{restaurantCategory}', 'RestaurantCategoryController@index'); Route::get('/{city}/{foodCategory}', 'CityFoodCategoryController@index');

gych's avatar

@nitinvpro You could use whereIn https://laravel.com/docs/11.x/routing#parameters-regular-expression-constraints

Here is a simple example, I've also updated your route to the new standard, the way you are writing you routes with Controller@Method is deprecated and should not be used anymore.

$cities = ['paris', 'london'];
$restaurants = ['restaurant1', 'restaurant2'];

Route::get(/{city}/{restaurant}', [RestaurantController::class, 'show'])->whereIn('city', $cities)->whereIn('restaurant', $restaurants);

If it should match data from the DB fetch the data but keep it in cache so there's no need to run the queries for each request.

You can also use a middleware for this instead of whereIn. Also add all those routes at the bottom in your routes file.

aleahy's avatar

As a general rule, order your routes so that the more generic they are, the lower down on the list.

Route::get('/{country}/{state}', [StateController::class, 'index']);

This should be near the bottom because it is accepting anything for country and anything for state. So it will intercept urls intended for the /cuisine/{cuisineSlug} and /food/{food} endpoints.

For /cuisine/cuisine-slug it will assign $country = 'cuisine' and $state = 'cuisine-slug'.

So by making it last, it will pick up anything with two paths where the first path is not country, cuisine or food.

Maybe I'm misunderstanding, but I don't see why 4 and 5 would stop 2 and 3, unless you are using cuisine or food for the country.

Please or to participate in this conversation.