php - started - Comprueba si pertenece la relación de ManyToany-Laravel
laravel software (7)
Creo que la forma oficial de hacer esto es hacer:
$client = Client::find(1);
$exists = $client->products->contains($product_id);
Es algo inútil ya que hará la consulta SELECT
, obtendrá todos los resultados en una Collection
y finalmente hará un foreach
sobre la Collection
para encontrar un modelo con la ID que ingresa. Sin embargo, no requiere modelar la tabla dinámica .
Si no le gusta el desperdicio de eso, puede hacerlo usted mismo en SQL / Query Builder, que tampoco requeriría modelar la tabla (ni requeriría obtener el modelo de Client
si no lo tiene ya para otro propósitos:
$exists = DB::table(''client_product'')
->whereClientId($client_id)
->whereProductId($product_id)
->count() > 0;
Dos de mis tablas (clientes y productos) tienen una relación ManyToMany usando BlongToMany de Laravel y una tabla dinámica. Ahora quiero verificar si un determinado cliente tiene un determinado producto.
Podría crear un modelo para verificar en la tabla dinámica, pero dado que Laravel no requiere este modelo para el método belongsToMany, me preguntaba si existe otra forma de verificar si existe una determinada relación sin tener un modelo para la tabla dinámica.
Hola a todos) Mi solución para este problema: creé una clase propia, ampliada desde Eloquent, y extiendo todos mis modelos desde ella. En esta clase, escribí esta sencilla función:
function have($relation_name, $id) {
return (bool) $this->$relation_name()->where(''id'',''='',$id)->count();
}
Para verificar una relación existente, debe escribir algo como:
if ($user->have(''subscribes'', 15)) {
// do some things
}
De esta manera, solo se genera una consulta de conteo SELECT (...) sin recibir datos reales de las tablas.
La pregunta es bastante antigua, pero esto puede ayudar a otros a buscar una solución:
$client = Client::find(1);
$exists = $client->products()->where(''products.id'', $productId)->exists();
No hay "desperdicio" como en la solución de @ alexrussell y la consulta es más eficiente también.
La solución de Alex funciona, pero cargará en la memoria un modelo de Client
y todos los modelos de Product
relacionados, y solo después de eso, comprobará si existe la relación.
Una mejor manera Eloquente de hacer eso es usar el método whereHas()
.
1. No necesita cargar el modelo del cliente, solo puede usar su ID.
2. Tampoco necesita cargar todos los productos relacionados con ese cliente en la memoria, como Alex.
3. Una consulta SQL a DB.
$doesClientHaveProduct = Product::where(''id'', $productId)
->whereHas(''clients'', function($q) use($clientId) {
$q->where(''id'', $clientId);
})
->count();
Los métodos de @nielsiano funcionarán, pero consultarán DB por cada par de usuario / producto, lo cual es una pérdida en mi opinión.
Si no desea cargar todos los datos de los modelos relacionados, esto es lo que haría por un solo usuario :
// 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);
}
Entonces puedes simplemente hacer esto:
$user = User::first();
$user->hasProduct($someId); // true / false
// or
Auth::user()->hasProduct($someId);
Solo se ejecuta 1 consulta, luego trabajas con la matriz.
La forma más fácil sería usar contains
como @alexrussell sugerido.
Creo que esto es una cuestión de preferencia, por lo tanto, a menos que su aplicación sea bastante grande y requiera mucha optimización, puede elegir con qué le resulta más fácil trabajar.
usar rasgo:
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...
}
Actualización: no tomé en cuenta la utilidad de verificar relaciones múltiples, si ese es el caso, entonces @deczo tiene una respuesta mucho mejor a esta pregunta. Ejecutar solo una consulta para verificar todas las relaciones es la solución deseada.
/**
* 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()
);
}
Podría poner esto en su modelo de Usuario / Cliente o podría tenerlo en un repositorio de clientes y usarlo donde lo necesite.
if ($this->clientRepository->clientHasProduct($clientId, $productId)
{
return ''Awesome'';
}
Pero si ya ha definido la relación belongsToMany en un modelo Client Eloquent, puede hacer esto, dentro de su modelo de Cliente, en su lugar:
return ! is_null(
$this->products()
->where(''product_id'', $productId)
->first()
);