*/ public function getUserOrganizations(User $user, int $organizationsId = null): array { $userOrganizations = $this->entityManager ->getRepository(UsersOrganizations::class) ->findAllDistinctOrganizationsByUserId($user->getId()); $organizations = []; foreach ($userOrganizations as $uo) { $orgId = $uo->getOrganization()->getId(); // Si $organizationsId est fourni, ignorer les autres organisations if ($organizationsId !== null && $orgId !== $organizationsId) { continue; } // Initialiser l'entrée de l'organisation si elle n'existe pas $organizations[$orgId] = $organizations[$orgId] ?? $this->createEmptyOrganizationBucket($uo); $organizations[$orgId]['uoId'] = $uo->getId(); // Agréger les rôles et applications $this->addRole($organizations[$orgId]['roles'], $uo->getRole()); $this->addApps($organizations[$orgId]['apps'], $uo->getApps()); } // Ordonner les rôles : Super Admin, Admin, puis les autres foreach ($organizations as &$org) { $org['roles'] = $this->sortRoles($org['roles']); } unset($org); $this->normalizeAppsIndexes($organizations); return array_values($organizations); } /** * Trie les rôles pour que Super Admin et Admin soient en premier, puis les autres. * * @param Roles[] $roles * @return Roles[] */ private function sortRoles(array $roles): array { usort($roles, function ($a, $b) { $priority = [ 'SUPER_ADMIN' => 0, 'ADMIN' => 1 ]; $aName = strtoupper($a->getName()); $bName = strtoupper($b->getName()); $aPriority = $priority[$aName] ?? 2; $bPriority = $priority[$bName] ?? 2; if ($aPriority === $bPriority) { return strcmp($aName, $bName); } return $aPriority <=> $bPriority; }); return $roles; } /** * Initialise la structure de données pour une organisation. * * @param UsersOrganizations $link Lien utilisateur-organisation * @return array{organization:object, roles:Roles[], apps:array} */ private function createEmptyOrganizationBucket(UsersOrganizations $link): array { return [ 'organization' => $link->getOrganization(), 'roles' => [], 'apps' => [], ]; } /** * Ajoute un rôle à la liste si non déjà présent (par ID). * * @param Roles[] &$roles Liste des rôles * @param Roles|null $role Rôle à ajouter * @return void */ private function addRole(array &$roles, ?Roles $role): void { if ($role === null) { return; } foreach ($roles as $existingRole) { if ($existingRole->getId() === $role->getId()) { return; // Already present } } $roles[] = $role; } /** * Fusionne une ou plusieurs applications dans le tableau associatif, une entrée par ID. * * @param array &$apps Tableau des applications * @param iterable $appsToAdd Applications à ajouter * @return void */ private function addApps(array &$apps, iterable $appsToAdd): void { foreach ($appsToAdd as $app) { $apps[$app->getId()] = $apps[$app->getId()] ?? $app; } } /** * Normalise le tableau des applications pour le rendre indexé (JSON-friendly). * * @param array &$organizations Tableau des organisations * @return void */ private function normalizeAppsIndexes(array &$organizations): void { foreach ($organizations as &$org) { $org['apps'] = array_values($org['apps']); } } /** * Définit les rôles d'un utilisateur dans une organisation, en s'assurant que le rôle USER est toujours présent. * Désactive tous les rôles si USER n'est pas sélectionné. * * @param User $user L'utilisateur * @param Organizations $organization L'organisation * @param array $selectedRoles Tableau des IDs de rôles sélectionnés * @return void * @throws \RuntimeException Si le rôle USER n'est pas trouvé */ public function setUserOrganizations(User $user, Organizations $organization, array $selectedRoles): void { $repo = $this->entityManager->getRepository(UsersOrganizations::class); $roleRepo = $this->entityManager->getRepository(Roles::class); $userRole = $roleRepo->findOneBy(['name' => 'USER']); if (!$userRole) { throw new \RuntimeException('USER role not found'); } if (!in_array($userRole->getId(), $selectedRoles)) { $this->deactivateAllUserRoles($user, $organization); return; } $currentUserOrgs = $repo->findBy([ 'users' => $user, 'organization' => $organization ]); $currentRolesMap = $this->mapUserOrgRoles($currentUserOrgs); $selectedRoles = $this->ensureUserRolePresent($selectedRoles, $userRole->getId()); $this->addOrUpdateRoles($selectedRoles, $currentRolesMap, $roleRepo, $user, $organization); $this->deactivateUnselectedRoles($currentRolesMap); $this->entityManager->flush(); } /** * Met à jour les applications associées à l'utilisateur dans une organisation. * * @param User $user L'utilisateur * @param Organizations $organization L'organisation * @param array $selectedApps Tableau des IDs d'applications sélectionnées * @return void */ public function setUserOrganizationsApps(User $user, Organizations $organization, array $selectedApps): void { $roleUser = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'USER']); $uoEntity = $this->entityManager ->getRepository(UsersOrganizations::class) ->findOneBy(['users' => $user, 'organization' => $organization, 'role' => $roleUser]); if (!$uoEntity) { return; } $this->removeUnselectedApps($uoEntity, $selectedApps); $this->addSelectedApps($uoEntity, $selectedApps); $this->entityManager->persist($uoEntity); $this->entityManager->flush(); } /** * Crée une map des rôles actuels de l'utilisateur dans l'organisation. * @param array $currentUserOrgs * @return array */ private function mapUserOrgRoles(array $currentUserOrgs): array { $map = []; foreach ($currentUserOrgs as $uo) { $map[$uo->getRole()->getId()] = $uo; } return $map; } /** * S'assure que le rôle USER est présent dans la sélection si nécessaire. * @param array $selectedRoles * @param int $userRoleId * @return array */ private function ensureUserRolePresent(array $selectedRoles, int $userRoleId): array { $hasNonUserRole = false; foreach ($selectedRoles as $roleId) { if ($roleId !== $userRoleId) { $hasNonUserRole = true; break; } } if ($hasNonUserRole && !in_array($userRoleId, $selectedRoles)) { $selectedRoles[] = $userRoleId; } return $selectedRoles; } /** * Ajoute ou réactive les rôles sélectionnés pour l'utilisateur dans l'organisation. * @param array $selectedRoles * @param array $currentRolesMap * @param $roleRepo * @param User $user * @param Organizations $organization */ private function addOrUpdateRoles(array $selectedRoles, array &$currentRolesMap, $roleRepo, User $user, Organizations $organization): void { foreach ($selectedRoles as $roleId) { if (!isset($currentRolesMap[$roleId])) { $roleEntity = $roleRepo->find($roleId); if ($roleEntity) { $newUserOrganization = new UsersOrganizations(); $newUserOrganization->setUsers($user); $newUserOrganization->setRole($roleEntity); $newUserOrganization->setOrganization($organization); $newUserOrganization->setIsActive(true); $this->entityManager->persist($newUserOrganization); } } else { $currentRolesMap[$roleId]->setIsActive(true); $this->entityManager->persist($currentRolesMap[$roleId]); } unset($currentRolesMap[$roleId]); } } /** * Désactive les rôles non sélectionnés pour l'utilisateur dans l'organisation. * @param array $currentRolesMap */ private function deactivateUnselectedRoles(array $currentRolesMap): void { foreach ($currentRolesMap as $uo) { $uo->setIsActive(false); $this->entityManager->persist($uo); } } /** * Retire les applications non sélectionnées de l'utilisateur dans l'organisation. * @param UsersOrganizations $uoEntity * @param array $selectedApps */ private function removeUnselectedApps(UsersOrganizations $uoEntity, array $selectedApps): void { foreach ($uoEntity->getApps()->toArray() as $existingApp) { if (!in_array($existingApp->getId(), $selectedApps)) { $uoEntity->removeApp($existingApp); } } } /** * Ajoute les applications sélectionnées à l'utilisateur dans l'organisation. * @param UsersOrganizations $uoEntity * @param array $selectedApps */ private function addSelectedApps(UsersOrganizations $uoEntity, array $selectedApps): void { foreach ($selectedApps as $appId) { $appEntity = $this->entityManager->getRepository(Apps::class)->find($appId); if ($appEntity && !$uoEntity->getApps()->contains($appEntity)) { $uoEntity->addApp($appEntity); } } } /** * Désactive tous les rôles d'un utilisateur dans une organisation. * * @param User $user L'utilisateur * @param Organizations $organization L'organisation * @return void */ public function deactivateAllUserRoles(User $user, Organizations $organization): void { $repo = $this->entityManager->getRepository(UsersOrganizations::class); $userOrganizations = $repo->findBy([ 'users' => $user, 'organization' => $organization ]); foreach ($userOrganizations as $uo) { $uo->setIsActive(false); //Log action $action = new Actions(); $action->setActionType("Désactivation role" ); $action->setDescription("Désactivation du rôle " . $uo->getRole()->getName() . " pour l'utilisateur " . $user->getUserIdentifier() . " dans l'organisation " . $organization->getName()); $action->setOrganization($organization); $action->setUsers($user); $this->entityManager->persist($uo); } $this->entityManager->flush(); } /** * Get all active users grouped by organization. * Users with no organization are grouped under 'autre'. * * @return array */ public function getActiveUsersGroupedByOrganization(): array { $users = $this->entityManager->getRepository(User::class)->getAllActiveUsers(); $userOrgs = $this->entityManager->getRepository(UsersOrganizations::class)->getAllActiveUserOrganizationLinks(); $userToOrgs = $this->mapUserToOrganizations($userOrgs); $orgs = []; foreach ($users as $user) { $userId = $user['id']; if (isset($userToOrgs[$userId])) { foreach ($userToOrgs[$userId] as $orgInfo) { $orgId = $orgInfo['organization_id']; if (!isset($orgs[$orgId])) { $orgs[$orgId] = [ 'organization_id' => $orgId, 'organization_name' => $orgInfo['organization_name'], 'users' => [], ]; } // $orgs[$orgId]['users'][$userId] = $user; $orgs[$orgId]['users'][$userId] = [ 'users' => $user, 'is_connected' => $this->userService->isUserConnected($user['email']) ]; } } else { if (!isset($orgs['autre'])) { $orgs['autre'] = [ 'organization_id' => null, 'organization_name' => 'autre', 'users' => [], ]; } $orgs['autre']['users'][$userId] = [ 'users' => $user, 'is_connected' => $this->userService->isUserConnected($user['email']) ]; } } // Convert users arrays to indexed arrays foreach ($orgs as &$org) { $org['users'] = array_values($org['users']); } return array_values($orgs); } /** * Get all active users for each organization in the given array. * * @param Organizations[] $organizations * @return array */ public function findActiveUsersByOrganizations(array $organizations): array { if (empty($organizations)) { return []; } $userOrgs = $this->entityManager->getRepository(UsersOrganizations::class)->getAllActiveUserOrganizationLinks($organizations); $usersByOrg = []; foreach ($userOrgs as $uo) { $org = $uo->getOrganization(); $orgId = $org->getId(); if (!isset($usersByOrg[$orgId])) { $usersByOrg[$orgId] = [ 'organization_id' => $orgId, 'organization_name' => $org->getName(), 'users' => [], ]; } $user = $uo->getUsers(); $userId = $user->getId(); // Add connection status to user data $usersByOrg[$orgId]['users'][$userId] = [ 'users' => $user, 'is_connected' => $this->userService->isUserConnected($user->getUserIdentifier()) ]; } // Convert users arrays to indexed arrays foreach ($usersByOrg as &$org) { $org['users'] = array_values($org['users']); } return array_values($usersByOrg); } /** * Helper: Map userId to their organizations (id and name), avoiding duplicates. * * @param UsersOrganizations[] $userOrgs * @return array */ private function mapUserToOrganizations(array $userOrgs): array { $userToOrgs = []; foreach ($userOrgs as $uo) { $userId = $uo->getUsers()->getId(); $org = $uo->getOrganization(); $orgId = $org->getId(); $orgName = $org->getName(); $userToOrgs[$userId][$orgId] = [ 'organization_id' => $orgId, 'organization_name' => $orgName, ]; } return $userToOrgs; } }