問題描述
目前我在我的模型集合中有這個 whereHas:
$query = self::whereHas('club', function($q) use ($search){$q->whereHas('owner', function($q) use ($search){$q->where('name', 'LIKE', '%'. $search .'%');});});
我的印象是上面的代碼可能是這樣的:
$query = self::whereHas('club.owner', function($q) use ($search){$q->where('name', 'LIKE', '%'. $search .'%');});
我知道這已經很強大了,但即便如此,如果我有一個 5 層深的嵌套關系,事情就會變得很糟糕.
更新:
正如評論中所述,我最終沒有說清楚我的問題,我深表歉意.
我將嘗試使用一個簡單的例子,考慮$owner->club->membership->product->package
,現在從所有者我想搜索某個包,應該是這樣的:
$query = self::whereHas('club', function($q) use ($search){$q->whereHas('membership', function($q) use ($search){$q->whereHas('product', function($q) use ($search){$q->whereHas('package', function($q) use ($search){$q->where('alias', 'LIKE', '%'. $search .'%');});//包裹});//產品});//會員資格});//俱樂部
這是正確的嗎?有捷徑嗎?
更新:PR 剛剛合并到 4.2,所以現在可以在 點嵌套 表示法>has
方法 ( ->has('relation1.relation2)
->whereHas('relation1.relation2, ..
)
您的問題仍然有點不清楚,或者您誤解了 whereHas() 方法,因為它用于過濾模型(在本例中為用戶)并僅獲取那些具有符合搜索條件的相關模型的模型.>
看來您想從給定的用戶的上下文中查找包,所以不需要使用 whereHas 方法.
無論如何,取決于關系(1-1,1-m,m-m),這可能很容易,也可能非常困難,而且效率不高.正如我所說,加載嵌套關系意味著對于每一級嵌套都會出現另一個 db 查詢,因此在這種情況下,您最終會得到 5 個查詢.
無論關系如何,您都可以像這樣反轉此鏈,因為這樣會更容易:
<小時>這不會在 atm 工作,因為 whereHas() 不處理點嵌套關系!
//給定 $user 和 $search:$packages = Package::where('alias','like',"%$search%")->whereHas('product.membership.club.user', function ($q) use ($user) {$q->whereId($user->id);})->get();
<小時>
如您所見,這更具可讀性,但仍運行 5 個查詢.通過這種方式,您可以獲得 $packages,這是您想要的模型的單個集合.
雖然從用戶的上下文中你會得到這樣的東西(再次取決于關系):
$user|-俱樂部||-會員|||-產品||||-包|||-另一個產品||||-包|||-又一個產品|||-包||-另一個會員.....
你明白了,不是嗎?
您可以從 Collection 中獲取包,但這會很麻煩.反過來更容易.
所以你的問題的答案就是加入表格:
//讓我們假設關系是最容易處理的:1-many$packages = Package::where('alias','like',"%$search%")->join('products','packages.product_id','=','products.id')->join('memberships','products.membership_id','=','memberships.id')->join('clubs','memberships.club_id','=','clubs.id')->where('clubs.user_id','=',$user->id)->get(['packages.*']);//除了包表外不要選擇任何東西
當然你可以用一個很好的方法包裝它,這樣你就不必每次執行這樣的搜索時都寫這個.這個查詢的性能肯定會比上面顯示的單獨 5 個查詢好得多.顯然這種方式你只加載包,沒有其他相關的模型.
Currently I have this whereHas in a collection of my model:
$query = self::whereHas('club', function($q) use ($search)
{
$q->whereHas('owner', function($q) use ($search)
{
$q->where('name', 'LIKE', '%'. $search .'%');
});
});
I was under the impression the code above could be as such:
$query = self::whereHas('club.owner', function($q) use ($search)
{
$q->where('name', 'LIKE', '%'. $search .'%');
});
I'm aware this is already a lot of power, but even then, if I have a nested relationship 5 levels deep, things will get ugly.
Update:
As stated in the comments, I ended up not making my question clear, I apologize.
I will try to use a simple example, consider $owner->club->membership->product->package
, now from owners I want to search a certain package, it would be something like this:
$query = self::whereHas('club', function($q) use ($search)
{
$q->whereHas('membership', function($q) use ($search)
{
$q->whereHas('product', function($q) use ($search)
{
$q->whereHas('package', function($q) use ($search)
{
$q->where('alias', 'LIKE', '%'. $search .'%');
});//package
});//product
});//membership
});//club
Is this correct? Is there a shortcut?
Update: the PR has been just merged to 4.2, so now it's possible to use dot nested notation in has
methods ( ->has('relation1.relation2)
->whereHas('relation1.relation2, ..
)
Your question remains a bit unclear or you misunderstand whereHas() method as it is used to filter models (users in this case) and get only those that have related models fitting search conditions.
It seems that you want to find Packages from the context of a given User, so no need to use whereHas method.
Anyway depending on the relations (1-1,1-m,m-m) this can be easy or pretty hard and not very efficient. As I stated, loading nested relations means that for every level of nesting comes another db query, so in this case you end up with 5 queries.
Regardless of the relations you can invert this chain like this, as it will be easier:
edit: This is not going to work atm as whereHas() doesn't process dot nested relations!
// given $user and $search:
$packages = Package::where('alias','like',"%$search%")
->whereHas('product.membership.club.user', function ($q) use ($user) {
$q->whereId($user->id);
})->get();
As you can see this is much more readable, still runs 5 queries. Also this way you get $packages, which is a single Collection of the models you wanted.
While from the context of a user you would get something like this (depending on the relations again):
$user
|-club
| |-membership
| | |-product
| | | |-packages
| | |-anotherProduct
| | | |-packages
| | |-yetAnotherProduct
| | |-packages
| |-anotherMembership
.....
You get the point, don't you?
You could fetch the packages from the Collection, but it would be cumbersome. It's easier the other way around.
So the answer to your question would be simply joining the tables:
// Let's assume the relations are the easiest to handle: 1-many
$packages = Package::where('alias','like',"%$search%")
->join('products','packages.product_id','=','products.id')
->join('memberships','products.membership_id','=','memberships.id')
->join('clubs','memberships.club_id','=','clubs.id')
->where('clubs.user_id','=',$user->id)
->get(['packages.*']); // dont select anything but packages table
Of course you can wrap it in a nice method so you don't have to write this everytime you perform such search. Performance of this query will be definitely much better than separate 5 queries shown above. Obviously this way you load only packages, without other related models.
這篇關于Eloquent 嵌套 whereHas的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!