Проверьте, существует ли отношение toToMany – Laravel

Две из моих таблиц (клиенты и продукты) имеют отношение ManyToMany с использованием blongToMany от Laravel и сводной таблицы. Теперь я хочу проверить, есть ли у определенного клиента определенный продукт.

Я мог бы создать модель для проверки сводной таблицы, но поскольку Laravel не требует этой модели для метода belongsToMany, мне было интересно, есть ли другой способ проверить, существует ли определенная связь без модели для сводной таблицы.

Я думаю, что официальный способ сделать это – сделать:

$client = Client::find(1); $exists = $client->products->contains($product_id); 

Это несколько расточительно в том, что он выполнит запрос SELECT , получит все результаты в Collection и затем, наконец, сделает foreach над Collection чтобы найти модель с идентификатором, который вы проходите. Однако для этого не требуется моделирование сводной таблицы ,

Если вам не нравится расточительность этого, вы можете сделать это самостоятельно в SQL / Query Builder, что также не потребует моделирования таблицы (и не потребовалось бы получить модель Client если у вас ее еще нет цели:

 $exists = DB::table('client_product') ->whereClientId($client_id) ->whereProductId($product_id) ->count() > 0; 

Методы @ nielsiano будут работать, но они будут запрашивать DB для каждой пары пользователь / продукт, что, на мой взгляд, является отходами.

Если вы не хотите загружать все данные связанных моделей, то это то, что я сделал бы для одного пользователя :

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

Тогда вы можете просто сделать это:

 $user = User::first(); $user->hasProduct($someId); // true / false // or Auth::user()->hasProduct($someId); 

Выполняется только 1 запрос, затем вы работаете с массивом.


Самый простой способ – использовать, например, @alexrussell.

Я думаю, что это вопрос предпочтения, поэтому, если ваше приложение довольно велико и требует большой оптимизации, вы можете выбрать, с чем вам легче работать.

Обновление: я не принимал во внимание полезность проверки нескольких отношений, если это так, то @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() ); } 

Вы можете поместить это в свою модель User / Client, или вы можете получить ее в ClientRepository и использовать ее там, где вам это нужно.

 if ($this->clientRepository->clientHasProduct($clientId, $productId) { return 'Awesome'; } 

Но если вы уже определили отношения belongsToMany на модели Client Eloquent, вы можете сделать это, в своей модели клиента, вместо этого:

  return ! is_null( $this->products() ->where('product_id', $productId) ->first() ); 

Привет всем) Мое решение для этой проблемы: я создал собственный класс, расширенный от Eloquent, и расширил все мои модели от него. В этом классе я написал эту простую функцию:

 function have($relation_name, $id) { return (bool) $this->$relation_name()->where('id','=',$id)->count(); } 

Для проверки существующего отношения вы должны написать что-то вроде:

 if ($user->have('subscribes', 15)) { // do some things } 

Этот способ генерирует только запрос SELECT count (…) без получения реальных данных из таблиц.

Вопрос довольно старый, но это может помочь другим найти решение:

 $client = Client::find(1); $exists = $client->products()->where('products.id', $productId)->exists(); 

Нет «расточительности», как в решении @ alexrussell, и запрос более эффективен.

использование признака:

 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... }