From 5c7e702eabc700afda226e0e33aa7a11d461ca03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Tue, 29 Sep 2026 11:33:50 +0200 Subject: [PATCH] fix: accept the ISO-2 country codes when authoring a destination --- src/Form/DestinationType.php | 9 +--- src/Model/DestinationDto.php | 26 ++++++++- tests/Model/DestinationDtoTest.php | 86 ++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 tests/Model/DestinationDtoTest.php diff --git a/src/Form/DestinationType.php b/src/Form/DestinationType.php index ad8f37a..f0d0254 100644 --- a/src/Form/DestinationType.php +++ b/src/Form/DestinationType.php @@ -40,14 +40,7 @@ class DestinationType extends AbstractType ]) ->add('country', ChoiceType::class, [ 'label' => 'Land', - 'choices' => [ - 'Österreich' => 'at', - 'Schweiz' => 'ch', - 'Frankreich' => 'fr', - 'Italien' => 'it', - 'Deutschland' => 'de', - 'Niederlande' => 'nl', - ], + 'choices' => DestinationDto::COUNTRIES, ]) ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $form = $event->getForm(); diff --git a/src/Model/DestinationDto.php b/src/Model/DestinationDto.php index e7b1f33..a90d75e 100644 --- a/src/Model/DestinationDto.php +++ b/src/Model/DestinationDto.php @@ -7,10 +7,26 @@ use Symfony\Component\Validator\Constraints as Assert; class DestinationDto { + /** + * The countries a destination can be authored in, as German label => ISO-3166-1 alpha-2. + * + * Both the form's choice list and the constraint below read this one map. They used to + * spell the codes out twice and drifted apart the moment the stored values moved to + * ISO-2: the form offered 'at' while the constraint still only accepted 'a'. + */ + public const COUNTRIES = [ + 'Österreich' => 'at', + 'Schweiz' => 'ch', + 'Frankreich' => 'fr', + 'Italien' => 'it', + 'Deutschland' => 'de', + 'Niederlande' => 'nl', + ]; + #[Assert\NotBlank(message: 'Bitte angeben')] private ?string $product = null; - #[Assert\Choice(choices: ['a', 'ch', 'd', 'f', 'i', 'nl'], message: 'Ungültige Auswahl')] + #[Assert\Choice(callback: 'countryCodes', message: 'Ungültige Auswahl')] private ?string $country = null; #[Assert\NotNull(message: 'Bitte das Beginndatum angeben')] @@ -46,6 +62,14 @@ class DestinationDto return $instance; } + /** + * @return list + */ + public static function countryCodes(): array + { + return array_values(self::COUNTRIES); + } + public function getProduct(): ?string { return $this->product; diff --git a/tests/Model/DestinationDtoTest.php b/tests/Model/DestinationDtoTest.php new file mode 100644 index 0000000..0d8457b --- /dev/null +++ b/tests/Model/DestinationDtoTest.php @@ -0,0 +1,86 @@ +assertSame(['at', 'ch', 'fr', 'it', 'de', 'nl'], DestinationDto::countryCodes()); + } + + /** + * @dataProvider isoCountryCodes + */ + public function testAnIsoCountryCodeIsAccepted(string $code): void + { + $this->assertCount(0, $this->validateCountry($code)); + } + + /** + * The four that the form offered and the constraint refused. + * + * @dataProvider busProNetCountryAbbreviations + */ + public function testABusProNetAbbreviationIsNoLongerAccepted(string $abbreviation): void + { + $this->assertCount(1, $this->validateCountry($abbreviation)); + } + + /** + * MyE&P drops a country it cannot map to two letters, so a destination without one is + * a normal row rather than an invalid one. + */ + public function testNoCountryIsAccepted(): void + { + $this->assertCount(0, $this->validateCountry(null)); + } + + /** + * @return iterable + */ + public static function isoCountryCodes(): iterable + { + foreach (DestinationDto::countryCodes() as $code) { + yield $code => [$code]; + } + } + + /** + * @return iterable + */ + public static function busProNetCountryAbbreviations(): iterable + { + yield 'a' => ['a']; + yield 'd' => ['d']; + yield 'f' => ['f']; + yield 'i' => ['i']; + } + + private function validateCountry(?string $country): ConstraintViolationListInterface + { + return Validation::createValidatorBuilder() + ->enableAttributeMapping() + ->getValidator() + ->validateProperty((new DestinationDto())->setCountry($country), 'country') + ; + } +}