mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-26 16:45:01 +00:00
Merge remote-tracking branch 'origin/upgrade-sf5' into signature-app-master
This commit is contained in:
@@ -13,6 +13,8 @@ namespace Chill\MainBundle\Repository;
|
||||
|
||||
use Chill\MainBundle\Entity\Notification;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Result;
|
||||
use Doctrine\DBAL\Statement;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -81,10 +83,7 @@ final class NotificationRepository implements ObjectRepository
|
||||
$results->free();
|
||||
} else {
|
||||
$wheres = [];
|
||||
foreach ([
|
||||
['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId],
|
||||
...$more,
|
||||
] as $k => ['relatedEntityClass' => $relClass, 'relatedEntityId' => $relId]) {
|
||||
foreach ([['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId], ...$more] as $k => ['relatedEntityClass' => $relClass, 'relatedEntityId' => $relId]) {
|
||||
$wheres[] = "(relatedEntityClass = :relatedEntityClass_{$k} AND relatedEntityId = :relatedEntityId_{$k})";
|
||||
$sqlParams["relatedEntityClass_{$k}"] = $relClass;
|
||||
$sqlParams["relatedEntityId_{$k}"] = $relId;
|
||||
@@ -228,11 +227,11 @@ final class NotificationRepository implements ObjectRepository
|
||||
$rsm->addRootEntityFromClassMetadata(Notification::class, 'cmn');
|
||||
|
||||
$sql = 'SELECT '.$rsm->generateSelectClause(['cmn' => 'cmn']).' '.
|
||||
'FROM chill_main_notification cmn '.
|
||||
'WHERE '.
|
||||
'EXISTS (select 1 FROM chill_main_notification_addresses_unread cmnau WHERE cmnau.user_id = :userId and cmnau.notification_id = cmn.id) '.
|
||||
'ORDER BY cmn.date DESC '.
|
||||
'LIMIT :limit OFFSET :offset';
|
||||
'FROM chill_main_notification cmn '.
|
||||
'WHERE '.
|
||||
'EXISTS (select 1 FROM chill_main_notification_addresses_unread cmnau WHERE cmnau.user_id = :userId and cmnau.notification_id = cmn.id) '.
|
||||
'ORDER BY cmn.date DESC '.
|
||||
'LIMIT :limit OFFSET :offset';
|
||||
|
||||
$nq = $this->em->createNativeQuery($sql, $rsm)
|
||||
->setParameter('userId', $user->getId())
|
||||
@@ -255,10 +254,12 @@ final class NotificationRepository implements ObjectRepository
|
||||
$qb = $this->repository->createQueryBuilder('n');
|
||||
|
||||
// add condition for related entity (in main arguments, and in more)
|
||||
$or = $qb->expr()->orX($qb->expr()->andX(
|
||||
$qb->expr()->eq('n.relatedEntityClass', ':relatedEntityClass'),
|
||||
$qb->expr()->eq('n.relatedEntityId', ':relatedEntityId')
|
||||
));
|
||||
$or = $qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->eq('n.relatedEntityClass', ':relatedEntityClass'),
|
||||
$qb->expr()->eq('n.relatedEntityId', ':relatedEntityId')
|
||||
)
|
||||
);
|
||||
$qb
|
||||
->setParameter('relatedEntityClass', $relatedEntityClass)
|
||||
->setParameter('relatedEntityId', $relatedEntityId);
|
||||
@@ -310,4 +311,86 @@ final class NotificationRepository implements ObjectRepository
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<int> the ids of the notifications marked as unread
|
||||
*/
|
||||
public function markAllNotificationAsReadForUser(User $user): array
|
||||
{
|
||||
// Get the database connection from the entity manager
|
||||
$connection = $this->em->getConnection();
|
||||
|
||||
/** @var Result $results */
|
||||
$results = $connection->transactional(function (Connection $connection) use ($user) {
|
||||
// Define the SQL query
|
||||
$sql = <<<'SQL'
|
||||
DELETE FROM chill_main_notification_addresses_unread
|
||||
WHERE user_id = :user_id
|
||||
RETURNING notification_id
|
||||
SQL;
|
||||
|
||||
return $connection->executeQuery($sql, ['user_id' => $user->getId()]);
|
||||
});
|
||||
|
||||
$notificationIdsTouched = [];
|
||||
foreach ($results->iterateAssociative() as $row) {
|
||||
$notificationIdsTouched[] = $row['notification_id'];
|
||||
}
|
||||
|
||||
return array_values($notificationIdsTouched);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $notificationIds
|
||||
*/
|
||||
public function markAllNotificationAsUnreadForUser(User $user, array $notificationIds): array
|
||||
{
|
||||
// Get the database connection from the entity manager
|
||||
$connection = $this->em->getConnection();
|
||||
|
||||
/** @var Result $results */
|
||||
$results = $connection->transactional(function (Connection $connection) use ($user, $notificationIds) {
|
||||
// This query double-check that the user is one of the addresses of the notification or the sender,
|
||||
// if the notification is already marked as unread, this query does not fails.
|
||||
// this query return the list of notification id which are affected
|
||||
$sql = <<<'SQL'
|
||||
INSERT INTO chill_main_notification_addresses_unread (user_id, notification_id)
|
||||
SELECT ?, chill_main_notification_addresses_user.notification_id
|
||||
FROM chill_main_notification_addresses_user JOIN chill_main_notification ON chill_main_notification_addresses_user.notification_id = chill_main_notification.id
|
||||
WHERE (chill_main_notification_addresses_user.user_id = ? OR chill_main_notification.sender_id = ?)
|
||||
AND chill_main_notification_addresses_user.notification_id IN ({ notification_ids })
|
||||
ON CONFLICT (user_id, notification_id) DO NOTHING
|
||||
RETURNING notification_id
|
||||
SQL;
|
||||
|
||||
$params = [$user->getId(), $user->getId(), $user->getId(), ...array_values($notificationIds)];
|
||||
$sql = strtr($sql, ['{ notification_ids }' => implode(', ', array_fill(0, count($notificationIds), '?'))]);
|
||||
|
||||
return $connection->executeQuery($sql, $params);
|
||||
});
|
||||
|
||||
$notificationIdsTouched = [];
|
||||
foreach ($results->iterateAssociative() as $row) {
|
||||
$notificationIdsTouched[] = $row['notification_id'];
|
||||
}
|
||||
|
||||
return array_values($notificationIdsTouched);
|
||||
}
|
||||
|
||||
public function findAllUnreadByUser(User $user): array
|
||||
{
|
||||
$rsm = new Query\ResultSetMappingBuilder($this->em);
|
||||
$rsm->addRootEntityFromClassMetadata(Notification::class, 'cmn');
|
||||
|
||||
$sql = 'SELECT '.$rsm->generateSelectClause(['cmn' => 'cmn']).' '.
|
||||
'FROM chill_main_notification cmn '.
|
||||
'WHERE '.
|
||||
'EXISTS (SELECT 1 FROM chill_main_notification_addresses_unread cmnau WHERE cmnau.user_id = :userId AND cmnau.notification_id = cmn.id) '.
|
||||
'ORDER BY cmn.date DESC';
|
||||
|
||||
$nq = $this->em->createNativeQuery($sql, $rsm)
|
||||
->setParameter('userId', $user->getId());
|
||||
|
||||
return $nq->getResult();
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
@@ -26,9 +27,25 @@ final readonly class UserRepository implements UserRepositoryInterface
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
private const FIELDS = ['id', 'email', 'enabled', 'civility_id', 'civility_abbreviation', 'civility_name', 'label', 'mainCenter_id',
|
||||
'mainCenter_name', 'mainScope_id', 'mainScope_name', 'userJob_id', 'userJob_name', 'currentLocation_id', 'currentLocation_name',
|
||||
'mainLocation_id', 'mainLocation_name'];
|
||||
private const FIELDS = [
|
||||
'id',
|
||||
'email',
|
||||
'enabled',
|
||||
'civility_id',
|
||||
'civility_abbreviation',
|
||||
'civility_name',
|
||||
'label',
|
||||
'mainCenter_id',
|
||||
'mainCenter_name',
|
||||
'mainScope_id',
|
||||
'mainScope_name',
|
||||
'userJob_id',
|
||||
'userJob_name',
|
||||
'currentLocation_id',
|
||||
'currentLocation_name',
|
||||
'mainLocation_id',
|
||||
'mainLocation_name',
|
||||
];
|
||||
|
||||
public function __construct(private EntityManagerInterface $entityManager, private Connection $connection)
|
||||
{
|
||||
@@ -296,6 +313,25 @@ final readonly class UserRepository implements UserRepositoryInterface
|
||||
return User::class;
|
||||
}
|
||||
|
||||
public function getResult(
|
||||
QueryBuilder $qb,
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = [],
|
||||
): array {
|
||||
$qb->select('u');
|
||||
|
||||
$qb
|
||||
->setFirstResult($start)
|
||||
->setMaxResults($limit);
|
||||
|
||||
foreach ($orderBy as $field => $direction) {
|
||||
$qb->addOrderBy('u.'.$field, $direction);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
private function queryByUsernameOrEmail(string $pattern): QueryBuilder
|
||||
{
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(User::class, 'u');
|
||||
@@ -312,4 +348,49 @@ final readonly class UserRepository implements UserRepositoryInterface
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function buildFilterBaseQuery(?string $queryString, array $isActive)
|
||||
{
|
||||
if (null !== $queryString) {
|
||||
$qb = $this->queryByUsernameOrEmail($queryString);
|
||||
} else {
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(User::class, 'u');
|
||||
}
|
||||
|
||||
// Add condition based on active/inactive status
|
||||
if (in_array('Active', $isActive, true) && !in_array('Inactive', $isActive, true)) {
|
||||
$qb->andWhere('u.enabled = true');
|
||||
} elseif (in_array('Inactive', $isActive, true) && !in_array('Active', $isActive, true)) {
|
||||
$qb->andWhere('u.enabled = false');
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function findFilteredUsers(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = ['username' => 'ASC'],
|
||||
): array {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
return $this->getResult($qb, $start, $limit, $orderBy);
|
||||
}
|
||||
|
||||
public function countFilteredUsers(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
): int {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
try {
|
||||
return $qb
|
||||
->select('COUNT(u)')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
} catch (NoResultException|NonUniqueResultException $e) {
|
||||
throw new \LogicException('a count query should return one result', previous: $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user