refonte role

This commit is contained in:
Charles 2025-08-12 10:01:00 +02:00
parent 716bfb8ce1
commit 9dc79eaa7d
10 changed files with 466 additions and 186 deletions

View File

@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250808085504 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE user_organizaton_app (id SERIAL NOT NULL, users_id INT NOT NULL, organization_id INT DEFAULT NULL, role_id INT DEFAULT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, is_active BOOLEAN NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_2C952FC767B3B43D ON user_organizaton_app (users_id)');
$this->addSql('CREATE INDEX IDX_2C952FC732C8A3DE ON user_organizaton_app (organization_id)');
$this->addSql('CREATE INDEX IDX_2C952FC7D60322AC ON user_organizaton_app (role_id)');
$this->addSql('COMMENT ON COLUMN user_organizaton_app.created_at IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('ALTER TABLE user_organizaton_app ADD CONSTRAINT FK_2C952FC767B3B43D FOREIGN KEY (users_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE user_organizaton_app ADD CONSTRAINT FK_2C952FC732C8A3DE FOREIGN KEY (organization_id) REFERENCES organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE user_organizaton_app ADD CONSTRAINT FK_2C952FC7D60322AC FOREIGN KEY (role_id) REFERENCES roles (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE users_organizations_apps DROP CONSTRAINT fk_f01f6897964985f0');
$this->addSql('ALTER TABLE users_organizations_apps DROP CONSTRAINT fk_f01f6897a2d76671');
$this->addSql('ALTER TABLE apps_organizations DROP CONSTRAINT fk_ffe659d586288a55');
$this->addSql('ALTER TABLE apps_organizations DROP CONSTRAINT fk_ffe659d5a2d76671');
$this->addSql('DROP TABLE users_organizations_apps');
$this->addSql('DROP TABLE apps_organizations');
$this->addSql('ALTER TABLE users_organizations DROP CONSTRAINT fk_4b991472d60322ac');
$this->addSql('DROP INDEX idx_4b991472d60322ac');
$this->addSql('ALTER TABLE users_organizations DROP role_id');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('CREATE TABLE users_organizations_apps (users_organizations_id INT NOT NULL, apps_id INT NOT NULL, PRIMARY KEY(users_organizations_id, apps_id))');
$this->addSql('CREATE INDEX idx_f01f6897964985f0 ON users_organizations_apps (users_organizations_id)');
$this->addSql('CREATE INDEX idx_f01f6897a2d76671 ON users_organizations_apps (apps_id)');
$this->addSql('CREATE TABLE apps_organizations (apps_id INT NOT NULL, organizations_id INT NOT NULL, PRIMARY KEY(apps_id, organizations_id))');
$this->addSql('CREATE INDEX idx_ffe659d586288a55 ON apps_organizations (organizations_id)');
$this->addSql('CREATE INDEX idx_ffe659d5a2d76671 ON apps_organizations (apps_id)');
$this->addSql('ALTER TABLE users_organizations_apps ADD CONSTRAINT fk_f01f6897964985f0 FOREIGN KEY (users_organizations_id) REFERENCES users_organizations (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE users_organizations_apps ADD CONSTRAINT fk_f01f6897a2d76671 FOREIGN KEY (apps_id) REFERENCES apps (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE apps_organizations ADD CONSTRAINT fk_ffe659d586288a55 FOREIGN KEY (organizations_id) REFERENCES organizations (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE apps_organizations ADD CONSTRAINT fk_ffe659d5a2d76671 FOREIGN KEY (apps_id) REFERENCES apps (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE user_organizaton_app DROP CONSTRAINT FK_2C952FC767B3B43D');
$this->addSql('ALTER TABLE user_organizaton_app DROP CONSTRAINT FK_2C952FC732C8A3DE');
$this->addSql('ALTER TABLE user_organizaton_app DROP CONSTRAINT FK_2C952FC7D60322AC');
$this->addSql('DROP TABLE user_organizaton_app');
$this->addSql('ALTER TABLE users_organizations ADD role_id INT NOT NULL');
$this->addSql('ALTER TABLE users_organizations ADD CONSTRAINT fk_4b991472d60322ac FOREIGN KEY (role_id) REFERENCES roles (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX idx_4b991472d60322ac ON users_organizations (role_id)');
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250808091021 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user_organizaton_app DROP CONSTRAINT fk_2c952fc732c8a3de');
$this->addSql('ALTER TABLE user_organizaton_app DROP CONSTRAINT fk_2c952fc767b3b43d');
$this->addSql('DROP INDEX idx_2c952fc732c8a3de');
$this->addSql('DROP INDEX idx_2c952fc767b3b43d');
$this->addSql('ALTER TABLE user_organizaton_app DROP organization_id');
$this->addSql('ALTER TABLE user_organizaton_app RENAME COLUMN users_id TO user_organization_id');
$this->addSql('ALTER TABLE user_organizaton_app ADD CONSTRAINT FK_2C952FC72014CF51 FOREIGN KEY (user_organization_id) REFERENCES users_organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_2C952FC72014CF51 ON user_organizaton_app (user_organization_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE user_organizaton_app DROP CONSTRAINT FK_2C952FC72014CF51');
$this->addSql('DROP INDEX IDX_2C952FC72014CF51');
$this->addSql('ALTER TABLE user_organizaton_app ADD organization_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE user_organizaton_app RENAME COLUMN user_organization_id TO users_id');
$this->addSql('ALTER TABLE user_organizaton_app ADD CONSTRAINT fk_2c952fc732c8a3de FOREIGN KEY (organization_id) REFERENCES organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE user_organizaton_app ADD CONSTRAINT fk_2c952fc767b3b43d FOREIGN KEY (users_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX idx_2c952fc732c8a3de ON user_organizaton_app (organization_id)');
$this->addSql('CREATE INDEX idx_2c952fc767b3b43d ON user_organizaton_app (users_id)');
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250811121053 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user_organizaton_app ADD application_id INT NOT NULL');
$this->addSql('ALTER TABLE user_organizaton_app ADD CONSTRAINT FK_2C952FC73E030ACD FOREIGN KEY (application_id) REFERENCES apps (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_2C952FC73E030ACD ON user_organizaton_app (application_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE user_organizaton_app DROP CONSTRAINT FK_2C952FC73E030ACD');
$this->addSql('DROP INDEX IDX_2C952FC73E030ACD');
$this->addSql('ALTER TABLE user_organizaton_app DROP application_id');
}
}

View File

@ -33,18 +33,18 @@ class Apps
#[ORM\Column(options: ['default' => true])]
private ?bool $isActive = null;
/**
* @var Collection<int, organizations>
*/
#[ORM\ManyToMany(targetEntity: organizations::class, inversedBy: 'apps')]
private Collection $organization;
#[ORM\Column(length: 255, nullable: true)]
private ?string $descriptionSmall = null;
/**
* @var Collection<int, UserOrganizatonApp>
*/
#[ORM\OneToMany(targetEntity: UserOrganizatonApp::class, mappedBy: 'application')]
private Collection $userOrganizatonApps;
public function __construct()
{
$this->organization = new ArrayCollection();
$this->userOrganizatonApps = new ArrayCollection();
}
public function getId(): ?int
@ -124,29 +124,6 @@ class Apps
return $this;
}
/**
* @return Collection<int, organizations>
*/
public function getOrganization(): Collection
{
return $this->organization;
}
public function addOrganization(organizations $organization): static
{
if (!$this->organization->contains($organization)) {
$this->organization->add($organization);
}
return $this;
}
public function removeOrganization(organizations $organization): static
{
$this->organization->removeElement($organization);
return $this;
}
public function getDescriptionSmall(): ?string
{
@ -159,4 +136,34 @@ class Apps
return $this;
}
/**
* @return Collection<int, UserOrganizatonApp>
*/
public function getUserOrganizatonApps(): Collection
{
return $this->userOrganizatonApps;
}
public function addUserOrganizatonApp(UserOrganizatonApp $userOrganizatonApp): static
{
if (!$this->userOrganizatonApps->contains($userOrganizatonApp)) {
$this->userOrganizatonApps->add($userOrganizatonApp);
$userOrganizatonApp->setApplication($this);
}
return $this;
}
public function removeUserOrganizatonApp(UserOrganizatonApp $userOrganizatonApp): static
{
if ($this->userOrganizatonApps->removeElement($userOrganizatonApp)) {
// set the owning side to null (unless already changed)
if ($userOrganizatonApp->getApplication() === $this) {
$userOrganizatonApp->setApplication(null);
}
}
return $this;
}
}

