@anibabbar Unfortunately there’s no real way to do this. If a request comes in and the slug could belong to one of many models, then there’s no way for Laravel to “magically” know which model you want to query.
Basically, you’re going to have to create your own fallback controller that does it’s own routing to look up the correct model, and then pass the request off to a dedicated controller for handling:
Route::fallback(FallbackController::class);
class FallbackController extends Controller
{
public function __invoke(Request $request)
{
$path = $request->path();
// Look up product with slug
if ($product = Product::query()->where('slug', '=', $path)->first()) {
return resolve(ProductController::class)->show($product);
}
// Look up page with slug
if ($page = Page::query()->where('slug', '=', $path)->first()) {
return resolve(PageController::class)->show($page);
}
// Look up post with slug
if ($post = Post::query()->where('slug', '=', $path)->first()) {
return resolve(PostController::class)->show($post);
}
// If here, no models have record with the slug; throw 404
abort(404);
}
}
Obviously this will get unwieldily the more models you wish to query by slug, so you may consider extrapolating slugs out to its own model and table, and then have some form of polymorphic relation pointing back to the record associated with that slug:
public function __invoke(Request $request)
{
$slug = Slug::query()->where('path', '=', $request->path())->firstOrFail();
return match ($slug->model_type) {
'page' => resolve(PageController::class)->show($slug->model),
'post' => resolve(PostController::class)->show($slug->model),
'product' => resolve(ProductController::class)->show($slug->model),
default => abort(404),
};
}
If you extrapolate slugs to its own model, you’d also be able to put a unique constraint on the path column, so that slugs are unique across all models, i.e. you can’t have both a page and a post with the same slug value.