Laravel regrouper une relation many to many

Par Ahmed Ibrahim, il y a 4 ans


J'ai 2 tables
-Users : id, nom
-Roles: id, nom

Ces deux tables ont une relation many to many avec la table pivot
-Role_user : role_id, user_id

Comment puis-je regrouper tous les utilisateurs par nom de rôle ?

J'ai essayé ceci

User::with('roles')->get()->groupBy('roles.name') ;

mais il semble que cela ne fonctionne que pour les relations de type "un à plusieurs".

14 réponses

Ahmed Ibrahim, il y a 4 ans

Salut t'es toujours là ?

Balsakup, il y a 4 ans

Salut, il faut que tu penses dans l'autre sens

// Récupère les rôles avec les utilisateurs associés $roles = Role::with(['users'])->get(); // Exemple qui affiche tous les utilisateurs de chaque rôle $roles->each(static fn(Role $role) => dump($role->users));
Ahmed Ibrahim, il y a 4 ans

Est-ce que ça pourait regrouper les utilisateurs comme ça :

Illuminate\Database\Eloquent\Collection {#290 ▼ #items: array:2 [▼ "ADMIN" => Illuminate\Database\Eloquent\Collection {#293 ▶} "USER" => Illuminate\Database\Eloquent\Collection {#291 ▶} ] #escapeWhenCastingToString: false }

ou dans la collection "ADMIN" j'ai tous les utilisateurs qui sont admin et dans "USER" les utilisateurs qui sont de simple utilisateur

Balsakup, il y a 4 ans

Oui, c'est possible en faisant

$roles = Role::with(['users'])->get()->pluck('users', 'name'); // A la place de `name`, mettre la colonne SQL qui contient le nom du rôle
Ahmed Ibrahim, il y a 4 ans

Ça marche mais cette maniere de faire ne va pas m'aider pour la suite car j'aurais besoin d'utiliser les relations qui appartienne au model user pour faire de requete dessus. Donc y'aurais pas un moyen de partir du sens de User ?

Ahmed Ibrahim, il y a 4 ans

Parce-que de base voila à quoi ressemble ma requete

User::with(['roles', 'attribution']) ->whereHas('attribution', function ($query) { $query->whereMonth('date_attribution', $this->month); }) ->get() ->groupBy('roles.name');

Est-il possible de faire ca dans le sens inverse ?

Balsakup, il y a 4 ans

J'ai pas testé, mais quelque chose du genre devrait sûrement fonctionner. Deplus, si tu es sur les dernières versions de Laravel, tu peux remplacer ton whereHas par un whereRelation comme j'ai mis dans l'exemple.

User::with(['roles', 'attribution']) ->whereRelation('attribution', 'data_attribution', $this->month) ->get() ->reduce(static function (Collection $agg, User $user) { $user->roles->each(static function (Role $role) use (&$agg, $user) { $agg[$role->name][] = $user; }); return $agg; }, collect());
Ahmed Ibrahim, il y a 4 ans

J'ai eu cette erreur

ErrorException Undefined array key "BM"
Ahmed Ibrahim, il y a 4 ans

J'ai remplace ce bout de code

$agg[$role->name][] = $user;

par ca

$agg[$role->name] = $user;

Et ca l'air de fonctionner sauf que pour chaque role il y'a qu'un seul utilisateur

Balsakup, il y a 4 ans
$agg = collect(); $agg->put($role->name, [...$agg->get($role->name, []), $user]);

A la place de

$agg[$role->name][] = $user
Ahmed Ibrahim, il y a 4 ans

Là ca fait que prendre le role associe au premier utilisateur c'etait mieux avec ca

$agg[$role->name] = $user
Ahmed Ibrahim, il y a 4 ans

J'ai testé avec ta methode
$roles = Role::with(['users.attribution'])->get()->pluck('users', 'name')
Et c'est bien ce que je veux mais y'a tous les roles qui sont listés alors que moi je voudrais seulement les roles qui appartiennent au moins à un utilisateurs. Comment porrais-je faire ça ? Merci d'avance

Ahmed Ibrahim, il y a 4 ans

Re j'ai trouvé la solution en faisant

User::with('roles')->get()->groupBy('roles.*.name');
Balsakup, il y a 4 ans

Salut,

Pour avoir que les rôles qui ont des utilisateurs, tu peux ajouter ->filter(static fn(Role $role) => $role->users->isNotEmpty() qui va garder que les rôles qui ont des utiisateurs liés

User::with(['roles', 'attribution']) ->whereRelation('attribution', 'data_attribution', $this->month) ->get() ->filter(static fn(Role $role) => $role->users->isNotEmpty()) // Filtre les rôles avec des utilisateurs ->reduce(static function (Collection $agg, User $user) { $user->roles->each(static function (Role $role) use (&$agg, $user) { $agg[$role->name][] = $user; }); return $agg; }, collect());