fix: accept the ISO-2 country codes when authoring a destination
This commit is contained in:
1 parent
169a17e19c
commit
5c7e702eab
3 files changed
+112
-9
No files matched your search
@@ -40,14 +40,7 @@ class DestinationType extends AbstractType
|
|||||||
])
|
])
|
||||||
->add('country', ChoiceType::class, [
|
->add('country', ChoiceType::class, [
|
||||||
'label' => 'Land',
|
'label' => 'Land',
|
||||||
'choices' => [
|
'choices' => DestinationDto::COUNTRIES,
|
||||||
'Österreich' => 'at',
|
|
||||||
'Schweiz' => 'ch',
|
|
||||||
'Frankreich' => 'fr',
|
|
||||||
'Italien' => 'it',
|
|
||||||
'Deutschland' => 'de',
|
|
||||||
'Niederlande' => 'nl',
|
|
||||||
],
|
|
||||||
])
|
])
|
||||||
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
|
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
|
||||||
$form = $event->getForm();
|
$form = $event->getForm();
|
||||||
|
|||||||
@@ -7,10 +7,26 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||||||
|
|
||||||
class DestinationDto
|
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')]
|
#[Assert\NotBlank(message: 'Bitte angeben')]
|
||||||
private ?string $product = null;
|
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;
|
private ?string $country = null;
|
||||||
|
|
||||||
#[Assert\NotNull(message: 'Bitte das Beginndatum angeben')]
|
#[Assert\NotNull(message: 'Bitte das Beginndatum angeben')]
|
||||||
@@ -46,6 +62,14 @@ class DestinationDto
|
|||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public static function countryCodes(): array
|
||||||
|
{
|
||||||
|
return array_values(self::COUNTRIES);
|
||||||
|
}
|
||||||
|
|
||||||
public function getProduct(): ?string
|
public function getProduct(): ?string
|
||||||
{
|
{
|
||||||
return $this->product;
|
return $this->product;
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Model;
|
||||||
|
|
||||||
|
use App\Model\DestinationDto;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||||
|
use Symfony\Component\Validator\Validation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stored country moved to ISO-3166-1 alpha-2, but the constraint on this DTO kept the
|
||||||
|
* old BusProNet abbreviations while the form was already offering the new codes. Every
|
||||||
|
* country except Schweiz and Niederlande - the two whose code happens to be unchanged -
|
||||||
|
* was rejected as "Ungültige Auswahl" on save, so a destination could not be created or
|
||||||
|
* edited for Österreich, Deutschland, Frankreich or Italien at all.
|
||||||
|
*
|
||||||
|
* The codes are asserted literally rather than read back off the map they come from, so
|
||||||
|
* that changing the map has to be a deliberate act rather than something a test agrees
|
||||||
|
* with by construction.
|
||||||
|
*/
|
||||||
|
class DestinationDtoTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testTheAuthorableCountriesAreTheIsoCodes(): void
|
||||||
|
{
|
||||||
|
$this->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<array{string}>
|
||||||
|
*/
|
||||||
|
public static function isoCountryCodes(): iterable
|
||||||
|
{
|
||||||
|
foreach (DestinationDto::countryCodes() as $code) {
|
||||||
|
yield $code => [$code];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterable<array{string}>
|
||||||
|
*/
|
||||||
|
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')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user