Laravel如何结合三方多对多pivot与多态多对多实现中间关联打标签
实现方案
1. 调整中间表结构
你现有的job_movie_person中间表缺少唯一主键,需要先新增自增id字段,用于多态标签关联的taggable_id映射,迁移代码如下:
Schema::table('job_movie_person', function (Blueprint $table) { $table->id()->first(); });
如果是新建中间表,直接在定义表结构时加上$table->id()即可。
2. 创建中间表对应模型
给中间表创建独立的Pivot模型,引入你现有的多态标签Trait即可让中间表记录支持打标签,我们这里用影视行业通用的任职记录命名Credit作为模型名,你也可以自定义为JobMoviePerson:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Database\Eloquent\Factories\HasFactory; // 引入你现有项目里的多态标签Trait use App\Traits\HasTags; class Credit extends Pivot { use HasFactory, HasTags; protected $table = 'job_movie_person'; protected $fillable = [ 'movie_id', 'person_id', 'job_id', ]; }
这里继承Pivot而非普通Model,更适配中间表的使用场景,原有标签逻辑不需要做任何修改。
3. 调整原有主模型的关联定义
分别修改Movie、Person、Job三个主模型的多对多关联,指定使用刚才创建的中间模型:
Movie模型调整
// 原有人员关联修改为 public function people() { return $this->belongsToMany(Person::class) ->using(Credit::class) ->withPivot('job_id') ->withTimestamps(); // 中间表有时间戳字段就保留,没有可删除 } // 原有给电影打标签的关联保持不变 public function tags() { return $this->morphToMany(Tag::class, 'taggable'); }
Person模型调整
public function movies() { return $this->belongsToMany(Movie::class) ->using(Credit::class) ->withPivot('job_id'); }
Job模型调整(如果有对应关联)
public function credits() { return $this->hasMany(Credit::class); }
4. 操作示例
给整部电影打标签(原有操作完全不变)
$movie = Movie::where('name', '与狼共舞')->first(); $oscarTag = Tag::where('name', 'Academy Award')->first(); $movie->tags()->attach($oscarTag);
给单条任职记录打标签
// 先找到对应人员和职位 $kevin = Person::where('name', '凯文·科斯特纳')->first(); $actorJob = Job::where('name', 'actor')->first(); // 获取到对应的任职记录(即Credit实例) $credit = $movie->people() ->wherePivot('person_id', $kevin->id) ->wherePivot('job_id', $actorJob->id) ->first() ->pivot; // 直接给该条任职记录绑定标签 $credit->tags()->attach($oscarTag);
查询示例
// 查询《与狼共舞》所有获得奥斯卡的任职记录 $oscarCredits = $movie->people() ->whereHas('pivot.tags', function ($query) use ($oscarTag) { $query->where('tags.id', $oscarTag->id); }) ->get(); // 查询凯文·科斯特纳所有获得奥斯卡的任职记录 $kevinOscarCredits = $kevin->movies() ->whereHas('pivot.tags', function ($query) use ($oscarTag) { $query->where('tags.id', $oscarTag->id); }) ->get();
本方案完全复用你现有多态标签系统,不需要修改tag和taggables表结构,原有主模型的标签逻辑完全不受影响。
内容的提问来源于stack exchange,提问作者wivku
相关产品推荐
相关产品推荐

