fix: validate mandatory services selection

This commit is contained in:
Björn Fromme committed 2026-03-16 12:03:00 +01:00
1 parent 474d171779
commit b752256bda
4 files changed
+291

No files matched your search

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace App\Validator\Constraints;
use App\BusProNet\Constants;
use App\BusProNet\Model\Service;
use App\Form\Model\ParticipantEditDto;
use App\Form\Service\ServiceAgeEvaluator;
use App\Service\ParticipantEligibilityService;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* Enforces selection of age-eligible mandatory additional services.
*/
class MandatoryAdditionalServicesSelectedValidator extends ConstraintValidator
{
public function __construct(
private readonly ParticipantEligibilityService $participantEligibilityService,
private readonly ServiceAgeEvaluator $serviceAgeEvaluator,
) {
}
public function validate(mixed $value, Constraint $constraint): void
{
if (false === $constraint instanceof MandatoryAdditionalServicesSelected) {
throw new UnexpectedTypeException($constraint, MandatoryAdditionalServicesSelected::class);
}
if (false === $value instanceof ParticipantEditDto) {
throw new UnexpectedTypeException($value, ParticipantEditDto::class);
}
$participant = $value->participant;
if (true === $participant->isCanceled()) {
return;
}
$participantIndex = $participant->index ?? 0;
if (false === $this->participantEligibilityService->isParticipantEligible($value->bookingContext, $participantIndex)) {
return;
}
$mandatoryAdditionalServices = array_filter(
$value->bookingContext->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_ADDITIONAL),
function (Service $service) use ($value, $participantIndex): bool {
if (true !== $service->mandatory) {
return false;
}
if (true === $this->serviceAgeEvaluator->canEvaluate($service)) {
return $this->serviceAgeEvaluator->isServiceAvailableForParticipant(
$service,
$value->bookingContext,
$participantIndex
);
}
return true;
}
);
if (true === empty($mandatoryAdditionalServices)) {
return;
}
$selectedAdditionalServiceIds = array_map(
static fn (Service $service): int => $service->id,
$participant->additionalServices
);
foreach ($mandatoryAdditionalServices as $mandatoryService) {
if (false === in_array($mandatoryService->id, $selectedAdditionalServiceIds, true)) {
$this->context->buildViolation($constraint->message)
->atPath('participant.additionalServices')
->addViolation();
return;
}
}
}
}