How could I have 2 different route keys names for my Post model? (Laravel)

Viewed 461

I've made a simple Laravel CRUD, and I'm stuck on a problem.
My posts have a slug column and a uuid column in the table in which they are stored. I've binded the routes to the PostController using

Route::resource("posts", "PostController");

I want to be able to call the show route by using the slug in the URL, (example.com/posts/all-about-my-new-banana-maker), but to be able to call the edit route by using the UUID (example.com/posts/ddd83f7b-9c73-11eb-93c2-e55e28ace783/edit)
I've tried editing my Post model and changing getRouteKeyName:

class Post extends Model
{
    use HasFactory;

    // Set mass-assignable fields
    protected $fillable = ["title", "content", "category", "image", "slug", "uuid"];

    /**
     * Get the route keyfor the model
     * @return string
     */
    public function getRouteKeyName() {
        return "slug";
    }
}

I can only see to have UUID or slug, not both at the same time. How could I make it so that both UUID and slug retrieve my post?

2 Answers

If you want to pass extra route parameter, then you need to define an another route for that :

Route::get("posts/{uuid}/{slug}", "PostController@data");

And your controller will be looked like :

public function data($uuid, $slug) {
    // You can access $uuid and $slug here
}

You can either remove any type hints from your methods, or override the route model binding in your RouteServiceProvider.

Remove type hinting

public function show($post)
{
    $post = Post::where('slug', $post)->firstOrFail();
}

public function edit($post)
{
    $post = Post::where('uuid', $post);
}

Override route model binding

Add something like the following to the boot method of the RouteServiceProvider.

Route::bind('post', function ($value){
    return Post::where('slug', $value)->orWhere('uuid', $value)->firstOrFail();
});

You still use type hinting if you override the route model binding in the RouteServiceProvider.

Related