feat: additional filter options for documents
This commit is contained in:
@@ -32,6 +32,7 @@ services:
|
|||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
bind:
|
bind:
|
||||||
$logger: '@monolog.logger.myep'
|
$logger: '@monolog.logger.myep'
|
||||||
|
$destinations: '%destinations%'
|
||||||
|
|
||||||
App\:
|
App\:
|
||||||
resource: '../src/'
|
resource: '../src/'
|
||||||
@@ -166,7 +167,3 @@ services:
|
|||||||
$defaults:
|
$defaults:
|
||||||
from: '%default_email_from%'
|
from: '%default_email_from%'
|
||||||
to: '%default_email_to%'
|
to: '%default_email_to%'
|
||||||
|
|
||||||
App\Form\AssignmentFilterType:
|
|
||||||
arguments:
|
|
||||||
$destinations: '%destinations%'
|
|
||||||
@@ -4,6 +4,7 @@ namespace App\Controller\Common;
|
|||||||
|
|
||||||
use App\Form\DocumentFilterType;
|
use App\Form\DocumentFilterType;
|
||||||
use App\Htmx\HxRedirectResponse;
|
use App\Htmx\HxRedirectResponse;
|
||||||
|
use App\Repository\AssignmentRepository;
|
||||||
use App\Service\Common\DocumentFilterHandler;
|
use App\Service\Common\DocumentFilterHandler;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@@ -13,8 +14,10 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
|||||||
|
|
||||||
class DocumentFilterController extends AbstractController
|
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')]
|
#[Route('/common/document/filter', name: 'app_common_document_filter')]
|
||||||
@@ -22,8 +25,12 @@ class DocumentFilterController extends AbstractController
|
|||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$formData = $this->filterHandler->getFilterSettings();
|
$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);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|||||||
@@ -19,8 +19,15 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
|
|
||||||
class AssignmentFilterType extends AbstractType
|
class AssignmentFilterType extends AbstractType
|
||||||
{
|
{
|
||||||
|
private array $hotelChoices = [];
|
||||||
|
|
||||||
public function __construct(private readonly Security $security, private readonly array $destinations)
|
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
|
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
|
$builder
|
||||||
->add('hotels', MultiselectType::class, [
|
->add('hotels', MultiselectType::class, [
|
||||||
'label' => 'Haus/Destination',
|
'label' => 'Haus/Destination',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'empty_label' => 'nicht filtern',
|
'empty_label' => 'nicht filtern',
|
||||||
'choices' => $hotelChoices,
|
'choices' => $this->hotelChoices,
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Form;
|
namespace App\Form;
|
||||||
|
|
||||||
|
use App\Entity\JobProfile;
|
||||||
use App\Entity\Teamer;
|
use App\Entity\Teamer;
|
||||||
use App\Entity\Upload;
|
use App\Entity\Upload;
|
||||||
use App\Model\DocumentFilterDto;
|
use App\Model\DocumentFilterDto;
|
||||||
@@ -13,6 +14,17 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
|
|
||||||
class DocumentFilterType extends AbstractType
|
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
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
@@ -32,6 +44,20 @@ class DocumentFilterType extends AbstractType
|
|||||||
'Honorarvertrag' => Upload::TYPE_CONTRACT,
|
'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, [
|
->add('dateFrom', DatepickerType::class, [
|
||||||
'label' => 'Einsatzzeitraum von',
|
'label' => 'Einsatzzeitraum von',
|
||||||
'attr' => [
|
'attr' => [
|
||||||
@@ -44,6 +70,18 @@ class DocumentFilterType extends AbstractType
|
|||||||
'placeholder' => 'nicht filtern',
|
'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, [
|
->add('apply', SubmitType::class, [
|
||||||
'label' => 'filtern',
|
'label' => 'filtern',
|
||||||
])
|
])
|
||||||
@@ -58,6 +96,7 @@ class DocumentFilterType extends AbstractType
|
|||||||
$resolver
|
$resolver
|
||||||
->setDefaults([
|
->setDefaults([
|
||||||
'data_class' => DocumentFilterDto::class,
|
'data_class' => DocumentFilterDto::class,
|
||||||
|
'job_profiles' => [],
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ class DocumentFilterDto extends AbstractFilterDto
|
|||||||
{
|
{
|
||||||
protected ?Teamer $teamer = null;
|
protected ?Teamer $teamer = null;
|
||||||
protected ?string $type = null;
|
protected ?string $type = null;
|
||||||
|
protected array $jobProfiles = [];
|
||||||
|
protected array $hotels = [];
|
||||||
protected ?\DateTimeImmutable $dateFrom = null;
|
protected ?\DateTimeImmutable $dateFrom = null;
|
||||||
protected ?\DateTimeImmutable $dateTo = null;
|
protected ?\DateTimeImmutable $dateTo = null;
|
||||||
|
protected ?string $status = null;
|
||||||
|
|
||||||
public function getTeamer(): ?Teamer
|
public function getTeamer(): ?Teamer
|
||||||
{
|
{
|
||||||
@@ -35,6 +38,30 @@ class DocumentFilterDto extends AbstractFilterDto
|
|||||||
return $this;
|
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
|
public function getDateFrom(): ?\DateTimeImmutable
|
||||||
{
|
{
|
||||||
return $this->dateFrom;
|
return $this->dateFrom;
|
||||||
@@ -58,4 +85,16 @@ class DocumentFilterDto extends AbstractFilterDto
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getStatus(): ?string
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStatus(?string $status): static
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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();
|
return $qb->getQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Service\Common;
|
namespace App\Service\Common;
|
||||||
|
|
||||||
|
use App\Entity\JobProfile;
|
||||||
use App\Entity\Teamer;
|
use App\Entity\Teamer;
|
||||||
use App\Model\AbstractFilterDto;
|
use App\Model\AbstractFilterDto;
|
||||||
use App\Model\DocumentFilterDto;
|
use App\Model\DocumentFilterDto;
|
||||||
@@ -33,6 +34,23 @@ class DocumentFilterHandler extends AbstractFilterHandler
|
|||||||
$filterDto->setTeamer($teamer);
|
$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;
|
return $filterDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +62,11 @@ class DocumentFilterHandler extends AbstractFilterHandler
|
|||||||
'type' => $filterDto->getType(),
|
'type' => $filterDto->getType(),
|
||||||
'date_from' => $filterDto->getDateFrom(),
|
'date_from' => $filterDto->getDateFrom(),
|
||||||
'date_to' => $filterDto->getDateTo(),
|
'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' } }) }}
|
{{ 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">
|
<div class="flex flex-col space-y-2 pb-4">
|
||||||
{{ form_row(filterForm.type) }}
|
{{ form_row(filterForm.type) }}
|
||||||
|
{{ form_row(filterForm.status) }}
|
||||||
|
{{ form_row(filterForm.jobProfiles) }}
|
||||||
|
{{ form_row(filterForm.hotels) }}
|
||||||
{{ form_row(filterForm.teamer) }}
|
{{ form_row(filterForm.teamer) }}
|
||||||
{{ form_row(filterForm.dateFrom) }}
|
{{ form_row(filterForm.dateFrom) }}
|
||||||
{{ form_row(filterForm.dateTo) }}
|
{{ form_row(filterForm.dateTo) }}
|
||||||
|
|||||||
Reference in New Issue
Block a user