laravel-polymorphic-relations
test12026-10-2517 次阅读
痛点:评论表跟着资源爆炸
文章、视频、商品都要评论,如果每种资源各建一张评论表,迁移和逻辑都会重复。多态关联让一张 comments 表靠 commentable_type 和 commentable_id 两个字段,同时挂载到任意多种模型上。
建表:morphs 帮你生成两列
morphs('commentable') 一次生成 commentable_type 和 commentable_id,类型列存的是模型类名。
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->text('body');
$table->foreignId('user_id');
$table->morphs('commentable'); // commentable_type + commentable_id
$table->timestamps();
});
模型里声明两端关系
评论侧用 morphTo,资源侧用 morphMany,字段名要和迁移里的前缀一致。
class Comment extends Model
{
protected $fillable = ['body', 'user_id'];
public function commentable()
{
return $this->morphTo();
}
public function user()
{
return $this->belongsTo(User::class);
}
}
class Post extends Model
{
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
class Video extends Model
{
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
增删查都用同一套 API
无论评论的是文章还是视频,写法完全一致;反向从评论也能还原出被评论的对象。
$post = Post::find(1);
$post->comments()->create(['body' => '好文', 'user_id' => 1]);
$comment = Comment::find(1);
echo get_class($comment->commentable); // App\Models\Post
用 morphMap 别把类名写进数据库
默认 type 列存完整类名,一旦改名或改命名空间历史数据就错位。用 MorphMap 映射成短名,数据库只存短键。
use Illuminate\Database\Eloquent\Relations\MorphMap;
MorphMap::set([
'post' => Post::class,
'video' => Video::class,
]);
记得预加载,别踩 N+1
列表里要带评论时,用 with('comments') 一次性取出;跨多种资源时给每种资源分别 with 即可。
多态关联是 Laravel 关系里最省表的设计之一,评论、点赞、附件、标签都该优先考虑它。
T
test1
文章作者
痛点:评论表跟着资源爆炸 文章、视频、商品都要评论,如果每种资源各建一张评论表,迁移和逻辑都会重复。多态关联让一张 c...
- 分类
- 技术
- 发布时间
- 2026-10-25
- 字数
- 约 1619 字
- 阅读
- 17 次
