feat: validate application date range against existing dispositions
This commit is contained in:
@@ -4,11 +4,13 @@ namespace App\Entity;
|
|||||||
|
|
||||||
use App\Entity\Traits\TimestampableEntity;
|
use App\Entity\Traits\TimestampableEntity;
|
||||||
use App\Repository\ApplicationRepository;
|
use App\Repository\ApplicationRepository;
|
||||||
|
use App\Validator\Constraints as AppAssert;
|
||||||
use Doctrine\DBAL\Types\Types;
|
use Doctrine\DBAL\Types\Types;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Uid\Uuid;
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
|
||||||
#[ORM\Entity(repositoryClass: ApplicationRepository::class)]
|
#[ORM\Entity(repositoryClass: ApplicationRepository::class)]
|
||||||
|
#[AppAssert\Application]
|
||||||
class Application implements TimestampableEntityInterface
|
class Application implements TimestampableEntityInterface
|
||||||
{
|
{
|
||||||
use TimestampableEntity;
|
use TimestampableEntity;
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
|
||||||
|
#[\Attribute]
|
||||||
|
class Application extends Constraint
|
||||||
|
{
|
||||||
|
public string $message = 'Diese Bewerbung überlappt sich mit einem deiner bestätigten Einsätze';
|
||||||
|
|
||||||
|
public function getTargets(): array|string
|
||||||
|
{
|
||||||
|
return static::CLASS_CONSTRAINT;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints;
|
||||||
|
|
||||||
|
use App\Repository\DispositionRepository;
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
|
||||||
|
class ApplicationValidator extends ConstraintValidator
|
||||||
|
{
|
||||||
|
public function __construct(private readonly DispositionRepository $dispositionRepository)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validate(mixed $value, Constraint $constraint): void
|
||||||
|
{
|
||||||
|
/** @var \App\Entity\Application $application */
|
||||||
|
$application = $value;
|
||||||
|
|
||||||
|
$teamer = $application->getTeamer();
|
||||||
|
|
||||||
|
$assignment = $application->getAssignment();
|
||||||
|
$destination = $assignment->getDestination();
|
||||||
|
|
||||||
|
$applicationDateFrom = $destination->getDateFrom();
|
||||||
|
$applicationDateTo = $destination->getDateTo();
|
||||||
|
|
||||||
|
$qb = $this
|
||||||
|
->dispositionRepository
|
||||||
|
->createQueryBuilder('disposition')
|
||||||
|
;
|
||||||
|
|
||||||
|
$conflictingCount = $qb
|
||||||
|
->select($qb->expr()->count('disposition'))
|
||||||
|
->innerJoin('disposition.assignment', 'assignment')
|
||||||
|
->innerJoin('assignment.destination', 'destination')
|
||||||
|
->where($qb->expr()->andX(
|
||||||
|
$qb->expr()->eq('disposition.teamer', ':teamer'),
|
||||||
|
$qb->expr()->orX(
|
||||||
|
$qb->expr()->andX(
|
||||||
|
$qb->expr()->gt('destination.dateTo', ':application_date_from'),
|
||||||
|
$qb->expr()->lt('destination.dateTo', ':application_date_to'),
|
||||||
|
),
|
||||||
|
$qb->expr()->andX(
|
||||||
|
$qb->expr()->lt('destination.dateFrom', ':application_date_to'),
|
||||||
|
$qb->expr()->gt('destination.dateFrom', ':application_date_from'),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
->setParameter('teamer', $teamer)
|
||||||
|
->setParameter('application_date_from', $applicationDateFrom)
|
||||||
|
->setParameter('application_date_to', $applicationDateTo)
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (0 < $conflictingCount) {
|
||||||
|
$this
|
||||||
|
->context
|
||||||
|
->buildViolation($constraint->message)
|
||||||
|
->addViolation()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
{%- block form_errors -%}
|
{%- block form_errors -%}
|
||||||
{%- if errors|length > 0 -%}
|
{%- if errors|length > 0 -%}
|
||||||
<ul>
|
<ul class="pb-2">
|
||||||
{%- for error in errors -%}
|
{%- for error in errors -%}
|
||||||
<li class="text-red-500">{{ error.message }}</li>
|
<li class="text-red-500">{{ error.message }}</li>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
</h2>
|
</h2>
|
||||||
{% include '_partials/_assignment_requirements_info.html.twig' %}
|
{% include '_partials/_assignment_requirements_info.html.twig' %}
|
||||||
{{ form_start(form) }}
|
{{ form_start(form) }}
|
||||||
|
{{ form_errors(form) }}
|
||||||
<div class="flex flex-col space-y-4 pb-8">
|
<div class="flex flex-col space-y-4 pb-8">
|
||||||
{% if form.pickup is defined %}
|
{% if form.pickup is defined %}
|
||||||
{{ form_row(form.pickup) }}
|
{{ form_row(form.pickup) }}
|
||||||
|
|||||||
Reference in New Issue
Block a user