View File

@ -51,11 +51,18 @@ class Organizations
#[ORM\OneToMany(targetEntity: Actions::class, mappedBy: 'Organization')]
private Collection $actions;
/**
* @var Collection<int, UserOrganizatonApp>
*/
#[ORM\OneToMany(targetEntity: UserOrganizatonApp::class, mappedBy: 'organization')]
private Collection $userOrganizatonApps;
public function __construct()
{
$this->apps = new ArrayCollection();
$this->actions = new ArrayCollection();
$this->createdAt = new \DateTimeImmutable();
$this->userOrganizatonApps = new ArrayCollection();
}
public function getId(): ?int
@ -215,4 +222,34 @@ class Organizations
return $this;
}
/**
* @return Collection<int, UserOrganizatonApp>
*/
public function getUserOrganizatonApps(): Collection
{
return $this->userOrganizatonApps;
}
public function addUserOrganizatonApp(UserOrganizatonApp $userOrganizatonApp): static
{
if (!$this->userOrganizatonApps->contains($userOrganizatonApp)) {
$this->userOrganizatonApps->add($userOrganizatonApp);
$userOrganizatonApp->setOrganization($this);
}
return $this;
}
public function removeUserOrganizatonApp(UserOrganizatonApp $userOrganizatonApp): static
{
if ($this->userOrganizatonApps->removeElement($userOrganizatonApp)) {
// set the owning side to null (unless already changed)
if ($userOrganizatonApp->getOrganization() === $this) {
$userOrganizatonApp->setOrganization(null);
}
}
return $this;
}
}

