Laravel 4 - 在构建集合时将 where 子句附加到关系的雄辩方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19635624/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 08:36:39  来源:igfitidea点击:

Laravel 4 - Eloquent way to attach a where clause to a relationship when building a collection

phpormlaravellaravel-4eloquent

提问by SwiftD

This may be a dupe but I've been trawling for some time looking for a proper answer to this and haven't found one yet.

这可能是一个骗局,但我已经搜索了一段时间以寻找正确的答案,但还没有找到。

So essentially all I want to do is join two tables and attach a where condition to the entire collection based on a field from the joined table.

所以基本上我想要做的就是连接两个表并根据连接表中的字段将 where 条件附加到整个集合。

So lets say I have two tables:

所以可以说我有两个表:

users:
   -id
   -name
   -email
   -password
   -etc

user_addresses:
   -address_line1
   -address_line2
   -town
   -city
   -etc

For the sake of argument (realising this may not be the best example) - lets assume a user can have multiple address entries. Now, laravel/eloquent gives us a nice way of wrapping up conditions on a collection in the form of scopes, so we'll use one of them to define the filter.

为了论证起见(意识到这可能不是最好的例子)——让我们假设一个用户可以有多个地址条目。现在,laravel/eloquent 为我们提供了一种以作用域形式包装集合条件的好方法,因此我们将使用其中一个来定义过滤器。

So, if I want to get all the users with an address in smallville, I may create a scope and relationships as follows:

因此,如果我想让所有用户在 smallville 中拥有一个地址,我可能会创建一个范围和关系,如下所示:

Users.php (model)

Users.php(模型)

class users extends Eloquent{
    public function addresses(){
        return $this->belongsToMany('Address');
    }

    public function scopeSmallvilleResidents($query){
        return $query->join('user_addresses', function($join) {
                    $join->on('user.id', '=', 'user_addresses.user_id');
                })->where('user_addresses.town', '=', 'Smallville');
    }
}

This works but its a bit ugly and it messes up my eloquent objects, since I no longer have a nice dynamic attribute containing users addresses, everything is just crammed into the user object.

这有效,但它有点难看,它弄乱了我雄辩的对象,因为我不再有一个很好的包含用户地址的动态属性,一切都被塞进了用户对象中。

I have tried various other things to get this to work, for example using a closure on the relationship looked promising:

我已经尝试了其他各种方法来让它发挥作用,例如对关系使用闭包看起来很有希望:

//this just filters at the point of attaching the relationship so will display all users but only pull in the address where it matches

//这只是在附加关系时进行过滤,因此将显示所有用户,但仅拉入匹配的地址

User::with(array('Addresses' => function($query){
                $query->where('town', '=', 'Smallville');
            }));

//This doesnt work at all

//这根本不起作用

User::with('Addresses')->where('user_addresses.town', '=', 'Smallville');

So is there an 'Eloquent' way of applying where clauses to relationships in a way that filters the main collection and keeps my eloquent objects in tact? Or have I like so many others been spoiled by the elegant syntax of Eloquent to the point where I'm asking too much?

那么,是否有一种“雄辩”的方式将 where 子句应用于关系,以过滤主集合并保持我雄辩的对象完整?或者我是否像许多其他人一样被 Eloquent 的优雅语法宠坏到我要求太多的地步?

Note: I am aware that you can usually get round this by defining relationships in the other direction (e.g. accessing the address table first) but this is not always ideal and not what i am asking.

注意:我知道您通常可以通过定义另一个方向的关系(例如首先访问地址表)来解决这个问题,但这并不总是理想的,也不是我要问的。

Thanks in advance for any help.

在此先感谢您的帮助。

采纳答案by Glad To Help

At this point, there is no means by which you can filter primary model based on a constraint in the related models. That means, you can't get only Userswho have user_address.town = 'Smallwille'in one swipe.

此时,您无法根据相关模型中的约束过滤主模型。这意味着,您不能只Users通过user_address.town = 'Smallwille'一次滑动就获得谁。

Personally I hope that this will get implemented soon because I can see a lot of people asking for it (including myself here).

我个人希望这能尽快实施,因为我可以看到很多人要求它(包括我自己)。

The current workaround is messy, but it works:

当前的解决方法很混乱,但它有效:

$products = array();
$categories  = Category::where('type', 'fruit')->get();
foreach($categories as $category)
{
 $products = array_merge($products, $category->products);
}
return $products;

回答by Elias Escalante

As stated in the question there is a way to filter the adresses first and then use eager loading to load the related users object. As so:

正如问题中所述,有一种方法可以先过滤地址,然后使用预先加载来加载相关的用户对象。如此:

$addressFilter = Addresses::with('Users')->where('town', $keyword)->first(); $users= $addressFilter->users;

$addressFilter = Addresses::with('Users')->where('town', $keyword)->first(); $users= $addressFilter->users;

of course bind with belongsTo in the model.

当然与模型中的belongsTo 绑定。

///*And in case anyone reading wants to also use pre-filtered Users data you can pass a closure to the 'with'

/// *如果有人阅读也想使用预过滤的用户数据,您可以将闭包传递给“with”

$usersFilter = Addresses::with(array('Users' => function($query) use ($keyword){ 
        $query->where('somefield', $keyword);
    }))->where('town', $keyword)->first();
$myUsers = $usersFilter->users;