You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel路由如何用名称替代ID显示在URL中?

问题描述

我原本的路由是/collections/1,希望将其修改为/collections/name(实例名称存储在数据库中且唯一,要求URL显示名称而非ID)。

现有代码

原路由代码

Route::get('/collections/{id}', [SousCategorieController::class, 'show']);

原控制器代码

public function show(Sous_categorie $sous_categorie, $id)
{
    $count = DB::table('produits')->select('produits.sous_categorie_id')->where('produits.sous_categorie_id', '=', $id)->get();
    
    $s_marque = DB::table('produits')
        ->select('marque')
        ->join('sous_categories', 'sous_categories.id', '=', 'produits.sous_categorie_id')
        ->whereIn('sous_categories.categorie_id', [$id])->get();
        
    $f_categorie = DB::table('sous_categories')->select('*')->where('categorie_id', '=', $id)->get();
    
    $s_produits = DB::table('produits')
        ->select('produits.*', 'sous_categories.categorie_id as laravel_through_key')
        ->join('sous_categories', 'sous_categories.id', '=', 'produits.sous_categorie_id')
        ->whereIn('sous_categories.categorie_id', [$id])
        ->paginate(8)->withQueryString();
        
    $product = Produit::orderBy('id', 'DESC')->paginate(12)->withQueryString();
    $prods = Produit::with('souscategories')->orderBy('id', 'DESC')->paginate(8)->withQueryString();
    $categories = Categorie::all();
    $sous_categorie = DB::table('sous_categories')->select('*')->where('categorie_id', 'like', '%' . $id . '%')->get();

    return view('collections.components', compact('sous_categorie', 'id', 'f_categorie', 'categories', 'prods', 'product', 's_produits', 's_marque', 'count'));
}

已尝试方案

重写模型的getRouteKeyName方法:

public function getRouteKeyName()
{
    return 'nom';
}

并修改路由为:

Route::get('/collections/{collection}', [SousCategorieController::class, 'show']);

但URL仍显示为http://127.0.0.1:8000/collections/1,未达到预期效果。


解决方案

1. 修正路由模型绑定

路由参数名需要和控制器方法中的模型变量名匹配,或者显式指定查询字段:

// 方式1:显式指定用nom字段查询
Route::get('/collections/{sous_categorie:nom}', [SousCategorieController::class, 'show']);

// 方式2:如果模型已经重写getRouteKeyName,可直接用模型变量名
Route::get('/collections/{sous_categorie}', [SousCategorieController::class, 'show']);

2. 调整控制器方法

移除多余的$id参数,直接使用路由绑定的模型实例,所有依赖$id的逻辑改用模型的id属性:

public function show(Sous_categorie $sous_categorie)
{
    $id = $sous_categorie->id;
    
    $count = DB::table('produits')
        ->select('produits.sous_categorie_id')
        ->where('produits.sous_categorie_id', '=', $id)
        ->get();
        
    $s_marque = DB::table('produits')
        ->select('marque')
        ->join('sous_categories', 'sous_categories.id', '=', 'produits.sous_categorie_id')
        ->whereIn('sous_categories.categorie_id', [$id])
        ->get();
        
    $f_categorie = DB::table('sous_categories')
        ->select('*')
        ->where('categorie_id', '=', $id)
        ->get();
        
    $s_produits = DB::table('produits')
        ->select('produits.*', 'sous_categories.categorie_id as laravel_through_key')
        ->join('sous_categories', 'sous_categories.id', '=', 'produits.sous_categorie_id')
        ->whereIn('sous_categories.categorie_id', [$id])
        ->paginate(8)->withQueryString();
        
    $product = Produit::orderBy('id', 'DESC')->paginate(12)->withQueryString();
    $prods = Produit::with('souscategories')->orderBy('id', 'DESC')->paginate(8)->withQueryString();
    $categories = Categorie::all();
    // 重命名变量避免和绑定的模型冲突
    $sous_categorie_list = DB::table('sous_categories')
        ->select('*')
        ->where('categorie_id', 'like', '%' . $id . '%')
        ->get();

    return view('collections.components', compact('sous_categorie_list', 'id', 'f_categorie', 'categories', 'prods', 'product', 's_produits', 's_marque', 'count'));
}

3. 生成URL时使用模型实例

视图中生成链接必须传入模型实例,而非ID,Laravel会自动用getRouteKeyName指定的字段生成URL:

<!-- 正确写法 -->
<a href="{{ route('collections.show', $sous_categorie) }}">{{ $sous_categorie->nom }}</a>

<!-- 错误写法(会生成带ID的URL) -->
<a href="{{ route('collections.show', $sous_categorie->id) }}">{{ $sous_categorie->nom }}</a>

4. 确认模型配置

确保Sous_categorie模型中正确重写了路由字段方法,且数据库中nom字段唯一:

class Sous_categorie extends Model
{
    // ...其他代码
    
    public function getRouteKeyName()
    {
        return 'nom';
    }
}

可选优化:使用Slug字段

如果nom包含空格或特殊字符,建议添加nom_slug字段存储URL友好的字符串:

  1. 迁移中添加$table->string('nom_slug')->unique();
  2. 模型中用Str::slug()自动生成slug(可通过模型事件或观察者实现)
  3. 修改getRouteKeyName为'nom_slug',同步调整路由参数

内容的提问来源于stack exchange,提问作者MOHAMED KESSOUM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:57:16