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友好的字符串:
- 迁移中添加
$table->string('nom_slug')->unique(); - 模型中用
Str::slug()自动生成slug(可通过模型事件或观察者实现) - 修改
getRouteKeyName为'nom_slug',同步调整路由参数
内容的提问来源于stack exchange,提问作者MOHAMED KESSOUM
相关产品推荐
相关产品推荐

