feat: additional filter options for documents

This commit is contained in:
Björn Fromme
2025-01-13 11:58:32 +01:00
parent 520e6b79f0
commit c5df1c2a67
8 changed files with 146 additions and 15 deletions
+1 -4
View File
@@ -32,6 +32,7 @@ services:
autoconfigure: true
bind:
$logger: '@monolog.logger.myep'
$destinations: '%destinations%'
App\:
resource: '../src/'
@@ -166,7 +167,3 @@ services:
$defaults:
from: '%default_email_from%'
to: '%default_email_to%'
App\Form\AssignmentFilterType:
arguments:
$destinations: '%destinations%'
@@ -4,6 +4,7 @@ namespace App\Controller\Common;
use App\Form\DocumentFilterType;
use App\Htmx\HxRedirectResponse;
use App\Repository\AssignmentRepository;
use App\Service\Common\DocumentFilterHandler;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
@@ -13,8 +14,10 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
class DocumentFilterController extends AbstractController
{
public function __construct(private readonly DocumentFilterHandler $filterHandler)
{
public function __construct(
private readonly DocumentFilterHandler $filterHandler,
private readonly AssignmentRepository $assignmentRepository,
) {
}
#[Route('/common/document/filter', name: 'app_common_document_filter')]
@@ -22,8 +25,12 @@ class DocumentFilterController extends AbstractController
public function index(Request $request): Response
{
$formData = $this->filterHandler->getFilterSettings();
$filterOptions = $this->assignmentRepository->getFilterOptions();
$formOptions = [
'job_profiles' => $filterOptions['jobProfiles'],
];
$form = $this->createForm(DocumentFilterType::class, $formData);
$form = $this->createForm(DocumentFilterType::class, $formData, $formOptions);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
+9 -7
View File
@@ -19,8 +19,15 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class AssignmentFilterType extends AbstractType
{
private array $hotelChoices = [];
public function __construct(private readonly Security $security, private readonly array $destinations)
{
$destinations = $this->destinations;
sort($destinations);
foreach ($destinations as $item) {
$this->hotelChoices[$item] = $item;
}
}
public function buildForm(FormBuilderInterface $builder, array $options): void
@@ -99,18 +106,13 @@ class AssignmentFilterType extends AbstractType
])
;
}
$hotelChoices = [];
$destinations = $this->destinations;
sort($destinations);
foreach ($destinations as $item) {
$hotelChoices[$item] = $item;
}
$builder
->add('hotels', MultiselectType::class, [
'label' => 'Haus/Destination',
'required' => false,
'empty_label' => 'nicht filtern',
'choices' => $hotelChoices,
'choices' => $this->hotelChoices,
])
;
}
+39
View File
@@ -2,6 +2,7 @@
namespace App\Form;
use App\Entity\JobProfile;
use App\Entity\Teamer;
use App\Entity\Upload;
use App\Model\DocumentFilterDto;
@@ -13,6 +14,17 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class DocumentFilterType extends AbstractType
{
private array $hotelChoices = [];
public function __construct(private readonly array $destinations)
{
$destinations = $this->destinations;
sort($destinations);
foreach ($destinations as $item) {
$this->hotelChoices[$item] = $item;
}
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
@@ -32,6 +44,20 @@ class DocumentFilterType extends AbstractType
'Honorarvertrag' => Upload::TYPE_CONTRACT,
],
])
->add('jobProfiles', MultiselectEntityType::class, [
'label' => 'Job-Profil',
'class' => JobProfile::class,
'required' => false,
'empty_label' => 'nicht filtern',
'choice_label' => 'name',
'choices' => $options['job_profiles'],
])
->add('hotels', MultiselectType::class, [
'label' => 'Haus/Destination',
'required' => false,
'empty_label' => 'nicht filtern',
'choices' => $this->hotelChoices,
])
->add('dateFrom', DatepickerType::class, [
'label' => 'Einsatzzeitraum von',
'attr' => [
@@ -44,6 +70,18 @@ class DocumentFilterType extends AbstractType
'placeholder' => 'nicht filtern',
],
])
->add('status', ChoiceType::class, [
'label' => 'Status',
'required' => false,
'placeholder' => 'nicht filtern',
'choices' => [
'neu' => Upload::STATUS_NEW,
'in Bearbeitung' => Upload::STATUS_PENDING,
'bestätigt' => Upload::STATUS_CHECKED,
'abgelehnt' => Upload::STATUS_REJECTED,
'bezahlt' => Upload::STATUS_PAID,
],
])
->add('apply', SubmitType::class, [
'label' => 'filtern',
])
@@ -58,6 +96,7 @@ class DocumentFilterType extends AbstractType
$resolver
->setDefaults([
'data_class' => DocumentFilterDto::class,
'job_profiles' => [],
])
;
}
+39
View File
@@ -8,8 +8,11 @@ class DocumentFilterDto extends AbstractFilterDto
{
protected ?Teamer $teamer = null;
protected ?string $type = null;
protected array $jobProfiles = [];
protected array $hotels = [];
protected ?\DateTimeImmutable $dateFrom = null;
protected ?\DateTimeImmutable $dateTo = null;
protected ?string $status = null;
public function getTeamer(): ?Teamer
{
@@ -35,6 +38,30 @@ class DocumentFilterDto extends AbstractFilterDto
return $this;
}
public function getJobProfiles(): array
{
return $this->jobProfiles;
}
public function setJobProfiles(array $jobProfiles): static
{
$this->jobProfiles = $jobProfiles;
return $this;
}
public function getHotels(): ?array
{
return $this->hotels;
}
public function setHotels(array $hotels): static
{
$this->hotels = $hotels;
return $this;
}
public function getDateFrom(): ?\DateTimeImmutable
{
return $this->dateFrom;
@@ -58,4 +85,16 @@ class DocumentFilterDto extends AbstractFilterDto
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
}
+21
View File
@@ -123,6 +123,27 @@ class UploadRepository extends ServiceEntityRepository
;
}
if (null !== $status = $filterDto->getStatus()) {
$qb
->andWhere($qb->expr()->eq('upload.status', ':status'))
->setParameter('status', $status)
;
}
if ($jobProfiles = $filterDto->getJobProfiles()) {
$qb
->andWhere($qb->expr()->in('assignment.jobProfile', ':jobProfiles'))
->setParameter('jobProfiles', $jobProfiles)
;
}
foreach ($filterDto->getHotels() as $hotel) {
$qb
->andWhere($qb->expr()->like('destination.hotel', ':hotel'))
->setParameter('hotel', '%'.$hotel.'%')
;
}
return $qb->getQuery();
}
@@ -2,6 +2,7 @@
namespace App\Service\Common;
use App\Entity\JobProfile;
use App\Entity\Teamer;
use App\Model\AbstractFilterDto;
use App\Model\DocumentFilterDto;
@@ -33,6 +34,23 @@ class DocumentFilterHandler extends AbstractFilterHandler
$filterDto->setTeamer($teamer);
}
if (isset($data['job_profiles']) && 0 < count($data['job_profiles'])) {
$jobProfiles = $this
->entityManager
->getRepository(JobProfile::class)
->findBy(['id' => $data['job_profiles']])
;
$filterDto->setJobProfiles($jobProfiles);
}
if (isset($data['hotels']) && 0 < count($data['hotels'])) {
$filterDto->setHotels($data['hotels']);
}
if (isset($data['status'])) {
$filterDto->setStatus($data['status']);
}
return $filterDto;
}
@@ -44,6 +62,11 @@ class DocumentFilterHandler extends AbstractFilterHandler
'type' => $filterDto->getType(),
'date_from' => $filterDto->getDateFrom(),
'date_to' => $filterDto->getDateTo(),
'job_profiles' => array_map(function (JobProfile $jobProfile) {
return $jobProfile->getId();
}, $filterDto->getJobProfiles()),
'hotels' => $filterDto->getHotels(),
'status' => $filterDto->getStatus(),
]);
}
}
@@ -6,6 +6,9 @@
{{ form_start(filterForm, { 'attr': { 'hx-post': app.request.uri, 'hx-target': '#htmx-modal', 'hx-swap': 'outerHTML' } }) }}
<div class="flex flex-col space-y-2 pb-4">
{{ form_row(filterForm.type) }}
{{ form_row(filterForm.status) }}
{{ form_row(filterForm.jobProfiles) }}
{{ form_row(filterForm.hotels) }}
{{ form_row(filterForm.teamer) }}
{{ form_row(filterForm.dateFrom) }}
{{ form_row(filterForm.dateTo) }}