Alizey's avatar

How to create a route with slug or id

How can we create a route that opens with slug name or its id. I watch the video but i don;t get that

Here is example

Route::get('/courses/{slug}/{id}', 'CourseDetailsController@index');

My Controller.

public function index($slug)
{
        return "testing";
}

How can i use the slug or id Want a url like http://abc.com/courses/Html
@Html there may be an Html Id. How can i make that route with controller

0 likes
19 replies
RachidLaasri's avatar

Route :

Route::get('/courses/{slug}/{id}', 'CourseDetailsController@index');

Controller :

public function index($slug, $id)
{
    // the query here, you can search by id or by slug.
}
3 likes
bashy's avatar

That's not normally done but you could check to see if the param is a digit, then find it by ID rather than slug?

RachidLaasri's avatar
public function index($slug, $id)
{
    $post = Post::where('id', $id)
            ->orWhere('slug', $slug)
            ->firstOrFail();
}
2 likes
bashy's avatar

That still requires two params. Guess they want to use example.com/courses/{id_or_slug}

2 likes
RachidLaasri's avatar
Level 41

@bashy Yes, they'll need to change the route; saying that both ID and slug are unique, this will work i guess.

Route::get('/courses/{param}', 'CourseDetailsController@index');
public function index($param)
{
    $post = Post::where('id', $param)
            ->orWhere('slug', $param)
            ->firstOrFail();
}
11 likes
bashy's avatar

Yup, I was just making sure the OP knew :)

2 likes
kurucu's avatar

The Laravel documentation now has something on this:

Customizing The Resolution Logic

If you wish to use your own resolution logic, you may use the Route::bind method. The Closure you pass to the bind method will receive the value of the URI segment and should return the instance of the class that should be injected into the route:

public function boot()
{
    parent::boot();

    Route::bind('user', function ($value) {
        return Post::where('id', $value)
            ->orWhere('slug', $value)
            ->first();
    });
}
3 likes
arthurvillar's avatar

There is a much simpler way! Just add this to your model class:

    public function getRouteKeyName()
    {
        return '[your-column-name-here]';
    }

Laravel uses this function getRouteKeyName() to do what the name indicates

4 likes
sam0081's avatar

this is not working with api. what to do in that case?

domain.com/api/list/dasd-1604424860

arthurvillar's avatar

@bashy True, I didn't notice he wanted to use one OR the other. The solution found before seems to be the best. Matching both at the same time just seems to be an unnecessarily complicated thing to do, unless you would want to compare them for safety reasons.

_Marco_'s avatar

I have a similar problem but mine is slightly more complicated because my slugs are numeric as well so if I do orwhere and first() and my slug is 1000 and I have a record with id 1000 as well it will just find one of them. Any idea how could I solve this? The only thing that occurs to me is have different routes with different methods but I would like to have the same route and method if possible.

chimit's avatar

Another alternative solution is to use the resolveRouteBinding method on your model to customize the resolution logic. In my case I search for numeric IDs and then for slugs:

/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value, $field = null)
{
    return is_numeric($value)
        ? $this->where('id', $value)->firstOrFail()
        : $this->where('slug', $value)->firstOrFail();
}
1 like

Please or to participate in this conversation.