php 检查belongsToMany 关系是否存在 - Laravel
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24555697/
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
Check if belongsToMany relation exists - Laravel
提问by almo
Two of my tables (clients and products) have a ManyToMany relation using Laravel's blongToMany and a pivot table. Now I want to check if a certain client has a certain product.
我的两个表(客户和产品)使用 Laravel 的 blongToMany 和数据透视表具有多对多关系。现在我想检查某个客户是否有某个产品。
I could create a model to check in the pivot table but since Laravel does not require this model for the belongsToMany method I was wondering if there is another way to check if a certain relationship exists without having a model for the pivot table.
我可以创建一个模型来检查数据透视表,但是由于 Laravel 不需要这个模型用于belongsToMany 方法,我想知道是否有另一种方法可以在没有数据透视表模型的情况下检查某种关系是否存在。
回答by alexrussell
I think the official way to do this is to do:
我认为这样做的官方方法是:
$client = Client::find(1);
$exists = $client->products->contains($product_id);
It's somewhat wasteful in that it'll do the SELECT
query, get all results into a Collection
and then finally do a foreach
over the Collection
to find a model with the ID you pass in. However, it doesn't require modelling the pivot table.
这是因为它会做的有点浪费SELECT
查询,得到的所有结果为Collection
,最后做一个foreach
在Collection
寻找与您传递ID的模式。然而,它并不需要建模数据透视表。
If you don't like the wastefulness of that, you could do it yourself in SQL/Query Builder, which also wouldn't require modelling the table (nor would it require getting the Client
model if you don't already have it for other purposes:
如果您不喜欢这种浪费,您可以在 SQL/Query Builder 中自己完成,这也不需要对表进行建模(Client
如果您还没有将模型用于其他目的,也不需要获取模型:
$exists = DB::table('client_product')
->whereClientId($client_id)
->whereProductId($product_id)
->count() > 0;
回答by Mouagip
The question is quite old but this may help others looking for a solution:
这个问题很老了,但这可能会帮助其他人寻找解决方案:
$client = Client::find(1);
$exists = $client->products()->where('products.id', $productId)->exists();
No "wastefulness" as in @alexrussell's solution and the query is more efficient, too.
没有@alexrussell 的解决方案中的“浪费”,查询也更有效。
回答by Alexey Mezenin
Alex's solution is working one, but it will load a Client
model and all related Product
models from DB into memory and only after that, it will check if the relationship exists.
Alex 的解决方案是有效的,但它会将Client
模型和所有相关Product
模型从 DB加载到内存中,只有在此之后,它才会检查关系是否存在。
A better Eloquent way to do that is to use whereHas()
method.
一个更好的 Eloquent 方法是使用whereHas()
方法。
1.You don't need to load client model, you can just use his ID.
1.不需要加载客户端模型,直接使用他的ID即可。
2.You also don't need to load all products related to that client into memory, like Alex does.
2.您也不需要像 Alex 那样将与该客户端相关的所有产品加载到内存中。
3.One SQL query to DB.
3.对 DB 的一个 SQL 查询。
$doesClientHaveProduct = Product::where('id', $productId)
->whereHas('clients', function($q) use($clientId) {
$q->where('id', $clientId);
})
->count();
回答by nielsiano
Update:I did not take into account the usefulness of checking multiple relations, if that is the case then @deczo has a way better answer to this question. Running only one query to check for all relations is the desired solution.
更新:我没有考虑检查多个关系的用处,如果是这种情况,那么@deczo 对这个问题有更好的答案。只运行一个查询来检查所有关系是理想的解决方案。
/**
* Determine if a Client has a specific Product
* @param $clientId
* @param $productId
* @return bool
*/
public function clientHasProduct($clientId, $productId)
{
return ! is_null(
DB::table('client_product')
->where('client_id', $clientId)
->where('product_id', $productId)
->first()
);
}
You could put this in you User/Client model or you could have it in a ClientRepository and use that wherever you need it.
你可以把它放在你的 User/Client 模型中,或者你可以把它放在 ClientRepository 中,并在任何需要的地方使用它。
if ($this->clientRepository->clientHasProduct($clientId, $productId)
{
return 'Awesome';
}
But if you already have defined the belongsToMany relationship on a Client Eloquent model, you could do this, inside your Client model, instead:
但是如果你已经在 Client Eloquent 模型上定义了belongsToMany 关系,你可以在你的 Client 模型中这样做:
return ! is_null(
$this->products()
->where('product_id', $productId)
->first()
);
回答by Jarek Tkaczyk
@nielsiano's methods will work, but they will query DB for every user/product pair, which is a waste in my opinion.
@nielsiano 的方法会起作用,但它们会为每个用户/产品对查询数据库,这在我看来是一种浪费。
If you don't want to load all the related models' data, then this is what I would do for a single user:
如果您不想加载所有相关模型的数据,那么这就是我对单个用户所做的:
// User model
protected $productIds = null;
public function getProductsIdsAttribute()
{
if (is_null($this->productsIds) $this->loadProductsIds();
return $this->productsIds;
}
public function loadProductsIds()
{
$this->productsIds = DB::table($this->products()->getTable())
->where($this->products()->getForeignKey(), $this->getKey())
->lists($this->products()->getOtherKey());
return $this;
}
public function hasProduct($id)
{
return in_array($id, $this->productsIds);
}
Then you can simply do this:
然后你可以简单地这样做:
$user = User::first();
$user->hasProduct($someId); // true / false
// or
Auth::user()->hasProduct($someId);
Only 1 query is executed, then you work with the array.
只执行 1 个查询,然后您使用该数组。
The easiest way would be using contains
like @alexrussell suggested.
最简单的方法是contains
像@alexrussell 建议的那样使用。
I think this is a matter of preference, so unless your app is quite big and requires a lot of optimization, you can choose what you find easier to work with.
我认为这是一个偏好问题,因此除非您的应用程序很大并且需要大量优化,否则您可以选择更容易使用的应用程序。
回答by saggid
Hello all) My solution for this problem: i created a own class, extended from Eloquent, and extend all my models from it. In this class i written this simple function:
大家好)我对这个问题的解决方案:我创建了一个自己的类,从 Eloquent 扩展,并从中扩展我的所有模型。在这门课中,我编写了这个简单的函数:
function have($relation_name, $id) {
return (bool) $this->$relation_name()->where('id','=',$id)->count();
}
For make a check existing relation you must write something like:
要检查现有关系,您必须编写如下内容:
if ($user->have('subscribes', 15)) {
// do some things
}
This way generates only a SELECT count(...)query without receiving real data from tables.
这种方式只生成一个SELECT count(...)查询,而不会从表中接收真实数据。
回答by ilvsx
use trait:
使用特性:
trait hasPivotTrait
{
public function hasPivot($relation, $model)
{
return (bool) $this->{$relation}()->wherePivot($model->getForeignKey(), $model->{$model->getKeyName()})->count();
}
}
.
.
if ($user->hasPivot('tags', $tag)){
// do some things...
}
回答by Maksim Ivanov
To check the existence of a relationship between 2 models, all we need is a single query against the pivot table without any joins.
要检查 2 个模型之间是否存在关系,我们只需要对数据透视表进行一次查询,无需任何连接。
You can achieve it using the built-in newPivotStatementForId
method:
您可以使用内置newPivotStatementForId
方法实现它:
$exists = $client->products()->newPivotStatementForId($product->id)->exists();
回答by daniel tamayo
This has time but maybe I can help someone
这有时间,但也许我可以帮助某人
if($client->products()->find($product->id)){ exists!! }
if($client->products()->find($product->id)){ 存在!!}
It should be noted that you must have the product and customer model, I hope it helps,
需要注意的是,你必须有产品和客户模型,希望对你有帮助,