View File

@ -263,6 +263,4 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
}

View File

@ -0,0 +1,103 @@
<?php
namespace App\Entity;
use App\Repository\UserOrganizatonAppRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: UserOrganizatonAppRepository::class)]
class UserOrganizatonApp
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column]
private ?\DateTimeImmutable $createdAt = null;
#[ORM\ManyToOne]
private ?Roles $role = null;
#[ORM\Column]
private ?bool $isActive;
#[ORM\ManyToOne(inversedBy: 'userOrganizatonApps')]
#[ORM\JoinColumn(nullable: false)]
private ?UsersOrganizations $userOrganization = null;
#[ORM\ManyToOne(inversedBy: 'userOrganizatonApps')]
#[ORM\JoinColumn(nullable: false)]
private ?Apps $application = null;
public function __construct()
{
$this->createdAt = new \DateTimeImmutable(); // Set createdAt to current time
$this->isActive = true; // Default value for isActive
}
public function getId(): ?int
{
return $this->id;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeImmutable $createdAt): static
{
$this->createdAt = $createdAt;
return $this;
}
public function getRole(): ?Roles
{
return $this->role;
}
public function setRole(?Roles $role): static
{
$this->role = $role;
return $this;
}
public function isActive(): ?bool
{
return $this->isActive;
}
public function setIsActive(bool $isActive): static
{
$this->isActive = $isActive;
return $this;
}
public function getUserOrganization(): ?UsersOrganizations
{
return $this->userOrganization;
}
public function setUserOrganization(?UsersOrganizations $userOrganization): static
{
$this->userOrganization = $userOrganization;
return $this;
}
public function getApplication(): ?Apps
{
return $this->application;
}
public function setApplication(?Apps $application): static
{
$this->application = $application;
return $this;
}
}

View File

