在 Laravel / Eloquent 中,如何获取项目以及 'liked' 或 'disliked' 状态

In Laravel / Eloquent, how to fetch items along with 'liked' or 'disliked' status

这是对我之前提出的一个问题的扩展,该问题是如何设置 。一个用户可以创建多个想法。任何用户都可以 'like' 或 'dislike' 任何想法。

如前一篇文章所述,这是我在 Laravel 中的关系:

用户

public function ideas(){
    return $this->hasMany('Idea');
}

public function liked(){
    return $this->belongsToMany('Idea', 'ideas_likes')->withPivot('liked');
}

想法

public function likes(){
    return $this->belongsToMany('User', 'ideas_likes')->withPivot('liked');
}

public function user(){
    return $this->belongsTo('User');
}

我的'ideas_likes'table看起来像:

ideas_likes
------------
id        primary key
user_id   foreign key
idea_id   foreign key
liked     boolean

我有一个网页列出了来自不同用户的想法。只有经过身份验证的用户才能访问此页面。每个想法旁边都有一个 喜欢 不喜欢 按钮。单击 like 按钮时,将向 ideas_likes table 添加一个条目,并将 'liked' 布尔值设置为 true。单击 dislike 按钮时,添加条目时 'liked' boolen 设置为 false。

当用户 不喜欢 某个想法时,该想法不应再显示在该用户的列表中。如果用户 喜欢 一个想法,则该想法将在列表中突出显示。

在我的视图中展示想法时,我会像这样循环浏览它们:

@foreach ($ideas as $idea)
  <div class="idea">
    <h1>{{ $idea->title }}</h1>
    <p>{{ $idea->description }}</p>
  </div>
@endforeach

但是,如前所述,我想强调查看列表的用户 'liked' 提出的想法。也许它看起来像这样:

@foreach ($ideas as $idea)
  <div class="idea@if($idea->liked) highlight@endif">
    <h1>{{ $idea->title }}</h1>
    <p>{{ $idea->description }}</p>
  </div>
@endforeach

此外,我还希望显示创意作者的用户名(不一定与登录用户相同):

@foreach ($ideas as $idea)
  <div class="idea@if($idea->liked) highlight@endif">
    <h1>{{ $idea->title }}</h1>
    <p>{{ $idea->description }}</p>
    <p>{{ $idea->user->username }}</p> <=== SOMETHING LIKE THIS
  </div>
@endforeach

在将 'likes' 的概念引入我的应用程序之前,我收集想法和用户信息的查询如下所示:

$ideas = Idea::with('user')->orderBy('created_at', 'desc')->get();

那是返回所有想法的列表,以及它们的相关用户信息。然而,现在它变得更加棘手。我想要所有的想法,加上它们相关的用户信息(无论是谁发布的),除了那些被当前经过身份验证的用户不喜欢的想法,并且还突出显示它们是否被经过身份验证的用户喜欢。呸!

如有任何帮助,我们将不胜感激。

这会处理预先加载并过滤掉当前用户不喜欢的想法。

$ideas = Idea::with('user', 'likes')->whereDoesntHave('likes', function($q){
    $q->where('user_id', Auth::id());
    $q->where('liked', false);
})->get();

现在您可以添加 accessor 来创建动态 liked 属性。在 Idea:

public function getLikedAttribute(){
    $user = $this->likes->find(Auth::id());
    return $user != null && $user->pivot->liked == true;
}

您可以像在问题中使用它一样使用它。 $idea->liked。请注意,您应该预先加载 likes 才能使用此访问器。否则,对于每个想法,当您访问 ->liked.

时,都会有一个额外的查询 运行 fetch likes

更新:更高效

我找到了一种方法,可以让它更有效率,而且每个想法都没有循环。但是我觉得它有点丑。为了能够急切加载数据,我必须创建一个新关系。

public function likedByCurrentUser(){
    return $this->belongsToMany('User', 'ideas_likes')
                ->where('user_id', Auth::id())
                ->where('liked', true)
                ->selectRaw('COUNT(*) > 0 AS liked');
}

这是重写的访问器:

public function getLikedAttribute(){
    return !! $this->likedByCurrentUser->first()['liked'];
}

你看,循环消失了!

最后你需要预先加载新的关系。这是示例:

$ideas = Idea::with('user', 'likedByCurrentUser')->whereDoesntHave('likes', function($q){
    $q->where('user_id', Auth::id());
    $q->where('liked', false);
})->get();

或者,您可以将 likedByCurrentUser 添加到模型中的 with 数组,这样它就会一直被预先加载。

protected $with = array('likedByCurrentUser');

更新 2

现在看看我的旧解决方案,我相信这可以做得更好(希望它也能正常工作)

关系:

public function likedByCurrentUser(){
    return $this->belongsToMany('User', 'ideas_likes')
                ->where('user_id', Auth::id())
                ->where('liked', true);
}

访问者:

public function getLikedAttribute(){
    return ! $this->likedByCurrentUser->isEmpty();
}

用法同上。