getApplication(); $appId = $app->getId(); $roleEntity = $uoa->getRole(); if (!isset($grouped[$appId])) { $grouped[$appId] = [ 'uoId' => $uoa->getUserOrganization()->getId(), 'application' => $app, 'roles' => [], 'rolesArray' => [], 'selectedRoleIds' => [], ]; } $grouped[$appId]['roles'][] = [ 'id' => $roleEntity->getId(), 'name' => $roleEntity->getName(), ]; $grouped[$appId]['selectedRoleIds'][] = $roleEntity->getId(); } // Load all possible roles once $allRoles = $this->entityManager->getRepository(Roles::class)->findAll(); foreach ($grouped as &$appGroup) { foreach ($allRoles as $role) { // exclude SUPER ADMIN from assignable roles if current user is just ADMIN if ($this->security->isGranted('ROLE_ADMIN') && !$this->security->isGranted('ROLE_SUPER_ADMIN') && $role->getName() === 'SUPER ADMIN') { continue; } $appGroup['rolesArray'][] = [ 'id' => $role->getId(), 'name' => $role->getName(), ]; } } return array_values($grouped); } /** * Deactivates all the UserOrganizationApp entities for a given UserOrganization. * * @param UsersOrganizations $userOrganization * @return void */ public function deactivateAllUserOrganizationsAppLinks(UsersOrganizations $userOrganization, Apps $app = null): void { if($app) { $uoas = $this->entityManager->getRepository(UserOrganizatonApp::class)->findBy(['userOrganization' => $userOrganization, 'application' => $app, 'isActive' => true]); } else { $uoas = $this->entityManager->getRepository(UserOrganizatonApp::class)->findBy(['userOrganization' => $userOrganization, 'isActive' => true]); } foreach ($uoas as $uoa) { $uoa->setIsActive(false); $this->actionService->createAction("Deactivate UOA link", $userOrganization->getUsers(), $userOrganization->getOrganization(), "App: " . $uoa->getApplication()->getName() . ", Role: " . $uoa->getRole()->getName()); $this->entityManager->persist($uoa); } } /** * Synchronizes user roles for a specific application within an organization. * * This method handles the complete lifecycle of user-application role assignments: * - Activates/deactivates existing role links based on selection * - Creates new role assignments for newly selected roles * - Updates the user's global Symfony security roles when ADMIN/SUPER_ADMIN roles are assigned * * @param UsersOrganizations $uo The user-organization relationship * @param Apps $application The target application * @param array $selectedRoleIds Array of role IDs that should be active for this user-app combination * @param User $actingUser The user performing this action (for audit logging) * * @return void * * @throws \Exception If role entities cannot be found or persisted */ public function syncRolesForUserOrganizationApp( UsersOrganizations $uo, Apps $application, array $selectedRoleIds, User $actingUser ): void { // Fetch existing UserOrganizationApp links for this user and application $uoas = $this->entityManager->getRepository(UserOrganizatonApp::class)->findBy([ 'userOrganization' => $uo, 'application' => $application, ]); $currentRoleIds = []; // Process existing role links - activate or deactivate based on selection foreach ($uoas as $uoa) { $roleId = $uoa->getRole()->getId(); $currentRoleIds[] = $roleId; $roleName = $uoa->getRole()->getName(); if (in_array((string) $roleId, $selectedRoleIds, true)) { // Role is selected - ensure it's active if (!$uoa->isActive()) { $uoa->setIsActive(true); $this->entityManager->persist($uoa); $this->actionService->createAction( "Re-activate user role for application", $actingUser, $uo->getOrganization(), "App: {$application->getName()}, Role: $roleName for user {$uo->getUsers()->getUserIdentifier()}" ); // Sync Admins roles to user's global Symfony security roles if (in_array($roleName, ['ADMIN', 'SUPER ADMIN'], true)) { $this->userService->syncUserRoles($uo->getUsers(), $roleName, true); } // Ensure ADMIN role is assigned if SUPER ADMIN is activated if ($roleName === 'SUPER ADMIN') { $this->ensureAdminRoleForSuperAdmin($uoa); } } } else { // Role is not selected - ensure it's inactive if ($uoa->isActive()) { $uoa->setIsActive(false); $this->entityManager->persist($uoa); $this->actionService->createAction( "Deactivate user role for application", $actingUser, $uo->getOrganization(), "App: {$application->getName()}, Role: $roleName for user {$uo->getUsers()->getUserIdentifier()}" ); // Sync Admins roles to user's global Symfony security roles if (in_array($roleName, ['ADMIN', 'SUPER ADMIN'], true)) { $this->userService->syncUserRoles($uo->getUsers(), $roleName, false); } } } } // Create new role assignments for roles that don't exist yet foreach ($selectedRoleIds as $roleId) { if (!in_array($roleId, $currentRoleIds)) { $role = $this->entityManager->getRepository(Roles::class)->find($roleId); if ($role) { // Create new user-organization-application role link $newUoa = new UserOrganizatonApp(); $newUoa->setUserOrganization($uo); $newUoa->setApplication($application); $newUoa->setRole($role); $newUoa->setIsActive(true); // Sync Admins roles to user's global Symfony security roles if (in_array($role->getName(), ['ADMIN', 'SUPER ADMIN'], true)) { $this->userService->syncUserRoles($uo->getUsers(), $role->getName(), true); } // Ensure ADMIN role is assigned if SUPER ADMIN is activated if ($role->getName() === 'SUPER ADMIN') { $this->ensureAdminRoleForSuperAdmin($newUoa); } $this->entityManager->persist($newUoa); $this->actionService->createAction("New user role for application", $actingUser, $uo->getOrganization(), "App: {$application->getName()}, Role: {$role->getName()} for user {$uo->getUsers()->getUserIdentifier()}"); } } } $this->entityManager->flush(); } /** * Attribute the role Admin to the user if the user has the role Super Admin * * @param UserOrganizatonApp $uoa * * @return void */ public function ensureAdminRoleForSuperAdmin(UserOrganizatonApp $uoa): void { $uoaAdmin = $this->entityManager->getRepository(UserOrganizatonApp::class)->findOneBy([ 'userOrganization' => $uoa->getUserOrganization(), 'application' => $uoa->getApplication(), 'role' => $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']) ]); if(!$uoaAdmin) { $uoaAdmin = new UserOrganizatonApp(); $uoaAdmin->setUserOrganization($uoa->getUserOrganization()); $uoaAdmin->setApplication($uoa->getApplication()); $uoaAdmin->setRole($this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN'])); $uoaAdmin->setIsActive(true); $this->entityManager->persist($uoaAdmin); } // If the ADMIN role link exists but is inactive, activate it if ($uoaAdmin && !$uoaAdmin->isActive()) { $uoaAdmin->setIsActive(true); } } }