mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-12-18 08:05:41 +00:00
Compare commits
10 Commits
ticket-app
...
v4.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
| c0f9e953fb | |||
| a49ea2b6b9 | |||
| a30232d3ce | |||
| aae55e6f8c | |||
| c9513f2f6c | |||
| 11d7425883 | |||
| 08897e0981 | |||
| 98cbfed054 | |||
| 9af4d19744 | |||
| c1cf5a8bb2 |
9
.changes/v4.11.0.md
Normal file
9
.changes/v4.11.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## v4.11.0 - 2025-12-17
|
||||
### Feature
|
||||
* ([#478](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/478)) Add filtering to admin lists: social actions, social issues, goals, results, and evaluations
|
||||
### Fixed
|
||||
* ([#466](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/466)) Fix migration query after previous fix
|
||||
|
||||
* Fix translation key/value
|
||||
|
||||
Cannot start with % and should be wrapped in "".
|
||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -6,6 +6,16 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||
|
||||
|
||||
## v4.11.0 - 2025-12-17
|
||||
### Feature
|
||||
* ([#478](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/478)) Add filtering to admin lists: social actions, social issues, goals, results, and evaluations
|
||||
### Fixed
|
||||
* ([#466](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/466)) Fix migration query after previous fix
|
||||
|
||||
* Fix translation key/value
|
||||
|
||||
Cannot start with % and should be wrapped in "".
|
||||
|
||||
## v4.10.1 - 2025-12-11
|
||||
### Fixed
|
||||
* Fix missing translation variable in NewLocation component
|
||||
|
||||
@@ -39,7 +39,7 @@ final class Version20251118124241 extends AbstractMigration
|
||||
$this->addSql("COMMENT ON COLUMN activity_user.by_migration IS 'For backup purpose - can be safely deleted after a while. See migration \\Chill\\Migrations\\Activity\\Version20251118124241'");
|
||||
|
||||
$this->addSql('INSERT INTO activity_user (activity_id, user_id, by_migration)
|
||||
SELECT id, user_id, true FROM activity
|
||||
SELECT id, user_id, true FROM activity WHERE user_id is not null
|
||||
ON CONFLICT DO NOTHING');
|
||||
}
|
||||
|
||||
|
||||
@@ -189,14 +189,14 @@ crud:
|
||||
title_edit: Rapport "belemmering" bewerken
|
||||
title_delete: Belemmering verwijderen
|
||||
button_delete: Verwijderen
|
||||
confirm_message_delete: %as_string% verwijderen?
|
||||
confirm_message_delete: "%as_string% verwijderen?"
|
||||
cscv:
|
||||
title_new: Nieuw CV voor %person%
|
||||
title_view: CV voor %person%
|
||||
title_edit: CV bewerken
|
||||
title_delete: CV verwijderen
|
||||
button_delete: Verwijderen
|
||||
confirm_message_delete: %as_string% verwijderen?
|
||||
confirm_message_delete: "%as_string% verwijderen?"
|
||||
no_date: Geen datum aangegeven
|
||||
no_end_date: einddatum onbekend
|
||||
no_start_date: startdatum onbekend
|
||||
@@ -206,7 +206,7 @@ crud:
|
||||
title_edit: Immersie bewerken
|
||||
title_delete: Immersie verwijderen
|
||||
button_delete: Verwijderen
|
||||
confirm_message_delete: %as_string% verwijderen?
|
||||
confirm_message_delete: "%as_string% verwijderen?"
|
||||
projet_prof:
|
||||
title_new: Nieuw professioneel project voor %person%
|
||||
title_view: Professioneel project voor %person%
|
||||
|
||||
@@ -13,14 +13,63 @@ namespace Chill\PersonBundle\Controller\SocialWork;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
|
||||
use Chill\PersonBundle\Repository\SocialWork\EvaluationRepository;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class EvaluationController extends CRUDController
|
||||
{
|
||||
public function __construct(private readonly EvaluationRepository $repository) {}
|
||||
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||
{
|
||||
$query->addOrderBy('e.id', 'ASC');
|
||||
|
||||
return parent::orderQuery($action, $query, $request, $paginator);
|
||||
}
|
||||
|
||||
protected function getQueryResult(
|
||||
string $action,
|
||||
Request $request,
|
||||
int $totalItems,
|
||||
PaginatorInterface $paginator,
|
||||
?FilterOrderHelper $filterOrder = null,
|
||||
) {
|
||||
if (0 === $totalItems) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::getQueryResult($action, $request, $totalItems, $paginator, $filterOrder);
|
||||
}
|
||||
|
||||
$queryString = $filterOrder->getQueryString();
|
||||
$activeFilter = $filterOrder->getCheckboxData('activeFilter');
|
||||
$nb = $this->repository->countFilteredEvaluations($queryString, $activeFilter);
|
||||
|
||||
$paginator = $this->getPaginatorFactory()->create($nb);
|
||||
|
||||
return $this->repository->findFilteredEvaluations($queryString, $activeFilter, $paginator->getCurrentPageFirstItemNumber(), $paginator->getItemsPerPage());
|
||||
}
|
||||
|
||||
protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int
|
||||
{
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::countEntities($action, $request, $filterOrder);
|
||||
}
|
||||
|
||||
return $this->repository->countFilteredEvaluations(
|
||||
$filterOrder->getQueryString(),
|
||||
$filterOrder->getCheckboxData('activeFilter')
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper
|
||||
{
|
||||
return $this->getFilterOrderHelperFactory()
|
||||
->create(self::class)
|
||||
->addSearchBox(['label'])
|
||||
->addCheckbox('activeFilter', [true => 'Active', false => 'Inactive'], ['Active'])
|
||||
->build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,68 @@ namespace Chill\PersonBundle\Controller\SocialWork;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
|
||||
use Chill\PersonBundle\Repository\SocialWork\GoalRepository;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class GoalController extends CRUDController
|
||||
{
|
||||
public function __construct(private readonly GoalRepository $repository) {}
|
||||
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||
{
|
||||
$query->addOrderBy('e.id', 'ASC');
|
||||
|
||||
return parent::orderQuery($action, $query, $request, $paginator);
|
||||
}
|
||||
|
||||
protected function getQueryResult(
|
||||
string $action,
|
||||
Request $request,
|
||||
int $totalItems,
|
||||
PaginatorInterface $paginator,
|
||||
?FilterOrderHelper $filterOrder = null,
|
||||
) {
|
||||
if (0 === $totalItems) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::getQueryResult($action, $request, $totalItems, $paginator, $filterOrder);
|
||||
}
|
||||
|
||||
$queryString = $filterOrder->getQueryString();
|
||||
$activeFilter = $filterOrder->getCheckboxData('activeFilter');
|
||||
$nb = $this->repository->countFilteredGoals($queryString, $activeFilter);
|
||||
|
||||
$paginator = $this->getPaginatorFactory()->create($nb);
|
||||
|
||||
return $this->repository->findFilteredGoals(
|
||||
$queryString,
|
||||
$activeFilter,
|
||||
$paginator->getCurrentPageFirstItemNumber(),
|
||||
$paginator->getItemsPerPage()
|
||||
);
|
||||
}
|
||||
|
||||
protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int
|
||||
{
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::countEntities($action, $request, $filterOrder);
|
||||
}
|
||||
|
||||
return $this->repository->countFilteredGoals(
|
||||
$filterOrder->getQueryString(),
|
||||
$filterOrder->getCheckboxData('activeFilter')
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper
|
||||
{
|
||||
return $this->getFilterOrderHelperFactory()
|
||||
->create(self::class)
|
||||
->addSearchBox(['label'])
|
||||
->addCheckbox('activeFilter', [true => 'Active', false => 'Inactive'], ['Active'])
|
||||
->build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,68 @@ namespace Chill\PersonBundle\Controller\SocialWork;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
|
||||
use Chill\PersonBundle\Repository\SocialWork\ResultRepository;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ResultController extends CRUDController
|
||||
{
|
||||
public function __construct(private readonly ResultRepository $repository) {}
|
||||
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||
{
|
||||
$query->addOrderBy('e.id', 'ASC');
|
||||
|
||||
return parent::orderQuery($action, $query, $request, $paginator);
|
||||
}
|
||||
|
||||
protected function getQueryResult(
|
||||
string $action,
|
||||
Request $request,
|
||||
int $totalItems,
|
||||
PaginatorInterface $paginator,
|
||||
?FilterOrderHelper $filterOrder = null,
|
||||
) {
|
||||
if (0 === $totalItems) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::getQueryResult($action, $request, $totalItems, $paginator, $filterOrder);
|
||||
}
|
||||
|
||||
$queryString = $filterOrder->getQueryString();
|
||||
$activeFilter = $filterOrder->getCheckboxData('activeFilter');
|
||||
$nb = $this->repository->countFilteredResults($queryString, $activeFilter);
|
||||
|
||||
$paginator = $this->getPaginatorFactory()->create($nb);
|
||||
|
||||
return $this->repository->findFilteredResults(
|
||||
$queryString,
|
||||
$activeFilter,
|
||||
$paginator->getCurrentPageFirstItemNumber(),
|
||||
$paginator->getItemsPerPage()
|
||||
);
|
||||
}
|
||||
|
||||
protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int
|
||||
{
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::countEntities($action, $request, $filterOrder);
|
||||
}
|
||||
|
||||
return $this->repository->countFilteredResults(
|
||||
$filterOrder->getQueryString(),
|
||||
$filterOrder->getCheckboxData('activeFilter')
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper
|
||||
{
|
||||
return $this->getFilterOrderHelperFactory()
|
||||
->create(self::class)
|
||||
->addSearchBox(['label'])
|
||||
->addCheckbox('activeFilter', [true => 'Active', false => 'Inactive'], ['Active'])
|
||||
->build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,68 @@ namespace Chill\PersonBundle\Controller\SocialWork;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
|
||||
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class SocialActionController extends CRUDController
|
||||
{
|
||||
public function __construct(private readonly SocialActionRepository $repository) {}
|
||||
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||
{
|
||||
$query->addOrderBy('e.ordering', 'ASC');
|
||||
|
||||
return parent::orderQuery($action, $query, $request, $paginator);
|
||||
}
|
||||
|
||||
protected function getQueryResult(
|
||||
string $action,
|
||||
Request $request,
|
||||
int $totalItems,
|
||||
PaginatorInterface $paginator,
|
||||
?FilterOrderHelper $filterOrder = null,
|
||||
) {
|
||||
if (0 === $totalItems) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::getQueryResult($action, $request, $totalItems, $paginator, $filterOrder);
|
||||
}
|
||||
|
||||
$queryString = $filterOrder->getQueryString();
|
||||
$activeFilter = $filterOrder->getCheckboxData('activeFilter');
|
||||
$nb = $this->repository->countFilteredSocialActions($queryString, $activeFilter);
|
||||
|
||||
$paginator = $this->getPaginatorFactory()->create($nb);
|
||||
|
||||
return $this->repository->findFilteredSocialActions(
|
||||
$queryString,
|
||||
$activeFilter,
|
||||
$paginator->getCurrentPageFirstItemNumber(),
|
||||
$paginator->getItemsPerPage()
|
||||
);
|
||||
}
|
||||
|
||||
protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int
|
||||
{
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::countEntities($action, $request, $filterOrder);
|
||||
}
|
||||
|
||||
return $this->repository->countFilteredSocialActions(
|
||||
$filterOrder->getQueryString(),
|
||||
$filterOrder->getCheckboxData('activeFilter')
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper
|
||||
{
|
||||
return $this->getFilterOrderHelperFactory()
|
||||
->create(self::class)
|
||||
->addSearchBox(['label'])
|
||||
->addCheckbox('activeFilter', [true => 'Active', false => 'Inactive'], ['Active'])
|
||||
->build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,15 @@ namespace Chill\PersonBundle\Controller\SocialWork;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
|
||||
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class SocialIssueController extends CRUDController
|
||||
{
|
||||
public function __construct(private readonly SocialIssueRepository $repository) {}
|
||||
|
||||
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
|
||||
{
|
||||
if ('new' === $action) {
|
||||
@@ -37,4 +41,54 @@ class SocialIssueController extends CRUDController
|
||||
|
||||
return parent::orderQuery($action, $query, $request, $paginator);
|
||||
}
|
||||
|
||||
protected function getQueryResult(
|
||||
string $action,
|
||||
Request $request,
|
||||
int $totalItems,
|
||||
PaginatorInterface $paginator,
|
||||
?FilterOrderHelper $filterOrder = null,
|
||||
) {
|
||||
if (0 === $totalItems) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::getQueryResult($action, $request, $totalItems, $paginator, $filterOrder);
|
||||
}
|
||||
|
||||
$queryString = $filterOrder->getQueryString();
|
||||
$activeFilter = $filterOrder->getCheckboxData('activeFilter');
|
||||
$nb = $this->repository->countFilteredSocialIssues($queryString, $activeFilter);
|
||||
|
||||
$paginator = $this->getPaginatorFactory()->create($nb);
|
||||
|
||||
return $this->repository->findFilteredSocialIssues(
|
||||
$queryString,
|
||||
$activeFilter,
|
||||
$paginator->getCurrentPageFirstItemNumber(),
|
||||
$paginator->getItemsPerPage()
|
||||
);
|
||||
}
|
||||
|
||||
protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int
|
||||
{
|
||||
if (!$filterOrder instanceof FilterOrderHelper) {
|
||||
return parent::countEntities($action, $request, $filterOrder);
|
||||
}
|
||||
|
||||
return $this->repository->countFilteredSocialIssues(
|
||||
$filterOrder->getQueryString(),
|
||||
$filterOrder->getCheckboxData('activeFilter')
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper
|
||||
{
|
||||
return $this->getFilterOrderHelperFactory()
|
||||
->create(self::class)
|
||||
->addSearchBox(['label'])
|
||||
->addCheckbox('activeFilter', [true => 'Active', false => 'Inactive'], ['Active'])
|
||||
->build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,16 @@ namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
final readonly class EvaluationRepository implements EvaluationRepositoryInterface
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(private EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(Evaluation::class);
|
||||
}
|
||||
@@ -65,4 +69,86 @@ final readonly class EvaluationRepository implements EvaluationRepositoryInterfa
|
||||
{
|
||||
return Evaluation::class;
|
||||
}
|
||||
|
||||
private function getLang(): string
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()?->getLocale() ?? 'fr';
|
||||
}
|
||||
|
||||
public function getResult(
|
||||
QueryBuilder $qb,
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = [],
|
||||
): array {
|
||||
$qb->select('e');
|
||||
|
||||
$qb
|
||||
->setFirstResult($start)
|
||||
->setMaxResults($limit);
|
||||
|
||||
foreach ($orderBy as $field => $direction) {
|
||||
$qb->addOrderBy('e.'.$field, $direction);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
private function queryByTitle(string $pattern): QueryBuilder
|
||||
{
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(Evaluation::class, 'e');
|
||||
|
||||
// Extract the current locale's value from the JSON `title` and search on it
|
||||
$qb
|
||||
->where($qb->expr()->like('LOWER(UNACCENT(JSON_EXTRACT(e.title, :lang)))', "CONCAT('%', LOWER(UNACCENT(:pattern)), '%')"))
|
||||
->setParameter('pattern', $pattern)
|
||||
->setParameter('lang', $this->getLang());
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function buildFilterBaseQuery(?string $queryString, array $isActive): QueryBuilder
|
||||
{
|
||||
if (null !== $queryString) {
|
||||
$qb = $this->queryByTitle($queryString);
|
||||
} else {
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(Evaluation::class, 'e');
|
||||
}
|
||||
|
||||
// Add condition based on active/inactive status
|
||||
if (in_array('Active', $isActive, true) && !in_array('Inactive', $isActive, true)) {
|
||||
$qb->andWhere('e.active = true');
|
||||
} elseif (in_array('Inactive', $isActive, true) && !in_array('Active', $isActive, true)) {
|
||||
$qb->andWhere('e.active = false');
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function findFilteredEvaluations(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = ['title' => 'ASC'],
|
||||
): array {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
return $this->getResult($qb, $start, $limit, $orderBy);
|
||||
}
|
||||
|
||||
public function countFilteredEvaluations(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
): int {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
try {
|
||||
return $qb
|
||||
->select('COUNT(e)')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
} catch (NoResultException|NonUniqueResultException $e) {
|
||||
throw new \LogicException('a count query should return one result', previous: $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,17 @@ use Chill\PersonBundle\Entity\SocialWork\Goal;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
final readonly class GoalRepository implements ObjectRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(private EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(Goal::class);
|
||||
}
|
||||
@@ -101,6 +104,102 @@ final readonly class GoalRepository implements ObjectRepository
|
||||
return Goal::class;
|
||||
}
|
||||
|
||||
private function getLang(): string
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()?->getLocale() ?? 'fr';
|
||||
}
|
||||
|
||||
public function getResult(
|
||||
QueryBuilder $qb,
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = [],
|
||||
): array {
|
||||
$qb->select('g');
|
||||
|
||||
$qb
|
||||
->setFirstResult($start)
|
||||
->setMaxResults($limit);
|
||||
|
||||
foreach ($orderBy as $field => $direction) {
|
||||
$qb->addOrderBy('g.'.$field, $direction);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
private function queryByTitle(string $pattern): QueryBuilder
|
||||
{
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(Goal::class, 'g');
|
||||
|
||||
// search across locales by extracting the localized value
|
||||
$qb
|
||||
->where($qb->expr()->like('LOWER(UNACCENT(JSON_EXTRACT(g.title, :lang)))', "CONCAT('%', LOWER(UNACCENT(:pattern)), '%')"))
|
||||
->setParameter('pattern', $pattern)
|
||||
->setParameter('lang', $this->getLang());
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function buildFilterBaseQuery(?string $queryString, array $isActive): QueryBuilder
|
||||
{
|
||||
if (null !== $queryString) {
|
||||
$qb = $this->queryByTitle($queryString);
|
||||
} else {
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(Goal::class, 'g');
|
||||
}
|
||||
|
||||
// Active when desactivationDate is null or in the future
|
||||
$now = new \DateTime('now');
|
||||
if (in_array('Active', $isActive, true) && !in_array('Inactive', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('g.desactivationDate'),
|
||||
$qb->expr()->gt('g.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
} elseif (in_array('Inactive', $isActive, true) && !in_array('Active', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('g.desactivationDate'),
|
||||
$qb->expr()->lte('g.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, Goal>
|
||||
*/
|
||||
public function findFilteredGoals(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = ['id' => 'ASC'],
|
||||
): array {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
return $this->getResult($qb, $start, $limit, $orderBy);
|
||||
}
|
||||
|
||||
public function countFilteredGoals(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
): int {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
try {
|
||||
return $qb
|
||||
->select('COUNT(g)')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
} catch (NoResultException|NonUniqueResultException $e) {
|
||||
throw new \LogicException('a count query should return one result', previous: $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder
|
||||
{
|
||||
$actions = $action->getDescendantsWithThis();
|
||||
|
||||
@@ -16,14 +16,17 @@ use Chill\PersonBundle\Entity\SocialWork\Result;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
final readonly class ResultRepository implements ObjectRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(private EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(Result::class);
|
||||
}
|
||||
@@ -125,6 +128,100 @@ final readonly class ResultRepository implements ObjectRepository
|
||||
return Result::class;
|
||||
}
|
||||
|
||||
private function getLang(): string
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()?->getLocale() ?? 'fr';
|
||||
}
|
||||
|
||||
public function getResult(
|
||||
QueryBuilder $qb,
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = [],
|
||||
): array {
|
||||
$qb->select('r');
|
||||
|
||||
$qb
|
||||
->setFirstResult($start)
|
||||
->setMaxResults($limit);
|
||||
|
||||
foreach ($orderBy as $field => $direction) {
|
||||
$qb->addOrderBy('r.'.$field, $direction);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
private function queryByTitle(string $pattern): QueryBuilder
|
||||
{
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(Result::class, 'r');
|
||||
|
||||
$qb
|
||||
->where($qb->expr()->like('LOWER(UNACCENT(JSON_EXTRACT(r.title, :lang)))', "CONCAT('%', LOWER(UNACCENT(:pattern)), '%')"))
|
||||
->setParameter('pattern', $pattern)
|
||||
->setParameter('lang', $this->getLang());
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function buildFilterBaseQuery(?string $queryString, array $isActive): QueryBuilder
|
||||
{
|
||||
if (null !== $queryString) {
|
||||
$qb = $this->queryByTitle($queryString);
|
||||
} else {
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(Result::class, 'r');
|
||||
}
|
||||
|
||||
$now = new \DateTime('now');
|
||||
if (in_array('Active', $isActive, true) && !in_array('Inactive', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('r.desactivationDate'),
|
||||
$qb->expr()->gt('r.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
} elseif (in_array('Inactive', $isActive, true) && !in_array('Active', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('r.desactivationDate'),
|
||||
$qb->expr()->lte('r.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, Result>
|
||||
*/
|
||||
public function findFilteredResults(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = ['id' => 'ASC'],
|
||||
): array {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
return $this->getResult($qb, $start, $limit, $orderBy);
|
||||
}
|
||||
|
||||
public function countFilteredResults(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
): int {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
try {
|
||||
return $qb
|
||||
->select('COUNT(r)')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
} catch (NoResultException|NonUniqueResultException $e) {
|
||||
throw new \LogicException('a count query should return one result', previous: $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function buildQueryByGoal(Goal $goal): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('r');
|
||||
|
||||
@@ -14,14 +14,17 @@ namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
final readonly class SocialActionRepository implements ObjectRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(private EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(SocialAction::class);
|
||||
}
|
||||
@@ -84,6 +87,100 @@ final readonly class SocialActionRepository implements ObjectRepository
|
||||
return SocialAction::class;
|
||||
}
|
||||
|
||||
private function getLang(): string
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()?->getLocale() ?? 'fr';
|
||||
}
|
||||
|
||||
public function getResult(
|
||||
QueryBuilder $qb,
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = [],
|
||||
): array {
|
||||
$qb->select('sa');
|
||||
|
||||
$qb
|
||||
->setFirstResult($start)
|
||||
->setMaxResults($limit);
|
||||
|
||||
foreach ($orderBy as $field => $direction) {
|
||||
$qb->addOrderBy('sa.'.$field, $direction);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
private function queryByTitle(string $pattern): QueryBuilder
|
||||
{
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(SocialAction::class, 'sa');
|
||||
|
||||
$qb
|
||||
->where($qb->expr()->like('LOWER(UNACCENT(JSON_EXTRACT(sa.title, :lang)))', "CONCAT('%', LOWER(UNACCENT(:pattern)), '%')"))
|
||||
->setParameter('pattern', $pattern)
|
||||
->setParameter('lang', $this->getLang());
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function buildFilterBaseQuery(?string $queryString, array $isActive): QueryBuilder
|
||||
{
|
||||
if (null !== $queryString) {
|
||||
$qb = $this->queryByTitle($queryString);
|
||||
} else {
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(SocialAction::class, 'sa');
|
||||
}
|
||||
|
||||
$now = new \DateTime('now');
|
||||
if (in_array('Active', $isActive, true) && !in_array('Inactive', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('sa.desactivationDate'),
|
||||
$qb->expr()->gt('sa.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
} elseif (in_array('Inactive', $isActive, true) && !in_array('Active', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('sa.desactivationDate'),
|
||||
$qb->expr()->lte('sa.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, SocialAction>
|
||||
*/
|
||||
public function findFilteredSocialActions(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = ['ordering' => 'ASC'],
|
||||
): array {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
return $this->getResult($qb, $start, $limit, $orderBy);
|
||||
}
|
||||
|
||||
public function countFilteredSocialActions(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
): int {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
try {
|
||||
return $qb
|
||||
->select('COUNT(sa)')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
} catch (NoResultException|NonUniqueResultException $e) {
|
||||
throw new \LogicException('a count query should return one result', previous: $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function buildQueryWithDesactivatedDateCriteria(): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('sa');
|
||||
|
||||
@@ -14,14 +14,17 @@ namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
final readonly class SocialIssueRepository implements ObjectRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(private EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(SocialIssue::class);
|
||||
}
|
||||
@@ -79,6 +82,100 @@ final readonly class SocialIssueRepository implements ObjectRepository
|
||||
return SocialIssue::class;
|
||||
}
|
||||
|
||||
public function getResult(
|
||||
QueryBuilder $qb,
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = [],
|
||||
): array {
|
||||
$qb->select('si');
|
||||
|
||||
$qb
|
||||
->setFirstResult($start)
|
||||
->setMaxResults($limit);
|
||||
|
||||
foreach ($orderBy as $field => $direction) {
|
||||
$qb->addOrderBy('si.'.$field, $direction);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
private function getLang(): string
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()?->getLocale() ?? 'fr';
|
||||
}
|
||||
|
||||
private function queryByTitle(string $pattern): QueryBuilder
|
||||
{
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(SocialIssue::class, 'si');
|
||||
|
||||
$qb
|
||||
->where($qb->expr()->like('LOWER(UNACCENT(JSON_EXTRACT(si.title, :lang)))', "CONCAT('%', LOWER(UNACCENT(:pattern)), '%')"))
|
||||
->setParameter('pattern', $pattern)
|
||||
->setParameter('lang', $this->getLang());
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function buildFilterBaseQuery(?string $queryString, array $isActive): QueryBuilder
|
||||
{
|
||||
if (null !== $queryString) {
|
||||
$qb = $this->queryByTitle($queryString);
|
||||
} else {
|
||||
$qb = $this->entityManager->createQueryBuilder()->from(SocialIssue::class, 'si');
|
||||
}
|
||||
|
||||
$now = new \DateTime('now');
|
||||
if (in_array('Active', $isActive, true) && !in_array('Inactive', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('si.desactivationDate'),
|
||||
$qb->expr()->gt('si.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
} elseif (in_array('Inactive', $isActive, true) && !in_array('Active', $isActive, true)) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('si.desactivationDate'),
|
||||
$qb->expr()->lte('si.desactivationDate', ':now')
|
||||
)
|
||||
)->setParameter('now', $now);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, SocialIssue>
|
||||
*/
|
||||
public function findFilteredSocialIssues(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
?int $start = 0,
|
||||
?int $limit = 50,
|
||||
?array $orderBy = ['ordering' => 'ASC'],
|
||||
): array {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
return $this->getResult($qb, $start, $limit, $orderBy);
|
||||
}
|
||||
|
||||
public function countFilteredSocialIssues(
|
||||
?string $queryString = null,
|
||||
array $isActive = ['active'],
|
||||
): int {
|
||||
$qb = $this->buildFilterBaseQuery($queryString, $isActive);
|
||||
|
||||
try {
|
||||
return $qb
|
||||
->select('COUNT(si)')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
} catch (NoResultException|NonUniqueResultException $e) {
|
||||
throw new \LogicException('a count query should return one result', previous: $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function buildQueryWithDesactivatedDateCriteria(): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('si');
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
{% block admin_content %}
|
||||
{% embed '@ChillMain/CRUD/_index.html.twig' %}
|
||||
|
||||
{% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %}
|
||||
|
||||
{% block table_entities_thead_tr %}
|
||||
<th>{{ 'Id'|trans }}</th>
|
||||
<th>{{ 'Title'|trans }}</th>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
{% block admin_content %}
|
||||
{% embed '@ChillMain/CRUD/_index.html.twig' %}
|
||||
|
||||
{% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %}
|
||||
|
||||
{% block table_entities_thead_tr %}
|
||||
<th>{{ 'Id'|trans }}</th>
|
||||
<th>{{ 'Title'|trans }}</th>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
{% block admin_content %}
|
||||
{% embed '@ChillMain/CRUD/_index.html.twig' %}
|
||||
|
||||
{% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %}
|
||||
|
||||
{% block table_entities_thead_tr %}
|
||||
<th>{{ 'Id'|trans }}</th>
|
||||
<th>{{ 'Title'|trans }}</th>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
{% block admin_content %}
|
||||
{% embed '@ChillMain/CRUD/_index.html.twig' %}
|
||||
|
||||
{% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %}
|
||||
|
||||
{% block table_entities_thead_tr %}
|
||||
<th>{{ 'Id' }}</th>
|
||||
<th>{{ 'Title'|trans }}</th>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
{% block admin_content %}
|
||||
{% embed '@ChillMain/CRUD/_index.html.twig' %}
|
||||
|
||||
{% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %}
|
||||
|
||||
{% block table_entities_thead_tr %}
|
||||
<th>{{ 'Id'|trans }}</th>
|
||||
<th>{{ 'Title'|trans }}</th>
|
||||
|
||||
Reference in New Issue
Block a user