Laravel中cviebrock/eloquent-sluggable按关联对象限定Slug唯一性
实现关联对象范围内的Slug唯一性(cviebrock/eloquent-sluggable)
要让Slug在关联的用户范围内唯一而非全局,只需利用该包的scope配置项,限定Slug唯一性检查的查询范围即可,具体步骤如下:
1. 确保模型关联正确
假设你的Album模型与User模型是从属关联(一个用户拥有多个专辑),先在Album模型中定义关联:
// app/Models/Album.php public function user() { return $this->belongsTo(User::class); }
同时确保users表和albums表的关联字段(如user_id)已正确设置。
2. 配置Sluggable的Scope规则
在Album模型的sluggable()方法中,添加scope闭包,限定仅检查当前用户下的专辑Slug:
// app/Models/Album.php use Cviebrock\EloquentSluggable\Sluggable; class Album extends Model { use Sluggable; public function sluggable(): array { return [ 'slug' => [ 'source' => 'title', // Slug的生成源,比如专辑标题 'scope' => function ($query) { // 限定查询范围为当前用户的所有专辑 return $query->where('user_id', $this->user_id); } ] ]; } }
这个scope会告诉包:生成/验证Slug时,只对比同一个用户下的专辑,不同用户的同名专辑不会互相干扰。
3. (可选)处理更新场景的自我排除
如果是更新已有专辑,包默认会自动排除当前模型本身,但如果需要手动强化,可以在scope中补充:
'scope' => function ($query) { $query->where('user_id', $this->user_id); // 更新时排除当前专辑 if ($this->exists) { $query->where('id', '!=', $this->id); } }
4. 配置路由与URL生成
为了实现/john-smith/albums/new-thing这样的URL结构:
- 先确保
User模型也用该包生成Slug(比如基于用户名组合):
// app/Models/User.php use Cviebrock\EloquentSluggable\Sluggable; class User extends Authenticatable { use Sluggable; public function sluggable(): array { return [ 'slug' => [ 'source' => ['first_name', 'last_name'] ] ]; } }
- 定义路由时使用模型绑定:
// routes/web.php Route::get('/{user:slug}/albums/{album:slug}', [AlbumController::class, 'show'])->name('albums.show');
测试验证
- 用户John Smith创建名为
New Thing的专辑,Slug为new-thing; - John再创建同名专辑,Slug自动变为
new-thing-2; - 用户Jane Smith创建同名专辑,Slug会是
new-thing(而非new-thing-3),因为唯一性检查仅限定在Jane的用户范围内。
内容的提问来源于stack exchange,提问作者ryanpitts1
相关产品推荐
相关产品推荐

