如何实现Eloquent多态关联?——Task模型关联User与Retailer的迁移、实例创建及关联类型判断
解决Laravel中Task模型与User/Retailer的多态关联问题
嘿,我来帮你搞定这个多态关联的需求,这在Laravel里其实很常见,咱们一步步来:
1. 修正数据库迁移代码
你现在写的$table->morphes('added_by');是拼写错误啦,正确的方法是morphs(),它会自动创建两个字段:added_by_type(存储关联模型的类名)和added_by_id(存储对应模型的ID),这正是多态关联需要的。
正确的迁移代码应该是这样的:
Schema::create('tasks', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('product_id'); $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); // 这里用morphs而不是morphes $table->morphs('added_by'); $table->timestamps(); });
执行这个迁移后,tasks表就会有added_by_type和added_by_id两个字段,用来关联User或Retailer模型。
2. 创建关联User的Task实例
首先你需要在Task模型里定义多态关联方法:
// app/Models/Task.php class Task extends Model { use HasFactory; protected $fillable = ['product_id', 'added_by_id', 'added_by_type']; // 定义多态关联 public function addedBy() { return $this->morphTo(__FUNCTION__, 'added_by_type', 'added_by_id'); } }
然后创建关联User的Task有几种方式:
方式一:直接指定字段值
use App\Models\Task; use App\Models\User; $user = User::find(1); Task::create([ 'product_id' => 1, 'added_by_id' => $user->id, 'added_by_type' => User::class, // 这里传入User模型的完整类名 ]);
方式二:用关联方法的associate()
$task = new Task(['product_id' => 1]); $task->addedBy()->associate($user); $task->save();
方式三:从User模型反向关联创建(推荐)
如果在User模型里定义反向关联:
// app/Models/User.php class User extends Model { // ...其他代码 public function tasks() { return $this->morphMany(Task::class, 'added_by'); } }
那创建起来更简单:
$user->tasks()->create(['product_id' => 1]);
同样的,Retailer模型也可以这样定义反向关联,用来创建关联Retailer的Task。
3. 判断Task关联的是User还是Retailer
有两种常用的方法:
方法一:检查added_by_type字段
直接判断模型类名:
$task = Task::find(1); if ($task->added_by_type === User::class) { // 关联的是User echo "这个任务是用户创建的"; } elseif ($task->added_by_type === Retailer::class) { // 关联的是Retailer echo "这个任务是零售商创建的"; }
方法二:用instanceof判断关联模型实例
先加载关联模型,然后判断实例类型:
$task = Task::with('addedBy')->find(1); if ($task->addedBy instanceof User) { // 关联的是User } elseif ($task->addedBy instanceof Retailer) { // 关联的是Retailer }
这种方法更面向对象,而且如果后续模型类名有修改(比如命名空间变更),只要实例是对应的模型,判断依然有效。
内容的提问来源于stack exchange,提问作者Anoop Krishnan
相关产品推荐
相关产品推荐

