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

xiolog's avatar

One level url generation in route.php

Hi all.

I need help from more experienced colleagues, as I don't understand how to do this.

I need to make a url of this kind (routes):

Get a specified company in the specified city -

/{city}/{company}

Get all companies in the specified city and located in the specified region -

/{city}/{region}

We get all companies in the specified city and located on the specified street

/{city}/{street}

Generally these urls should look something like this:

/new-york/sun-ltd
/new-york/manhattan
/new-york/seventh-avenue

As you can see, company, region and street must be at the same level. This is what the customer wants. He wants it for SEO.

I don't understand how to do this. Please help me.

0 likes
2 replies
rodrigo.pedra's avatar
Level 56

Well I would add an identifier path to make it easier to distinguish between sub-paths:

/{city}/companies/{companies}
/{city}/regions/{region}
/{city}/at/{street}

Then have each path linked to a different controller where you already know what type the second parameter is.

But as you said it is a client requirement you can try this:

1 - Use explicit binding

Easiest to code, but worst in performance, you can add an explicit binding.

Add this to your app's RouteServiceProvider boot method:

Route::bind('location', function ($slug) {
    return Company::where('slug', $slug)->first()
        ?? Region::where('slug', $slug)->first() 
        ?? Address::where('slug', $slug)->first(); 
});

Reference: https://laravel.com/docs/8.x/routing#explicit-binding

I am assuming you have a separate model to each entity on your path. This will execute at most 3 queries, one for each entity, and use the null-coalesce operator to try the next one if no record was found.

Then you can have only one path:

/{city}/{location}

In your controller you won't typehint the parameter, but Laravel will know from the explicit binding what to pass to it if the location binding name matches the parameter name:

public function index(City $city, $location)
{
    // ...
}

2 - Use an auxiliary table to keep all slugs.

To avoid issuing 3 queries, you can create a polymorphic table that saves and indexes all the slugs and relates to the correct model.

Then you can use implicit model binding as you would use for the City model.

This will always make 2 queries (one for the polymorphic table, and one for the related model).

Read about polymorphic models in the docs here:

https://laravel.com/docs/8.x/eloquent-relationships#polymorphic-relationships

Hope this helps.

1 like
xiolog's avatar

Hi. Thanks for your answer. I understood :)

1 like

Please or to participate in this conversation.