Merge remote-tracking branch 'origin/master' into rector/rules-up-to-php80

Conflicts:
	src/Bundle/ChillActivityBundle/Controller/ActivityController.php
	src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/DateAggregator.php
	src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php
	src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php
	src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php
	src/Bundle/ChillCalendarBundle/Command/MapAndSubscribeUserCalendarCommand.php
	src/Bundle/ChillCalendarBundle/RemoteCalendar/Connector/MSGraph/MSGraphUserRepository.php
	src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php
	src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php
	src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php
	src/Bundle/ChillEventBundle/Search/EventSearch.php
	src/Bundle/ChillMainBundle/Controller/ExportController.php
	src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php
	src/Bundle/ChillMainBundle/Cron/CronManager.php
	src/Bundle/ChillMainBundle/Entity/CronJobExecution.php
	src/Bundle/ChillMainBundle/Export/ExportManager.php
	src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php
	src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php
	src/Bundle/ChillMainBundle/Repository/NotificationRepository.php
	src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php
	src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php
	src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php
	src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php
	src/Bundle/ChillPersonBundle/Controller/SocialWorkSocialActionApiController.php
	src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AgeAggregator.php
	src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php
	src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php
	src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepository.php
	src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php
	src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php
	src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodWorkEvaluationContext.php
	src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php
	src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php
	src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php
This commit is contained in:
2023-07-17 12:49:13 +02:00
544 changed files with 18622 additions and 2105 deletions

View File

@@ -23,13 +23,25 @@ use Doctrine\Persistence\ObjectRepository;
final class NotificationRepository implements ObjectRepository
{
private EntityManagerInterface $em;
private ?Statement $notificationByRelatedEntityAndUserAssociatedStatement = null;
private EntityRepository $repository;
public function __construct(private EntityManagerInterface $em)
private const BASE_COUNTER_SQL = <<<'SQL'
SELECT
SUM((EXISTS (SELECT 1 AS c FROM chill_main_notification_addresses_unread cmnau WHERE user_id = :userid and cmnau.notification_id = cmn.id))::int) AS unread,
SUM((cmn.sender_id = :userid)::int) AS sent,
SUM((EXISTS (SELECT 1 AS c FROM chill_main_notification_addresses_user cmnau_all WHERE user_id = :userid and cmnau_all.notification_id = cmn.id))::int) + SUM((cmn.sender_id = :userid)::int) AS total
FROM chill_main_notification cmn
SQL;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $em->getRepository(Notification::class);
$this->em = $entityManager;
$this->repository = $entityManager->getRepository(Notification::class);
}
public function countAllForAttendee(User $addressee): int
@@ -48,29 +60,45 @@ final class NotificationRepository implements ObjectRepository
->getSingleScalarResult();
}
public function countNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user): array
/**
* @param list<array{relatedEntityClass: class-string, relatedEntityId: int}> $more
* @return array{unread: int, sent: int, total: int}
*/
public function countNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user, array $more = []): array
{
if (null === $this->notificationByRelatedEntityAndUserAssociatedStatement) {
$sql =
'SELECT
SUM((EXISTS (SELECT 1 AS c FROM chill_main_notification_addresses_unread cmnau WHERE user_id = :userid and cmnau.notification_id = cmn.id))::int) AS unread,
SUM((cmn.sender_id = :userid)::int) AS sent,
COUNT(cmn.*) AS total
FROM chill_main_notification cmn
WHERE relatedentityclass = :relatedEntityClass AND relatedentityid = :relatedEntityId AND sender_id IS NOT NULL';
$sqlParams = ['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId, 'userid' => $user->getId()];
$this->notificationByRelatedEntityAndUserAssociatedStatement =
$this->em->getConnection()->prepare($sql);
if ([] === $more) {
if (null === $this->notificationByRelatedEntityAndUserAssociatedStatement) {
$sql = self::BASE_COUNTER_SQL . ' WHERE relatedentityclass = :relatedEntityClass AND relatedentityid = :relatedEntityId AND sender_id IS NOT NULL';
$this->notificationByRelatedEntityAndUserAssociatedStatement =
$this->em->getConnection()->prepare($sql);
}
$results = $this->notificationByRelatedEntityAndUserAssociatedStatement
->executeQuery($sqlParams);
$result = $results->fetchAssociative();
$results->free();
} else {
$wheres = [];
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;
}
$sql = self::BASE_COUNTER_SQL . ' WHERE sender_id IS NOT NULL AND (' . implode(' OR ', $wheres) . ')';
$result = $this->em->getConnection()->fetchAssociative($sql, $sqlParams);
}
$results = $this->notificationByRelatedEntityAndUserAssociatedStatement
->executeQuery(['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId, 'userid' => $user->getId()]);
$result = $results->fetchAssociative();
$results->free();
return $result;
return array_map(fn (?int $number) => $number ?? 0, $result);
}
public function countUnreadByUser(User $user): int
@@ -164,8 +192,8 @@ final class NotificationRepository implements ObjectRepository
}
/**
* @param mixed|null $limit
* @param mixed|null $offset
* @param int|null $limit
* @param int|null $offset
*
* @return Notification[]
*/
@@ -175,13 +203,15 @@ final class NotificationRepository implements ObjectRepository
}
/**
* @param list<array{relatedEntityClass: class-string, relatedEntityId: int}> $more
* @return array|Notification[]
*/
public function findNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user): array
public function findNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user, array $more): array
{
return
$this->buildQueryNotificationByRelatedEntityAndUserAssociated($relatedEntityClass, $relatedEntityId, $user)
$this->buildQueryNotificationByRelatedEntityAndUserAssociated($relatedEntityClass, $relatedEntityId, $user, $more)
->select('n')
->addOrderBy('n.date', 'DESC')
->getQuery()
->getResult();
}
@@ -219,13 +249,36 @@ final class NotificationRepository implements ObjectRepository
return Notification::class;
}
private function buildQueryNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user): QueryBuilder
/**
* @param list<array{relatedEntityClass: class-string, relatedEntityId: int}> $more
*/
private function buildQueryNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user, array $more = []): QueryBuilder
{
$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')
));
$qb
->where($qb->expr()->eq('n.relatedEntityClass', ':relatedEntityClass'))
->andWhere($qb->expr()->eq('n.relatedEntityId', ':relatedEntityId'))
->setParameter('relatedEntityClass', $relatedEntityClass)
->setParameter('relatedEntityId', $relatedEntityId);
foreach ($more as $k => ['relatedEntityClass' => $relatedClass, 'relatedEntityId' => $relatedId]) {
$or->add(
$qb->expr()->andX(
$qb->expr()->eq('n.relatedEntityClass', ':relatedEntityClass_'.$k),
$qb->expr()->eq('n.relatedEntityId', ':relatedEntityId_'.$k)
)
);
$qb
->setParameter('relatedEntityClass_'.$k, $relatedClass)
->setParameter('relatedEntityId_'.$k, $relatedId);
}
$qb
->andWhere($or)
->andWhere($qb->expr()->isNotNull('n.sender'))
->andWhere(
$qb->expr()->orX(
@@ -233,8 +286,6 @@ final class NotificationRepository implements ObjectRepository
$qb->expr()->eq('n.sender', ':user')
)
)
->setParameter('relatedEntityClass', $relatedEntityClass)
->setParameter('relatedEntityId', $relatedEntityId)
->setParameter('user', $user);
return $qb;

