2015-01-17 121 views
0

我有2个表格:usersarticlesusers表具有名为is_suspended的列,其接受yesno,并且articles表具有名为is_published的列,其接受01。要从数据库中提取商品数据,articles.is_published必须等于1,而users.is_suspended必须等于no。现在假设users.is_suspended等于yes,如果我尝试使用查询生成器这样获取的文章的数据:Laravel的Eloquent ORM与查询生成器

// 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(); 

这将很好地工作,并且将返回任何结果(因为users.is_suspended = yes)。现在,让我们尝试获取与Laravel雄辩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 
    } 
] 

,将取回物品,即使用户的数据被暂停,这是错误的。所以我的问题是如何解决第二个代码行为像第一个代码?

回答

2

您可能想要使用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(); 
+0

这很好。但是,如何选择特定列和我应该放在哪里:select(['user_id','user_name','user_email'])。我曾试图这样做:$ q-> select(['user_id','user_name','user_email','created_at']) - > where('is_suspended','=','no');但它会导致错误:(基数违规:1241操作数应该包含4列)。 – Amr

+0

为你添加它,你把它放在原来的位置,用'with'方法回调。 –

+0

它导致错误说:explode()期望参数2是字符串,给定的对象。 – Amr

0

你需要whereHas而不是with(或两者兼而有之,但在这种情况下没有必要with),像@DavidBarker说。

不过我建议多,考虑下面的代码可读性:

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

它利用scopes

因此,这里是你可以做什么,让您的生活更轻松:

  1. 变化is_suspendedbool因为:

    $user->is_suspended; // no 
    (bool) $user->is_suspended; // true  
    
  2. User模型和published定义范围suspendedArticle

    // Article model - on User accordingly 
    public function scopePublished($query) 
    { 
        $query->where('is_published', 1); 
    } 
    
  3. 如果您想要获取单个模型,请使用find($id)where('col', $id)->first()而不是get,因为后者将返回集合,即使只有一个结果。