首页 > 解决方案 > 如何使用数据透视表中的数据过滤 Eloquent 集合

问题描述

我正在寻找一种精细而简洁的解决方案,以使用相关数据透视表中的数据过滤我的 Eloquent 集合。我实际上已经找到了解决问题的方法,尽管感觉我的解决方案有点糟糕。这是我得到的:

两个模型视频和用户,每个用户都可以单独跟踪视频的进度。为此,我需要在与用户相关的评级表中保存每个视频的进度。当您只想搜索进度时,除了一些其他过滤器(类别、全文搜索)之外,您还可以这样做。我觉得有点奇怪的是,我必须将“where()”部分加倍,我正在检查登录用户的视频进度。

视频.php

class Video extends Model
{
    use SearchableTrait;
    use Taggable;
    [...]
    public function videocreator(){
        return $this->belongsTo('App\User', 'create_user_id');
    }

    public function users(){
        return $this->belongsToMany('App\User', 'progress', 'video_id', 'user_id')
            ->withPivot('progress_index')
            ->withTimestamps();
    }
    [...]
}

用户.php

class User extends Authenticatable
{
    use Notifiable;
    [...]
    public function videoscreated(){
        return $this->hasMany('App\Video');
    }

    public function videos(){
        return $this->belongsToMany('App\Video', 'progress', 'user_id', 'video_id')
            ->withPivot('progress_index')
            ->withTimestamps();;
    }
}

视频控制器.php

class VideoController extends Controller
{
    public function index(Request $request)
    {
    [...]
    $videos = Video::with('videocreator')->with(['users' => function ($query) {
                $query->where('users.id', '=', auth()->user()->id);
        }])->latest();

    if($request->filled('progress') && $request['progress'] !== 'all'){
            $videos = $videos->whereHas('users', function($query) use($selectedProgress) {
                $query->where('progress_index', $selectedProgress)->where('users.id', '=', auth()->user()->id);
                });
        }

    $videos = $videos->get();
    [...]
}

如您所见,这部分where('users.id', '=', auth()->user()->id)是重复的。我的一个来自 Ruby on Rails Faction 的朋友建议先从用户模型中获取视频(这就是你在那里的做法)。尽管通过这种方式,您可以将视频限制在进度表中的用户范围内。这不是你想要的。该应用程序应仅跟踪每个视频的每个用户进度,这意味着所有用户都可以看到所有视频(而不是不属于他们自己的进度。另一种方法是将您为用户过滤的部分放入关系中. 一种方法如:myProgress()或类似的东西。

你对此有何看法?有没有更“雄辩”的方法来解决这个问题?提前感谢您阅读这篇文章!

标签: laraveleloquentpivot

解决方案


我会做这样的事情:

// Get an instance of the videos relationship of the current authenticated user
// Eager load the videocreator relationship
$videoQuery = request()->user()->videos()->with('videocreator');

if ($request->filled('progress') && $request->input('progress') !== "all") {
  // Constrain the query : only get the videos with rated_index equal to $selectedProgress
  $videoQuery = $videoQuery->wherePivot('rated_index', $selectedProgress);
}

// Finally, run the query against the database
$videos = $videoQuery->latest()->get();

推荐阅读