View File

@@ -38,6 +38,19 @@ final class PermissionsGroupRepository implements ObjectRepository
return $this->repository->findAll();
}
/**
* @return list<PermissionsGroup>
*/
public function findAllOrderedAlphabetically(): array
{
$qb = $this->repository->createQueryBuilder('pg');
return $qb->select(['pg', 'pg.name AS HIDDEN sort_name'])
->orderBy('sort_name')
->getQuery()
->getResult();
}
/**
* @param mixed|null $limit
* @param mixed|null $offset

View File

@@ -14,6 +14,8 @@ namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\Regroupment;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Doctrine\Persistence\ObjectRepository;
final class RegroupmentRepository implements ObjectRepository
@@ -59,6 +61,30 @@ final class RegroupmentRepository implements ObjectRepository
return $this->repository->findOneBy($criteria, $orderBy);
}
/**
* @throws NonUniqueResultException
* @throws NoResultException
*/
public function findOneByName(string $name): ?Regroupment
{
return $this->repository->createQueryBuilder('r')
->where('LOWER(r.name) = LOWER(:searched)')
->setParameter('searched', $name)
->getQuery()
->getSingleResult();
}
/**
* @return array<Regroupment>
*/
public function findRegroupmentAssociatedToNoCenter(): array
{
return $this->repository->createQueryBuilder('r')
->where('SIZE(r.centers) = 0')
->getQuery()
->getResult();
}
public function getClassName()
{
return Regroupment::class;

View File

@@ -13,6 +13,7 @@ namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;
@@ -73,6 +74,81 @@ final class UserRepository implements UserRepositoryInterface
return $this->repository->findAll();
}
/**
* @param string $lang
*/
public function findAllAsArray(string $lang): iterable
{
$dql = sprintf(<<<'DQL'
SELECT
u.id AS id,
u.username AS username,
u.email,
u.enabled,
IDENTITY(u.civility) AS civility_id,
JSON_EXTRACT(civility.abbreviation, :lang) AS civility_abbreviation,
JSON_EXTRACT(civility.name, :lang) AS civility_name,
u.label,
mainCenter.id AS mainCenter_id,
mainCenter.name AS mainCenter_name,
IDENTITY(u.mainScope) AS mainScope_id,
JSON_EXTRACT(mainScope.name, :lang) AS mainScope_name,
IDENTITY(u.userJob) AS userJob_id,
JSON_EXTRACT(userJob.label, :lang) AS userJob_name,
currentLocation.id AS currentLocation_id,
currentLocation.name AS currentLocation_name,
mainLocation.id AS mainLocation_id,
mainLocation.name AS mainLocation_name,
u.absenceStart
FROM Chill\MainBundle\Entity\User u
LEFT JOIN u.civility civility
LEFT JOIN u.currentLocation currentLocation
LEFT JOIN u.mainLocation mainLocation
LEFT JOIN u.mainCenter mainCenter
LEFT JOIN u.mainScope mainScope
LEFT JOIN u.userJob userJob
ORDER BY u.label
DQL);
$query = $this->entityManager->createQuery($dql)
->setHydrationMode(AbstractQuery::HYDRATE_ARRAY)
->setParameter('lang', $lang)
;
foreach ($query->toIterable() as $u) {
yield $u;
}
}
public function findAllUserACLAsArray(): iterable
{
$sql = <<<'SQL'
SELECT
u.id,
u.username,
u.email,
u.label,
u.enabled,
c.id AS center_id,
c.name AS center_name,
pg.id AS permissionsGroup_id,
pg.name AS permissionsGroup_name
FROM users u
LEFT JOIN user_groupcenter ON u.id = user_groupcenter.user_id
LEFT JOIN group_centers ON user_groupcenter.groupcenter_id = group_centers.id
LEFT JOIN centers c on group_centers.center_id = c.id
LEFT JOIN permission_groups pg on group_centers.permissionsgroup_id = pg.id
ORDER BY u.username, c.name, pg.name
SQL;
$query = $this->entityManager->getConnection()->executeQuery($sql);
foreach ($query->iterateAssociative() as $u) {
yield $u;
}
}
/**
* @param mixed|null $limit
* @param mixed|null $offset

View File

@@ -14,6 +14,9 @@ namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\User;
use Doctrine\Persistence\ObjectRepository;
/**
* @template ObjectRepository<User>
*/
interface UserRepositoryInterface extends ObjectRepository
{
public function countBy(array $criteria): int;
@@ -24,20 +27,25 @@ interface UserRepositoryInterface extends ObjectRepository
public function countByUsernameOrEmail(string $pattern): int;
public function find($id, $lockMode = null, $lockVersion = null): ?User;
/**
* @return User[]
*/
public function findAll(): array;
/**
* @param mixed|null $limit
* @param mixed|null $offset
* Find a list of all users.
*
* @return User[]
* The main purpose for this method is to provide a lightweight list of all users in the database.
*
* @param string $lang The lang to display all the translatable string (no fallback if not present)
* @return iterable<array{id: int, username: string, email: string, enabled: bool, civility_id: int, civility_abbreviation: string, civility_name: string, label: string, mainCenter_id: int, mainCenter_name: string, mainScope_id: int, mainScope_name: string, userJob_id: int, userJob_name: string, currentLocation_id: int, currentLocation_name: string, mainLocation_id: int, mainLocation_name: string, absenceStart: \DateTimeImmutable}>
*/
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array;
public function findAllAsArray(string $lang): iterable;
/**
* Find a list of permissions associated to each users.
*
* The main purpose for this method is to provide a lightweight list of all permissions group and center
* associated to each user.
*
* @return iterable<array{id: int, username: string, email: string, enabled: bool, center_id: int, center_name: string, permissionsGroup_id: int, permissionsGroup_name: string}>
*/
public function findAllUserACLAsArray(): iterable;
/**
* @return array|User[]
@@ -53,8 +61,6 @@ interface UserRepositoryInterface extends ObjectRepository
public function findByUsernameOrEmail(string $pattern, ?array $orderBy = [], ?int $limit = null, ?int $offset = null): array;
public function findOneBy(array $criteria, ?array $orderBy = null): ?User;
public function findOneByUsernameOrEmail(string $pattern): ?User;
/**
@@ -68,6 +74,4 @@ interface UserRepositoryInterface extends ObjectRepository
* @param mixed $flag
*/
public function findUsersHavingFlags($flag, array $amongstUsers = []): array;
public function getClassName(): string;
}