首页
Preview

Laravel:优雅地使用 Has Many Through Pivot…

Laravel Relationships 覆盖了模型可以访问的所有内容。我们有_一对一_,一对多多对多,_多态_关系等等。但是有一种关系没有被覆盖,因为它非常特殊:通过多对多关系访问枢轴

_通过多对多枢轴_意味着:通过使用枢轴表(甚至是多态表)连接的另一个关系来访问遥远的“一对多”关系。

而你也可以做到:

  • 不用下载 composer 包,不用管它们是做什么的,
  • 不用创建无数个类来重写 Eloquent Relationships,就像它们是你的亲密朋友一样,
  • 不用编写原始的 DB 调用和连接,就像你在 3 个月后还会理解你所做的一样。

而且只有一种方法可以做到这一点,优雅

让我们来制定一个可以使用这个的情景

让我们暂时忘记 自适应比特率流 吧?

我有一个网站,人们可以制作播客。他们上传他们的音频文件用于他们的播客,并让用户通过订阅来听它们。问题在于音质:只有_为播客付费的用户_才能听到高质量的版本。

让我们明确一下:我们有一个播客,每个播客都有很多音频文件。虽然播客保存有关其自身的信息,例如主持人、主题、持续时间和闪存图像,但音频文件则引用可用于播客的不同音频质量,例如 64 kbps MP3 和 192 kbps。因此,在这种情况下,我们将为一个播客有 2 个音频文件。

通过这种方法,付费用户可以访问比那些不付费的用户更高质量的文件,而后者将被困在像 1998 年那样的 64kbps 音频中。

我们如何将用户与播客关联起来?一个订阅枢轴将帮助我们完成这两个,我们还将使用一个漂亮的 has_paid 布尔列保存用户是否已为播客付费。这基本上是一个_多对多_关系。有很多用户,也有很多播客。

关系访问将如下所示:

我对任何形式的绘画都不擅长。艺术是我最差的科目。抱歉。

嗨,应用程序,我的最新高质量音频文件是什么?嗯?

乍一看,我们知道我们不能直接从用户模型访问音频文件,因此我们必须首先通过查询播客,然后查询音频文件

从用户,但按播客分组,这不是我们要找的。

$user->podcasts()
    ->with([
        'audioFiles' => function ($query) {
            return $query->orderBy('created_at', 'desc');
        }
    ])
    ->get();

幼稚的做法可能会使用类似以下内容的东西来获取所有音频文件。

AudioFiles::whereHas('podcast', function($query) use ($user) {
    return $query->whereHas('user', function($query) use ($user) {
        return $query->where('user_id', $user->id)
            ->where('has_paid', true);
    });
})->orderBy('created_at', 'desc')->get();

我们如何简化此过程?我们只需要音频文件,不需要整个播客和其他东西!这很容易。如果你理解了在图像中突出显示 ID 的目的,那么下一步将比水更清楚。

第一步:创建订阅枢轴

这样可以直接访问枢轴表信息,而无需使用原始的 DB 调用。你可以使用 Artisan 来创建它,也可以手动编写。

如果你的 Pivot 想连接一个可变模型,这个类应该扩展 MorphPivot 而不是常见的 Pivot。多态枢轴声明_几乎_相同。

第二步:准备你的播客模型

在这里,我们需要告诉播客模型,我们将使用我们新创建的 Subscription Pivot 模型将其连接到用户模型。

// App\Podcast.phppublic function users()
{
    return $this->belongsToMany('App\Users')
        ->using('App\Pivots\Subscription');
}

第三步:准备你的用户模型

同样,用户模型也是相同的概念。

// App\User.phppublic function podcasts()
{
    return $this->hasMany('App\Podcast')
        ->using('App\Pivots\Subscription');
}

最后一步:添加魔术粉

不要关闭你的编辑器中的用户模型!现在我们必须告诉它使用_Has Many Through_关系访问音频文件,但不是从播客模型,而是从我们的订阅枢轴模型

有了这个魔法,你可以毫不费力地从用户模型访问音频文件,无论它可能有多少个可听的音频文件。作为奖励,我们不创建任何难以维护的新类,只是 Laravel 给我们的。

可选:定义关系的反向

要在音频文件上执行相同的操作,你可以告诉模型使用订阅枢轴模型进行连接:

public function users()
{
    return $this->hasManyThrough(
        'App\Users'
        'App\Pivots\Subscription',
        'podcast_id',
        'user_id',
        'id',
        'podcast_id'
    );
}

一旦我们这样做,我们就可以访问多少用户可以通过订阅来访问这些文件。我们完成了,现在我们可以做到这样的事情:

/* Get the latest Audio File the user is Subscribed, in HQ */
$user->audioFiles()
    ->where('quality', '>=', 192)
    ->orderBy('created_at', 'desc')
    ->first();

如何按枢轴列过滤?

假设有人创建了一个仅付费的播客。没问题。

要过滤付费播客后面的音频文件,供免费用户使用,我们只需在查询构建器上调用 wherePivot() 方法即可。

/* Get the latest Audio File this Free User can listen to */
$user->audioFiles()
    ->wherePivot('has_paid', false)
    ->orderBy('created_at', 'desc')
    ->first();

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
anko
宽以待人处事,严于律己修身。

评论(0)

添加评论