@ -17,33 +17,29 @@ class UsersOrganizations
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?user $users = null;
private ?User $users = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Organizations $organization = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Roles $role = null;
#[ORM\Column(options: ['default' => true])]
private ?bool $isActive = null;
/**
* @var Collection<int, Apps>
*/
#[ORM\ManyToMany(targetEntity: Apps::class)]
private Collection $apps;
#[ORM\Column(nullable:true, options: ['default' => 'CURRENT_TIMESTAMP'])]
private ?\DateTimeImmutable $createdAt = null;
/**
* @var Collection<int, UserOrganizatonApp>
*/
#[ORM\OneToMany(targetEntity: UserOrganizatonApp::class, mappedBy: 'userOrganization')]
private Collection $userOrganizatonApps;
public function __construct()
{
$this->apps = new ArrayCollection();
$this->isActive = true; // Default value for isActive
$this->createdAt = new \DateTimeImmutable(); // Set createdAt to current
$this->userOrganizatonApps = new ArrayCollection();
}
public function getId(): ?int
@ -75,18 +71,6 @@ class UsersOrganizations
return $this;
}
public function getRole(): ?roles
{
return $this->role;
}
public function setRole(?roles $role): static
{
$this->role = $role;
return $this;
}
public function isActive(): ?bool
{
return $this->isActive;
@ -99,38 +83,37 @@ class UsersOrganizations
return $this;
}
/**
* @return Collection<int, apps>
*/
public function getApps(): Collection
{
return $this->apps;
}
public function addApp(apps $app): static
{
if (!$this->apps->contains($app)) {
$this->apps->add($app);
}
return $this;
}
public function removeApp(apps $app): static
{
$this->apps->removeElement($app);
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(?\DateTimeImmutable $createdAt): static
/**
* @return Collection<int, UserOrganizatonApp>
*/
public function getUserOrganizatonApps(): Collection
{
$this->createdAt = $createdAt;
return $this->userOrganizatonApps;
}
public function addUserOrganizatonApp(UserOrganizatonApp $userOrganizatonApp): static
{
if (!$this->userOrganizatonApps->contains($userOrganizatonApp)) {
$this->userOrganizatonApps->add($userOrganizatonApp);
$userOrganizatonApp->setUserOrganization($this);
}
return $this;
}
public function removeUserOrganizatonApp(UserOrganizatonApp $userOrganizatonApp): static
{
if ($this->userOrganizatonApps->removeElement($userOrganizatonApp)) {
// set the owning side to null (unless already changed)
if ($userOrganizatonApp->getUserOrganization() === $this) {
$userOrganizatonApp->setUserOrganization(null);
}
}
return $this;
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Repository;
use App\Entity\UserOrganizatonApp;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<UserOrganizatonApp>
*/
class UserOrganizatonAppRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, UserOrganizatonApp::class);
}
// /**
// * @return UserOrganizatonApp[] Returns an array of UserOrganizatonApp objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('u.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?UserOrganizatonApp
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -19,153 +19,116 @@ class UsersOrganizationsRepository extends ServiceEntityRepository
parent::__construct($registry, UsersOrganizations::class);
}
/**
* Find all distinct active organizations for a given user ID.
*
* @param int $userId
* @return UsersOrganizations[]
*/
public function findAllDistinctOrganizationsByUserId(int $userId): array
{
return $this->createQueryBuilder('uo')
->select('DISTINCT uo')
->leftJoin('uo.organization', 'o')
->leftJoin('uo.role', 'r')
->addSelect('o', 'r')
->where('uo.users = :userId', 'uo.isActive = :isActive')
->setParameter('userId', $userId)
->setParameter('isActive', true)
->getQuery()
->getResult();
}
/**
* Find all organizations where a user (by email) has a specific role.
*
* Find organizations where a user has a specific role (e.g., ADMIN)
*
* @param string $userEmail
* @param string $roleName
* @return Organizations[]
* @return array Array of UsersOrganizations entities (with organizations preloaded)
*/
public function findOrganizationsByUserEmailAndRoleName(string $userEmail, string $roleName): array
public function findUserOrganizationsByRole(string $userEmail, string $roleName): array
{
$results = $this->createQueryBuilder('uo')
return $this->createQueryBuilder('uo')
->select('uo, o')
->innerJoin('uo.users', 'u')
->innerJoin('uo.organization', 'o')
->innerJoin('uo.role', 'r')
->innerJoin('uo.userOrganizatonApps', 'uoa')
->innerJoin('uoa.role', 'r')
->where('u.email = :email')
->andWhere('r.name = :roleName')
->andWhere('uo.isActive = :isActive')
->andWhere('o.isActive = :orgIsActive') // Check if organization is active
->andWhere('u.isActive = :userIsActive')
->andWhere('o.isActive = :orgIsActive')
->andWhere('uoa.isActive = :uoaIsActive')
->setParameter('email', $userEmail)
->setParameter('roleName', $roleName)
->setParameter('isActive', true)
->setParameter('orgIsActive', true) // Parameter for organization active status
->setParameter('userIsActive', true)
->setParameter('orgIsActive', true)
->setParameter('uoaIsActive', true)
->getQuery()
->getResult();
return array_map(fn($uo) => $uo->getOrganization(), $results);
}
/**
* Helper: Get all active UsersOrganizations links, optionally filtered by organizations.
* Get all active user-organization relationships.
* Optionally filter by specific organizations.
*
* @param Organizations[]|null $organizations
* @return UsersOrganizations[]
* @param array|null $organizations Array of Organization entities to filter by
* @return array Array of UsersOrganizations entities
*/
public function getAllActiveUserOrganizationLinks(array $organizations = null): array
{
$qb = $this->createQueryBuilder('uo')
->innerJoin('uo.organization', 'o')
->innerJoin('uo.users', 'u')
->where('uo.isActive = :isActive')
->setParameter('isActive', true);
if (!empty($organizations)) {
$qb->andWhere('o IN (:organizations)')
->setParameter('organizations', $organizations);
}
return $qb->getQuery()->getResult();
}
/**
* Get the last 10 new active users for a specific organization.
* Users are ordered by creation date (most recent first).
*
* @param Organizations $organization
* @return array
*/
public function getLastNewActiveUsersByOrganization(Organizations $organization): array
{
$results = $this->createQueryBuilder('uo')
->select('u.id', 'u.surname', 'u.name', 'u.email', 'u.pictureUrl', 'u.isActive', 'uo.createdAt')
$queryBuilder = $this->createQueryBuilder('uo')
->innerJoin('uo.users', 'u')
->innerJoin('uo.organization', 'o')
->where('uo.isActive = :isActive')
->andWhere('u.isActive = :userIsActive')
->andWhere('u.isDeleted = :userIsDeleted')
->andWhere('o.isActive = :orgIsActive')
->andWhere('uo.organization = :organization')
->andWhere('o.isDeleted = :orgIsDeleted')
->setParameter('isActive', true)
->setParameter('userIsActive', true)
->setParameter('userIsDeleted', false)
->setParameter('orgIsActive', true)
->setParameter('organization', $organization)
->orderBy('uo.createdAt', 'DESC')
->setMaxResults(10)
->getQuery()
->getResult();
->setParameter('orgIsDeleted', false)
->orderBy('o.name', 'ASC')
->addOrderBy('u.surname', 'ASC');
// Remove duplicates by user ID (in case user has multiple roles)
$uniqueUsers = [];
foreach ($results as $result) {
$userId = $result['id'];
if (!isset($uniqueUsers[$userId])) {
$uniqueUsers[$userId] = $result;
}
// Filter by specific organizations if provided
if ($organizations !== null && !empty($organizations)) {
$queryBuilder->andWhere('uo.organization IN (:organizations)')
->setParameter('organizations', $organizations);
}
return array_values($uniqueUsers);
return $queryBuilder->getQuery()->getResult();
}
/**
* Get all active admin users for a specific organization.
* Returns users who have the 'ADMIN' role in the given organization.
* Get all active users who are not in any organization.
*
* @param Organizations $organization
* @return array
* @return array Array of User entities
*/
public function getAdminUsersByOrganization(Organizations $organization): array
public function getUsersWithoutOrganizations(): array
{
$results = $this->createQueryBuilder('uo')
->select('u.id', 'u.surname', 'u.name', 'u.email', 'u.pictureUrl', 'u.isActive')
->innerJoin('uo.users', 'u')
->innerJoin('uo.organization', 'o')
->innerJoin('uo.role', 'r')
->where('uo.isActive = :isActive')
->andWhere('u.isActive = :userIsActive')
->andWhere('o.isActive = :orgIsActive')
->andWhere('uo.organization = :organization')
->andWhere('r.name = :roleName')
->setParameter('isActive', true)
return $this->getEntityManager()->getRepository(User::class)
->createQueryBuilder('u')
->leftJoin('App\Entity\UsersOrganizations', 'uo', 'WITH', 'uo.users = u AND uo.isActive = true')
->where('u.isActive = :userIsActive')
->andWhere('u.isDeleted = :userIsDeleted')
->andWhere('uo.id IS NULL')
->setParameter('userIsActive', true)
->setParameter('orgIsActive', true)
->setParameter('organization', $organization)
->setParameter('roleName', 'ADMIN')
->setParameter('userIsDeleted', false)
->orderBy('u.surname', 'ASC')
->getQuery()
->getResult();
// Remove duplicates by user ID (in case user has multiple admin-related roles)
$uniqueUsers = [];
foreach ($results as $result) {
$userId = $result['id'];
if (!isset($uniqueUsers[$userId])) {
$uniqueUsers[$userId] = $result;
}
}
return array_values($uniqueUsers);
}
// /**
// * Get the last 10 new active users for a specific organization.
// * Users are ordered by creation date (most recent first).
// *
// * @param Organizations $organization
// * @return array
// */
// public function getLastNewActiveUsersByOrganization(Organizations $organization): array
// {
// return $this->createQueryBuilder('uo')
// ->select('u.id', 'u.surname', 'u.name', 'u.email', 'u.pictureUrl', 'u.isActive', 'uo.createdAt')
// ->innerJoin('uo.users', 'u')
// ->innerJoin('uo.organization', 'o')
// ->where('uo.isActive = :isActive')
// ->andWhere('u.isActive = :userIsActive')
// ->andWhere('o.isActive = :orgIsActive')
// ->andWhere('uo.organization = :organization')
// ->setParameter('isActive', true)
// ->setParameter('userIsActive', true)
// ->setParameter('orgIsActive', true)
// ->setParameter('organization', $organization)
// ->orderBy('uo.createdAt', 'DESC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult();
// }
}