web-dev-qa-db-fra.com

Où PAS dans le tableau croisé dynamique

Dans Laravel, nous pouvons configurer des relations comme suit:

class User {
    public function items()
    {
        return $this->belongsToMany('Item');
    }
}

Nous permettant d'obtenir tous les éléments d'un tableau croisé dynamique pour un utilisateur:

Auth::user()->items();

Cependant, si je veux obtenir le contraire de cela. Et obtenez tous les éléments que l’utilisateur NE A PAS encore. Donc, pas dans le tableau croisé dynamique.

Y a-t-il un moyen simple de faire cela?

26
Rob

Pour plus de simplicité et de symétrie, vous pouvez créer une nouvelle méthode dans le modèle User:

// User model
public function availableItems()
{
    $ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
    return \Item::whereNotIn('id', $ids)->get();
}

Pour utiliser call:

Auth::user()->availableItems();
13
Makita

En regardant le code source de la classe Illuminate\Database\Eloquent\Builder, nous avons deux méthodes dans Laravel qui fait ceci: whereDoesntHave (contraire de whereHas) et doesntHave (contraire de has)

// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1)  AND ...

    User::whereDoesntHave('Role', function ($query) use($id) {
          $query->whereId($id);
    })
    ->get();

cela fonctionne correctement pour moi!

Pour une relation simple "Où n'existe pas existe", utilisez ceci:

User::doesntHave('Role')->get();

Désolé, je ne comprends pas l'anglais. J'ai utilisé le traducteur google.

41
Wallace Maxters

Ce n'est pas si simple, mais le moyen le plus efficace consiste généralement à utiliser une sous-requête.

$items = Item::whereNotIn('id', function ($query) use ($user_id)
    {
        $query->select('item_id')
            ->table('item_user')
            ->where('user_id', '=', $user_id);
    })
    ->get();

Si c'était quelque chose que je faisais souvent, je l'ajouterais comme méthode d'étendue au modèle Item.

class Item extends Eloquent {

    public function scopeWhereNotRelatedToUser($query, $user_id)
    {
        $query->whereNotIn('id', function ($query) use ($user_id)
        {
            $query->select('item_id')
                ->table('item_user')
                ->where('user_id', '=', $user_id);
        });
    }

}

Puis utilisez ça plus tard comme ça.

$items = Item::whereNotRelatedToUser($user_id)->get();
6
Collin James

Que diriez-vous de gauche rejoindre?

En supposant que les tables sont users, items et item_user rechercher toutes les items non associées à l'utilisateur 123:

DB::table('items')->leftJoin(
    'item_user', function ($join) {
        $join->on('items.id', '=', 'item_user.item_id')
             ->where('item_user.user_id', '=', 123);
    })
    ->whereNull('item_user.item_id')
    ->get();
1
mp31415

A fini par écrire une portée pour ceci comme ceci:

public function scopeAvail($query)
{
    return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}

Et puis appelez:

Items::avail()->get();

Fonctionne pour le moment, mais un peu brouillon. Aimeriez-vous voir quelque chose avec un mot clé comme not:

Auth::user()->itemsNot();

De manière générale, Eloquent exécute quand même la requête ci-dessus, sauf avec un = au lieu d'un <>.

0
Rob

Peut-être que vous pouvez utiliser:

DB::table('users')
        ->whereExists(function($query)
        {
            $query->select(DB::raw(1))
                  ->from('orders')
                  ->whereRaw('orders.user_id = users.id');
        })
        ->get();

Source: http://laravel.com/docs/4.2/queries#advanced-wheres

0
Turcko007

cela devrait fonctionner pour vous

$someuser = Auth::user();     

$someusers_items = $someuser->related()->lists('item_id');

$all_items = Item::all()->lists('id');

$someuser_doesnt_have_items = array_diff($all_items, $someusers_items); 
0
Gadoma