You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中将多态系统应用于反向关联的多类型文章翻译场景

结论

不需要新增额外中间表,你当前的数据库结构可以直接被Laravel支持,之前的代码报错是因为多态关联的方向写反了。

适配方案

我们可以通过「双关联预加载 + 动态属性」的方式实现你要的调用效果,完全不需要修改表结构,哪怕TextPostTranslation用的是parent_id作为外键也可以正常适配:

1. 改写Post模型

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Post extends Model
{
    // 视频类型翻译关联
    public function videoTranslations(): HasMany
    {
        return $this->hasMany(VideoPostTranslation::class, 'post_id');
    }

    // 文字类型翻译关联,适配非标准外键parent_id
    public function textTranslations(): HasMany
    {
        return $this->hasMany(TextPostTranslation::class, 'parent_id');
    }

    // 动态返回对应类型的翻译集合
    public function getTranslationsAttribute()
    {
        return match ($this->type) {
            'video' => $this->videoTranslations,
            'text' => $this->textTranslations,
            default => collect(),
        };
    }

    // 实现translations关联的预加载支持
    public function scopeWithTranslations($query)
    {
        return $query->with(['videoTranslations', 'textTranslations']);
    }
}

2. 翻译模型反向关联写法

class VideoPostTranslation extends Model
{
    public function post()
    {
        return $this->belongsTo(Post::class, 'post_id');
    }
}

class TextPostTranslation extends Model
{
    public function post()
    {
        return $this->belongsTo(Post::class, 'parent_id');
    }
}

3. 调用方式和你预期完全一致

// 预加载所有翻译,仅会执行3次查询:查Post、查所有VideoPostTranslation、查所有TextPostTranslation,开销极低
$posts = Post::withTranslations()->get();

foreach($posts as $post) {
  switch($post->type) {
    case 'video': 
      // 直接获取video_specific_data字段
      foreach($post->translations as $translation) {
          echo $translation->video_specific_data;
      }
      break;
    case 'text':
      // 直接获取text_specific_data字段
      foreach($post->translations as $translation) {
          echo $translation->text_specific_data;
      }
      break;
  }
}

进阶优化(可选)

如果你希望完全使用Post::with('translations')的写法,不需要调用自定义scope,可以把两个翻译关联加入模型的$with属性实现自动预加载,或者通过Laravel的关联宏自定义translations关联的预加载逻辑即可。


内容的提问来源于stack exchange,提问作者Sebastian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 08:48:01