Laravel 的 Eloquent ORM 与查询生成器

Laravel's Eloquent ORM versus Query Builder

我有 2 个 table:usersarticlesusers table 有一个名为 is_suspended 的列,它接受 yesno,而 articles table 有一个名为 is_published 接受 01。要从数据库中获取文章数据,articles.is_published 必须等于 1 并且 users.is_suspended 必须等于 no。现在假设 users.is_suspended 等于 yes,如果我尝试像这样使用查询生成器获取文章数据:

// first code:

    $articles = Article::join('users', 'articles.user_id', '=', 'users.user_id')
        ->select(['articles.*', 'users.user_name', 'users.user_email'])
        ->where('articles.article_id', '=', 9)
        ->where('articles.is_published', '=', 1)
        ->where('users.is_suspended', '=', 'no')
        ->get();

这将完美地工作并且 return 什么都不会(因为 users.is_suspended = yes)。现在让我们尝试使用 Laravel Eloquent ORM 获取同一篇文章,如下所示:

// second code:

$articles = Article::with([
    'user' => function($query) {
        $query->select(['user_id', 'user_name', 'user_email'])
            ->where('users.is_suspended', '=', 'no');
    }])
    ->where('articles.article_id', '=', 9)
    ->where('articles.is_published', '=', 1)
    ->get();

在这种情况下我会得到下一个结果:

[
  {
    article_id: 9,
    user_id: 1,
    article_title: "Article title here",
    article_body: "Article body here",
    is_published: 1,
    created_at: "2015-01-17 02:26:24",
    updated_at: "2015-01-17 02:26:24",
    user: null
  }
]

即使用户被挂起,它也会获取文章的数据,这是错误的。所以我的问题是如何修复第二个代码使其像第一个代码一样?

您可能想使用 with 来确保延迟加载关系,但您对其施加的任何约束仅适用于加载的关系。要限制对用户未暂停的文章的响应,您需要使用 whereHas 方法。

$articles = Article::with(['user' => function($q){
        $q->select(['user_id', 'user_name', 'user_email', 'created_at']);
    }])
    ->whereHas('user', function($q) {
        $q->where('is_suspended', '=', 'no');
    })
    ->where('articles.article_id', '=', 9)
    ->where('articles.is_published', '=', 1)
    ->get();

你需要 whereHas 而不是 with(或两者都需要,但在这种情况下不需要 with),就像@DavidBarker 说的那样。

但是我建议更多,请考虑这段代码的可读性:

$article = Article::whereHas('user', function ($q) {
   $q->active();
})->published()->find(9);

它利用了scopes

因此,您可以采取以下措施让您的生活更轻松:

  1. is_suspended 更改为 bool 因为:

    $user->is_suspended; // no
    (bool) $user->is_suspended; // true    
    
  2. User 模型上定义范围 suspended 并在 Article 上定义范围 published:

    // Article model - on User accordingly
    public function scopePublished($query)
    {
        $query->where('is_published', 1);
    }
    
  3. 当你想获取单个模型时使用find($id)where('col', $id)->first()而不是get,因为后者会return一个集合,甚至虽然只有一个结果。