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();
评论(0)