必须用 $table->morphs('commentable') 创建标准多态字段及联合索引,确保 commentable_id 为 unsignedBigInteger、commentable_type 为长度≥255的string,并配置 Relation::morphMap 映射短名以避免类名过长问题。

要让 Laravel 的评论模型既能关联文章又能关联视频,必须先建出能同时指向多个模型的数据库表结构,字段名、类型、索引缺一不可,否则 morphTo() 会返回 null、with('commentable') 查不到数据、甚至报 Class not found 错误。
用 morphs() 一行创建标准字段和索引
在迁移文件的 up() 方法中写入:$table->morphs('commentable');。
这行代码会自动创建 commentable_id(unsignedBigInteger)、commentable_type(string,长度 255)、联合索引 ['commentable_id', 'commentable_type'],三者一步到位。
不要手写 $table->unsignedBigInteger('commentable_id') 再加 $table->string('commentable_type')——漏掉索引或类型长度不足,后续 with 预加载就会全表扫描。
运行 php artisan migrate 执行迁移。
手动建表时必须满足的硬性条件
方法一:字段名与类型不可更改
【commentable_id 必须是 unsignedBigInteger,不能用 id 或 integer 替代】
【commentable_type 必须是 string 且长度 ≥255,否则存不下 App\Models\Content\Article 这类长类名】
方法二:索引顺序影响查询性能
复合索引必须是 ['commentable_type', 'commentable_id'],不是反过来——因为 type 值离散度高,放前面能更快过滤出候选行。
方法三:外键约束不适用
别给 commentable_id 加 foreignKey(),Laravel 多态目标不唯一,数据库层无法定义标准外键;morphs() 默认也不加,这是故意的设计。
配置 morphMap 避免类名过长和部署失败
第一步:在 AppServiceProvider 的 boot() 方法中注册映射
Relation::morphMap([
'post' => App\Models\Post::class,
'video' => App\Models\Video::class,
'image' => App\Models\Image::class,
]);
第二步:确保数据库 commentable_type 字段存的是 'post'、'video' 这类短名,而不是完整类名。
第三步:所有被关联模型(Post/Video/Image)的 comments() 关系中,morphMany 的第二个参数必须和 Comment 模型里 morphTo() 的方法名完全一致——比如都叫 'commentable'。
这一步漏掉,$post->comments 就查不到,$comment->commentable 也解析失败。


















