如何将 Laravel 的多态系统应用于似乎被逆转的事物

Posted

技术标签:

【中文标题】如何将 Laravel 的多态系统应用于似乎被逆转的事物【英文标题】:How can I apply Laravel's polymorph-system to what seems to be reversed 【发布时间】:2021-11-01 19:11:17 【问题描述】:

背景

在我们的 Laravel 系统中,我们有一个 Post,例如VideoPost 或 TextPost(类型存储在 type-attribute 中)。每个帖子(无论是什么类型)都依赖于翻译,因此我们让每个帖子都有一个 PostTranslation,其中包含与 VideoPostTranslation 或 TextPostTranslation 的一对多关系。

这意味着我要访问 Post 的翻译内容,首先必须获取 Post,然后检查类型,并获取相关的 PostTranslations 和它的任何子类型(例如 VideoPostTranslation)。

我们现在已经意识到这是次优的,我们希望就如何实现这一点获得一些帮助。

目标

我们想将我们的数据库转换成这样的:

[Post]
int: id
str: type // one of [video, text]

[VideoPostTranslation]
int: id
int: post_id
str: language_code
str: video_specific_data

[TextPostTranslation]
int: id
int: parent_id
str: language_code
str: text_specific_data

在这个结构中,没有冗余数据,希望 Laravel 可以帮助我们查询这个。

最好是我们希望能够编写如下内容:

$posts = Post::with('translations')->get();

foreach($posts as $post) 
  switch($post->type) 
    case 'video': 
      // handle $post->translations[]->video_specific_data
    case 'text':
      // handle $post->translations[]->text_specific_data
  

我们已经看到 Laravel 有一个很好的类之间的变形系统,但它通常要求包含类型数据的系统也是处理变形的系统。在他们的一对多示例中,他们使用可评论系统,其中评论可以通过commentable-relation 引用帖子和视频,但我不确定这在我们的案例中如何工作。

例如,这将不起作用:

class Post extends Model

  public function translations()
  
    return $this->morphTo();
  


class VideoPostTranslation extends Model

  public function post()
  
    return $this->morphMany(Post::class, 'translations');
  


class TextPostTranslation extends Model

  public function post()
  
    return $this->morphMany(Post::class, 'translations');
  

我们需要“实施”哪些改变?我们是否需要添加一个名为 PageTranslation 的中间多对多表来处理这种关系?或者是否可以让 Laravel 使用建议的数据库结构?

【问题讨论】:

【参考方案1】:

在我看来,你们的关系很好,应该会奏效。 您能否进一步解释一下它是如何不起作用的以及您遇到了什么错误。此外,提供的foreach 循环中的switch 语句可能不是必需的。而不是

foreach($posts as $post) 
  switch($post->type) 
    case 'video': 
      // handle $post->translations[]->video_specific_data
    case 'text':
      // handle $post->translations[]->text_specific_data
  

您可以通过关系名称直接访问其翻译后的模型。传递语言键以检索特定语言的翻译。

foreach($posts as $post) 
    $post->translations()->where('language_code', $langKey)->first()->content;

如果video_post_translationstext_post_translations 有其独特的字段,例如video_post_translations 有一个video,而在text_post_translations 表中,这个video 字段不存在(这很可能),可以使用switch case

如果仍然使用switch case,请考虑将video_post_translationstext_post_translations 表分组,这肯定会简化问题,因为posts.type 已经区分了所需的字段。根据您的需要,这种方法可能不适合。

【讨论】:

我已经使用建议的数据库结构和模型代码进行了测试,但它目前不起作用。我知道要让它按照 Laravel 的意图工作,我们需要多态关系以另一种方式进行,例如这意味着一篇帖子需要通过指定typeid 来引用一个VideoPageVersion。我意识到它可以通过数据透视表来解决,所以我想我们只需要尝试一下。

以上是关于如何将 Laravel 的多态系统应用于似乎被逆转的事物的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 5分离/删除多态关系

如何在laravel中获得多态关系?

Laravel 5:没有 CSRF 检查的 POST

Laravel - 渴望加载多态关系的相关模型

Laravel 4:如何将 WHERE 条件应用于 Eloquent 类的所有查询?

在 Laravel 中:如何根据 URI 将多个过滤器应用于一整套路由?