mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Refactor SavedExport listing to support filtering.
Introduced filtering capabilities for SavedExport listings by title and description. Moved index functionality to a new `SavedExportIndexController` and updated the repository with the necessary filter logic. Adjusted the Twig template to render the new filter interface.
This commit is contained in:
parent
9f32b5ac48
commit
be448c650e
@ -14,13 +14,8 @@ namespace Chill\MainBundle\Controller;
|
|||||||
use Chill\MainBundle\Entity\ExportGeneration;
|
use Chill\MainBundle\Entity\ExportGeneration;
|
||||||
use Chill\MainBundle\Entity\SavedExport;
|
use Chill\MainBundle\Entity\SavedExport;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Export\ExportInterface;
|
|
||||||
use Chill\MainBundle\Export\ExportManager;
|
use Chill\MainBundle\Export\ExportManager;
|
||||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
|
||||||
use Chill\MainBundle\Form\SavedExportType;
|
use Chill\MainBundle\Form\SavedExportType;
|
||||||
use Chill\MainBundle\Repository\ExportGenerationRepository;
|
|
||||||
use Chill\MainBundle\Repository\SavedExportRepositoryInterface;
|
|
||||||
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
|
|
||||||
use Chill\MainBundle\Security\Authorization\ExportGenerationVoter;
|
use Chill\MainBundle\Security\Authorization\ExportGenerationVoter;
|
||||||
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
|
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
@ -46,11 +41,9 @@ final readonly class SavedExportController
|
|||||||
private EntityManagerInterface $entityManager,
|
private EntityManagerInterface $entityManager,
|
||||||
private ExportManager $exportManager,
|
private ExportManager $exportManager,
|
||||||
private FormFactoryInterface $formFactory,
|
private FormFactoryInterface $formFactory,
|
||||||
private SavedExportRepositoryInterface $savedExportRepository,
|
|
||||||
private Security $security,
|
private Security $security,
|
||||||
private TranslatorInterface $translator,
|
private TranslatorInterface $translator,
|
||||||
private UrlGeneratorInterface $urlGenerator,
|
private UrlGeneratorInterface $urlGenerator,
|
||||||
private ExportGenerationRepository $exportGenerationRepository,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
#[Route(path: '/{_locale}/exports/saved/{id}/delete', name: 'chill_main_export_saved_delete')]
|
#[Route(path: '/{_locale}/exports/saved/{id}/delete', name: 'chill_main_export_saved_delete')]
|
||||||
@ -234,52 +227,4 @@ final readonly class SavedExportController
|
|||||||
$this->urlGenerator->generate('chill_main_export_saved_edit', ['id' => $savedExport->getId()]),
|
$this->urlGenerator->generate('chill_main_export_saved_edit', ['id' => $savedExport->getId()]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/{_locale}/exports/saved/my', name: 'chill_main_export_saved_list_my')]
|
|
||||||
public function list(): Response
|
|
||||||
{
|
|
||||||
$user = $this->security->getUser();
|
|
||||||
|
|
||||||
if (!$this->security->isGranted(ChillExportVoter::GENERATE_SAVED_EXPORT) || !$user instanceof User) {
|
|
||||||
throw new AccessDeniedHttpException(sprintf('Missing role: %s', ChillExportVoter::GENERATE_SAVED_EXPORT));
|
|
||||||
}
|
|
||||||
|
|
||||||
$exports = array_filter(
|
|
||||||
$this->savedExportRepository->findSharedWithUser($user, ['exportAlias' => 'ASC', 'title' => 'ASC']),
|
|
||||||
fn (SavedExport $savedExport): bool => $this->security->isGranted(SavedExportVoter::GENERATE, $savedExport),
|
|
||||||
);
|
|
||||||
|
|
||||||
// group by center
|
|
||||||
/** @var array<string, array{saved: SavedExport, export: ExportInterface}> $exportsGrouped */
|
|
||||||
$exportsGrouped = [];
|
|
||||||
|
|
||||||
foreach ($exports as $savedExport) {
|
|
||||||
$export = $this->exportManager->getExport($savedExport->getExportAlias());
|
|
||||||
|
|
||||||
$exportsGrouped[
|
|
||||||
$export instanceof GroupedExportInterface
|
|
||||||
? $this->translator->trans($export->getGroup()) : '_'
|
|
||||||
][] = ['saved' => $savedExport, 'export' => $export];
|
|
||||||
}
|
|
||||||
|
|
||||||
ksort($exportsGrouped);
|
|
||||||
|
|
||||||
// get last executions
|
|
||||||
$lastExecutions = [];
|
|
||||||
foreach ($exports as $savedExport) {
|
|
||||||
$lastExecutions[$savedExport->getId()->toString()] = $this->exportGenerationRepository
|
|
||||||
->findExportGenerationBySavedExportAndUser($savedExport, $user, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(
|
|
||||||
$this->templating->render(
|
|
||||||
'@ChillMain/SavedExport/index.html.twig',
|
|
||||||
[
|
|
||||||
'grouped_exports' => $exportsGrouped,
|
|
||||||
'total' => \count($exports),
|
|
||||||
'last_executions' => $lastExecutions,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\SavedExport;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Export\ExportInterface;
|
||||||
|
use Chill\MainBundle\Export\ExportManager;
|
||||||
|
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||||
|
use Chill\MainBundle\Repository\ExportGenerationRepository;
|
||||||
|
use Chill\MainBundle\Repository\SavedExportRepositoryInterface;
|
||||||
|
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
|
||||||
|
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
|
||||||
|
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
|
||||||
|
use Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
final readonly class SavedExportIndexController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private \Twig\Environment $templating,
|
||||||
|
private ExportManager $exportManager,
|
||||||
|
private SavedExportRepositoryInterface $savedExportRepository,
|
||||||
|
private Security $security,
|
||||||
|
private TranslatorInterface $translator,
|
||||||
|
private ExportGenerationRepository $exportGenerationRepository,
|
||||||
|
private FilterOrderHelperFactoryInterface $filterOrderHelperFactory,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
#[Route(path: '/{_locale}/exports/saved/my', name: 'chill_main_export_saved_list_my')]
|
||||||
|
public function list(): Response
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
if (!$this->security->isGranted(ChillExportVoter::GENERATE_SAVED_EXPORT) || !$user instanceof User) {
|
||||||
|
throw new AccessDeniedHttpException(sprintf('Missing role: %s', ChillExportVoter::GENERATE_SAVED_EXPORT));
|
||||||
|
}
|
||||||
|
|
||||||
|
$filter = $this->buildFilter();
|
||||||
|
|
||||||
|
$filterParams = [];
|
||||||
|
if ('' !== $filter->getQueryString() && null !== $filter->getQueryString()) {
|
||||||
|
$filterParams[SavedExportRepositoryInterface::FILTER_DESCRIPTION | SavedExportRepositoryInterface::FILTER_TITLE] = $filter->getQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
$exports = array_filter(
|
||||||
|
$this->savedExportRepository->findSharedWithUser($user, ['exportAlias' => 'ASC', 'title' => 'ASC'], filters: $filterParams),
|
||||||
|
fn (SavedExport $savedExport): bool => $this->security->isGranted(SavedExportVoter::GENERATE, $savedExport),
|
||||||
|
);
|
||||||
|
|
||||||
|
// group by center
|
||||||
|
/** @var array<string, array{saved: SavedExport, export: ExportInterface}> $exportsGrouped */
|
||||||
|
$exportsGrouped = [];
|
||||||
|
|
||||||
|
foreach ($exports as $savedExport) {
|
||||||
|
$export = $this->exportManager->getExport($savedExport->getExportAlias());
|
||||||
|
|
||||||
|
$exportsGrouped[$export instanceof GroupedExportInterface
|
||||||
|
? $this->translator->trans($export->getGroup()) : '_'][] = ['saved' => $savedExport, 'export' => $export];
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($exportsGrouped);
|
||||||
|
|
||||||
|
// get last executions
|
||||||
|
$lastExecutions = [];
|
||||||
|
foreach ($exports as $savedExport) {
|
||||||
|
$lastExecutions[$savedExport->getId()->toString()] = $this->exportGenerationRepository
|
||||||
|
->findExportGenerationBySavedExportAndUser($savedExport, $user, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
$this->templating->render(
|
||||||
|
'@ChillMain/SavedExport/index.html.twig',
|
||||||
|
[
|
||||||
|
'grouped_exports' => $exportsGrouped,
|
||||||
|
'total' => \count($exports),
|
||||||
|
'last_executions' => $lastExecutions,
|
||||||
|
'filter' => $filter,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildFilter(): FilterOrderHelper
|
||||||
|
{
|
||||||
|
$filter = $this->filterOrderHelperFactory->create('saved-export-index-filter');
|
||||||
|
$filter->addSearchBox();
|
||||||
|
|
||||||
|
return $filter->build();
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
use Symfony\Component\String\UnicodeString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @implements ObjectRepository<SavedExport>
|
* @implements ObjectRepository<SavedExport>
|
||||||
@ -60,7 +61,7 @@ class SavedExportRepository implements SavedExportRepositoryInterface
|
|||||||
return $this->prepareResult($qb, $orderBy, $limit, $offset);
|
return $this->prepareResult($qb, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findSharedWithUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null): array
|
public function findSharedWithUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null, array $filters = []): array
|
||||||
{
|
{
|
||||||
$qb = $this->repository->createQueryBuilder('se');
|
$qb = $this->repository->createQueryBuilder('se');
|
||||||
|
|
||||||
@ -76,6 +77,27 @@ class SavedExportRepository implements SavedExportRepositoryInterface
|
|||||||
)
|
)
|
||||||
->setParameter('user', $user);
|
->setParameter('user', $user);
|
||||||
|
|
||||||
|
foreach ($filters as $key => $filter) {
|
||||||
|
if (self::FILTER_TITLE === ($key & self::FILTER_TITLE)
|
||||||
|
|| self::FILTER_DESCRIPTION === ($key & self::FILTER_DESCRIPTION)) {
|
||||||
|
$filter = new UnicodeString($filter);
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
foreach ($filter->split(' ') as $word) {
|
||||||
|
$orx = $qb->expr()->orX();
|
||||||
|
if (self::FILTER_TITLE === ($key & self::FILTER_TITLE)) {
|
||||||
|
$orx->add($qb->expr()->like('LOWER(se.title)', 'LOWER(:qs'.$i.')'));
|
||||||
|
}
|
||||||
|
if (self::FILTER_DESCRIPTION === ($key & self::FILTER_DESCRIPTION)) {
|
||||||
|
$orx->add($qb->expr()->like('LOWER(se.description)', 'LOWER(:qs'.$i.')'));
|
||||||
|
}
|
||||||
|
$qb->andWhere($orx);
|
||||||
|
$qb->setParameter('qs'.$i, '%'.$word->trim().'%');
|
||||||
|
++$i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->prepareResult($qb, $orderBy, $limit, $offset);
|
return $this->prepareResult($qb, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@ use Doctrine\Persistence\ObjectRepository;
|
|||||||
*/
|
*/
|
||||||
interface SavedExportRepositoryInterface extends ObjectRepository
|
interface SavedExportRepositoryInterface extends ObjectRepository
|
||||||
{
|
{
|
||||||
|
public const FILTER_TITLE = 0x01;
|
||||||
|
public const FILTER_DESCRIPTION = 0x10;
|
||||||
|
|
||||||
public function find($id): ?SavedExport;
|
public function find($id): ?SavedExport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +37,14 @@ interface SavedExportRepositoryInterface extends ObjectRepository
|
|||||||
*/
|
*/
|
||||||
public function findByUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null): array;
|
public function findByUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null): array;
|
||||||
|
|
||||||
public function findSharedWithUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null): array;
|
/**
|
||||||
|
* Get the saved export created by and the user and the ones shared with the user.
|
||||||
|
*
|
||||||
|
* @param array<int, mixed> $filters filters where keys are one of the constant starting with FILTER_
|
||||||
|
*
|
||||||
|
* @return list<SavedExport>
|
||||||
|
*/
|
||||||
|
public function findSharedWithUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null, array $filters = []): array;
|
||||||
|
|
||||||
public function findOneBy(array $criteria): ?SavedExport;
|
public function findOneBy(array $criteria): ?SavedExport;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
{% block title %}{{ 'saved_export.Saved exports'|trans }}{% endblock %}
|
{% block title %}{{ 'saved_export.Saved exports'|trans }}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% macro render_export_card(saved, export, export_alias, generations) %}
|
{% macro render_export_card(saved, export, export_alias, generations) %}
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
@ -88,6 +89,7 @@
|
|||||||
{{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'my'}) }}
|
{{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'my'}) }}
|
||||||
|
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
|
{{ filter|chill_render_filter_order_helper }}
|
||||||
|
|
||||||
{% if total == 0 %}
|
{% if total == 0 %}
|
||||||
<p class="chill-no-data-statement" >{{ 'saved_export.Any saved export'|trans }}</p>
|
<p class="chill-no-data-statement" >{{ 'saved_export.Any saved export'|trans }}</p>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user