2015-11-06 18 views
1

这是通过人工获取的数据作为一个数组,然后repassing它:如何在Eloquent子查询中使用自定义查询范围?

public function scopeWhereWhitelisted($query, $value=true, Tenant $tenant) 
{ 
    return $query->where(function($query)use($value,$tenant) 
    { 
     $user_id_list = $tenant->getWhiteListedUsersGroup() 
               ->users() 
               ->select('users.id') 
               ->lists('id') 
               ->all() 
     ; 

     $query->{ $value ? 'whereIn' : 'whereNotIn' }('users.id',$user_id_list); 
    }); 
} 

但我想这个工作(注释//表示唯一的区别):

public function scopeWhereWhitelisted($query, $value=true, Tenant $tenant) 
{ 
    return $query->where(function($query)use($value,$tenant) 
    { 
     $user_id_list = $tenant->getWhiteListedUsersGroup() 
               ->users() 
               ->select('users.id') 
               //->lists('id') 
               //->all() 
     ; 

     $user_id_list = $tenant->getWhiteListedUsersGroup()->users()->select('users.id');//->lists('id')->all(); 
     $query->{ $value ? 'whereIn' : 'whereNotIn' }('users.id',$user_id_list); 
    }); 
} 

我想成为能够创建一个“真正的”子查询,而不必为每个范围提供自定义查询范围和关系查询的重复副本。 $tenant->getWhiteListedUsersGroup()->users()是许多一对多的关系

这里是什么工作要做,以获得真正的子查询的例子:

public function scopeWhereWhitelisted($query, $value=true, Tenant $tenant) 
{ 
    return $query->where(function($query)use($value,$tenant) 
    { 
     $query->{ $value ? 'whereIn' : 'whereNotIn' }('users.id',function($query) 
     { 
      $query->from('groups_memberships') 
        //  recreating an existing relationship function 
        ->join('groups','groups.id','group_memberships.group_id') 
        ->select('users.id') 
        //  recreating an already existing query scope 
        ->whereNull('deleted_at') 
      ; 
     }); 
    }); 
} 
  • 这个问题很可能会同时适用于Laravel 4.0+和5.0+
  • 这个问题未回答How to do this in Laravel, subquery where in
  • 重构代码以便查询从预期的子查询开始,只要我需要第二个非平凡的子查询就不会工作。
  • 列入/排除->getQuery()并没有区别。
  • 我必须在假的子选择或非DRY自定义查询范围之间进行选择。
  • 看来主要的问题是子选择引擎迫使我使用不能从现有关系初始化的预先存在的$query对象。
  • 软删除的重新创建(whereNull('deleted_at'))是一个简单的例子,但我可能必须重新创建一个可能相对复杂的queryscope。

回答

0

这是你最喜欢的吗?

$value; //true or false 

$tenant->whereHas('user', function($query) use ($value){ 
    $query->whereHas('groupMembership', function($query) use ($value){ 
     $query->whereHas('group', function($query) use ($value){ 
      if($value){ $query->onlyTrashed();) 
     }); 
    }) 
}) 

这假定该组关系包括在关系

+0

'一个withTrashed()调用whereHas'是严格假表。每个'whereHas'都为每个表格计算一个临时列。这意味着索引不能使用,并且会有全表扫描。你有三个'whereHas'嵌套,这意味着对于用户表中的每一行,MySQL必须计算“has groupMembership”tmp列。要确定,groupMember的每个全表扫描都将执行组的全表扫描。这基本上是指数增长的全表扫描的3层。 https://github.com/laravel/framework/issues/3543 – InstanceOfMichael