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
Auteur
Réponse acceptée

Re j'ai trouvé la solution en faisant

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

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

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

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

Ç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 ?

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 ?

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());

J'ai eu cette erreur

ErrorException
Undefined array key "BM"

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

$agg = collect();
$agg->put($role->name, [...$agg->get($role->name, []), $user]);

A la place de

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

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

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

Salut t'es toujours là ?

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

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());